diff options
author | Phil Hughes <me@iamphill.com> | 2017-10-31 09:10:03 +0000 |
---|---|---|
committer | Phil Hughes <me@iamphill.com> | 2017-10-31 09:10:03 +0000 |
commit | ac8e94d4d56d98f9e4c3b7c0f331eaa6fa5a4312 (patch) | |
tree | 81e903cd886f94380e510daf237a4d139f270fae /app | |
parent | 662f87ca372515f0b739796b31c7e242f1ebcd7f (diff) | |
parent | 6e6cea23e187b6c93886da4d043ea5a6fb7bfab5 (diff) | |
download | gitlab-ce-ac8e94d4d56d98f9e4c3b7c0f331eaa6fa5a4312.tar.gz |
Merge branch 'master' into multi-file-editor-vuex
Diffstat (limited to 'app')
36 files changed, 393 insertions, 612 deletions
diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js index c1f902a785a..5d27518ac85 100644 --- a/app/assets/javascripts/boards/components/board_sidebar.js +++ b/app/assets/javascripts/boards/components/board_sidebar.js @@ -1,5 +1,4 @@ /* eslint-disable comma-dangle, space-before-function-paren, no-new */ -/* global IssuableContext */ /* global MilestoneSelect */ /* global LabelsSelect */ /* global Sidebar */ @@ -11,6 +10,7 @@ import AssigneeTitle from '../../sidebar/components/assignees/assignee_title'; import Assignees from '../../sidebar/components/assignees/assignees'; import DueDateSelectors from '../../due_date_select'; import './sidebar/remove_issue'; +import IssuableContext from '../../issuable_context'; const Store = gl.issueBoards.BoardsStore; diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index 184665f395c..3f083655f95 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -11,8 +11,7 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager { // Issue boards is slightly different, we handle all the requests async // instead or reloading the page, we just re-fire the list ajax requests this.isHandledAsync = true; - this.cantEdit = cantEdit.filter(i => typeof i === 'string'); - this.cantEditWithValue = cantEdit.filter(i => typeof i === 'object'); + this.cantEdit = cantEdit; } updateObject(path) { @@ -43,9 +42,7 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager { this.filteredSearchInput.dispatchEvent(new Event('input')); } - canEdit(tokenName, tokenValue) { - if (this.cantEdit.includes(tokenName)) return false; - return this.cantEditWithValue.findIndex(token => token.name === tokenName && - token.value === tokenValue) === -1; + canEdit(tokenName) { + return this.cantEdit.indexOf(tokenName) === -1; } } diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index 798d7e0d147..ea82958e80d 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -14,18 +14,16 @@ gl.issueBoards.BoardsStore = { }, state: {}, detail: { - issue: {}, + issue: {} }, moving: { issue: {}, - list: {}, + list: {} }, create () { this.state.lists = []; this.filter.path = getUrlParamsArray().join('&'); - this.detail = { - issue: {}, - }; + this.detail = { issue: {} }; }, addList (listObj, defaultAvatar) { const list = new List(listObj, defaultAvatar); diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 970e83c0ecb..b516fda84b9 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -1,8 +1,8 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */ /* global ProjectSelect */ -/* global IssuableIndex */ +import IssuableIndex from './issuable_index'; /* global Milestone */ -/* global IssuableForm */ +import IssuableForm from './issuable_form'; /* global LabelsSelect */ /* global MilestoneSelect */ /* global NewBranchForm */ @@ -173,7 +173,7 @@ import Diff from './diff'; filteredSearchManager.setup(); } const pagePrefix = page === 'projects:merge_requests:index' ? 'merge_request_' : 'issue_'; - IssuableIndex.init(pagePrefix); + new IssuableIndex(pagePrefix); shortcut_handler = new ShortcutsNavigation(); new UsersSelect(); @@ -231,12 +231,16 @@ import Diff from './diff'; case 'projects:milestones:new': case 'projects:milestones:edit': case 'projects:milestones:update': + new ZenMode(); + new DueDateSelectors(); + new GLForm($('.milestone-form'), true); + break; case 'groups:milestones:new': case 'groups:milestones:edit': case 'groups:milestones:update': new ZenMode(); new DueDateSelectors(); - new GLForm($('.milestone-form'), true); + new GLForm($('.milestone-form'), false); break; case 'projects:compare:show': new Diff(); diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js b/app/assets/javascripts/filtered_search/dropdown_utils.js index cf8a9b0402b..8d711e3213c 100644 --- a/app/assets/javascripts/filtered_search/dropdown_utils.js +++ b/app/assets/javascripts/filtered_search/dropdown_utils.js @@ -147,16 +147,6 @@ class DropdownUtils { return dataValue !== null; } - static getVisualTokenValues(visualToken) { - const tokenName = visualToken && visualToken.querySelector('.name').textContent.trim(); - let tokenValue = visualToken && visualToken.querySelector('.value') && visualToken.querySelector('.value').textContent.trim(); - if (tokenName === 'label' && tokenValue) { - // remove leading symbol and wrapping quotes - tokenValue = tokenValue.replace(/^~("|')?(.*)/, '$2').replace(/("|')$/, ''); - } - return { tokenName, tokenValue }; - } - // Determines the full search query (visual tokens + input) static getSearchQuery(untilInput = false) { const container = FilteredSearchContainer.container; diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js index 69c57f923b6..7b233842d5a 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js @@ -185,8 +185,8 @@ class FilteredSearchManager { if (e.keyCode === 8 || e.keyCode === 46) { const { lastVisualToken } = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); - const { tokenName, tokenValue } = gl.DropdownUtils.getVisualTokenValues(lastVisualToken); - const canEdit = tokenName && this.canEdit && this.canEdit(tokenName, tokenValue); + const sanitizedTokenName = lastVisualToken && lastVisualToken.querySelector('.name').textContent.trim(); + const canEdit = sanitizedTokenName && this.canEdit && this.canEdit(sanitizedTokenName); if (this.filteredSearchInput.value === '' && lastVisualToken && canEdit) { this.filteredSearchInput.value = gl.FilteredSearchVisualTokens.getLastTokenPartial(); gl.FilteredSearchVisualTokens.removeLastTokenPartial(); @@ -336,8 +336,8 @@ class FilteredSearchManager { let canClearToken = t.classList.contains('js-visual-token'); if (canClearToken) { - const { tokenName, tokenValue } = gl.DropdownUtils.getVisualTokenValues(t); - canClearToken = this.canEdit && this.canEdit(tokenName, tokenValue); + const tokenKey = t.querySelector('.name').textContent.trim(); + canClearToken = this.canEdit && this.canEdit(tokenKey); } if (canClearToken) { @@ -469,7 +469,7 @@ class FilteredSearchManager { } hasFilteredSearch = true; - const canEdit = this.canEdit && this.canEdit(sanitizedKey, sanitizedValue); + const canEdit = this.canEdit && this.canEdit(sanitizedKey); gl.FilteredSearchVisualTokens.addFilterVisualToken( sanitizedKey, `${symbol}${quotationsToUse}${sanitizedValue}${quotationsToUse}`, diff --git a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js index 6139e81fe6d..d2f92929b8a 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js +++ b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js @@ -38,14 +38,21 @@ class FilteredSearchVisualTokens { } static createVisualTokenElementHTML(canEdit = true) { + let removeTokenMarkup = ''; + if (canEdit) { + removeTokenMarkup = ` + <div class="remove-token" role="button"> + <i class="fa fa-close"></i> + </div> + `; + } + return ` - <div class="${canEdit ? 'selectable' : 'hidden'}" role="button"> + <div class="selectable" role="button"> <div class="name"></div> <div class="value-container"> <div class="value"></div> - <div class="remove-token" role="button"> - <i class="fa fa-close"></i> - </div> + ${removeTokenMarkup} </div> </div> `; diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js index 5b4ca94ed30..1dc70872d92 100644 --- a/app/assets/javascripts/importer_status.js +++ b/app/assets/javascripts/importer_status.js @@ -1,83 +1,81 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, camelcase, no-var, one-var, one-var-declaration-per-line, prefer-template, quotes, object-shorthand, comma-dangle, no-unused-vars, prefer-arrow-callback, no-else-return, vars-on-top, no-new, max-len */ +class ImporterStatus { + constructor(jobsUrl, importUrl) { + this.jobsUrl = jobsUrl; + this.importUrl = importUrl; + this.initStatusPage(); + this.setAutoUpdate(); + } -(function() { - window.ImporterStatus = (function() { - function ImporterStatus(jobs_url, import_url) { - this.jobs_url = jobs_url; - this.import_url = import_url; - this.initStatusPage(); - this.setAutoUpdate(); - } + initStatusPage() { + $('.js-add-to-import') + .off('click') + .on('click', (event) => { + const $btn = $(event.currentTarget); + const $tr = $btn.closest('tr'); + const $targetField = $tr.find('.import-target'); + const $namespaceInput = $targetField.find('.js-select-namespace option:selected'); + const id = $tr.attr('id').replace('repo_', ''); + let targetNamespace; + let newName; + if ($namespaceInput.length > 0) { + targetNamespace = $namespaceInput[0].innerHTML; + newName = $targetField.find('#path').prop('value'); + $targetField.empty().append(`${targetNamespace}/${newName}`); + } + $btn.disable().addClass('is-loading'); - ImporterStatus.prototype.initStatusPage = function() { - $('.js-add-to-import').off('click').on('click', (function(_this) { - return function(e) { - var $btn, $namespace_input, $target_field, $tr, id, target_namespace, newName; - $btn = $(e.currentTarget); - $tr = $btn.closest('tr'); - $target_field = $tr.find('.import-target'); - $namespace_input = $target_field.find('.js-select-namespace option:selected'); - id = $tr.attr('id').replace('repo_', ''); - target_namespace = null; - newName = null; - if ($namespace_input.length > 0) { - target_namespace = $namespace_input[0].innerHTML; - newName = $target_field.find('#path').prop('value'); - $target_field.empty().append(target_namespace + "/" + newName); - } - $btn.disable().addClass('is-loading'); - return $.post(_this.import_url, { - repo_id: id, - target_namespace: target_namespace, - new_name: newName - }, { - dataType: 'script' - }); - }; - })(this)); - return $('.js-import-all').off('click').on('click', function(e) { - var $btn; - $btn = $(this); + return $.post(this.importUrl, { + repo_id: id, + target_namespace: targetNamespace, + new_name: newName, + }, { + dataType: 'script', + }); + }); + + $('.js-import-all') + .off('click') + .on('click', function onClickImportAll() { + const $btn = $(this); $btn.disable().addClass('is-loading'); - return $('.js-add-to-import').each(function() { + return $('.js-add-to-import').each(function triggerAddImport() { return $(this).trigger('click'); }); }); - }; + } + + setAutoUpdate() { + return setInterval(() => $.get(this.jobsUrl, data => $.each(data, (i, job) => { + const jobItem = $(`#project_${job.id}`); + const statusField = jobItem.find('.job-status'); - ImporterStatus.prototype.setAutoUpdate = function() { - return setInterval(((function(_this) { - return function() { - return $.get(_this.jobs_url, function(data) { - return $.each(data, function(i, job) { - var job_item, status_field; - job_item = $("#project_" + job.id); - status_field = job_item.find(".job-status"); - if (job.import_status === 'finished') { - job_item.removeClass("active").addClass("success"); - return status_field.html('<span><i class="fa fa-check"></i> done</span>'); - } else if (job.import_status === 'scheduled') { - return status_field.html("<i class='fa fa-spinner fa-spin'></i> scheduled"); - } else if (job.import_status === 'started') { - return status_field.html("<i class='fa fa-spinner fa-spin'></i> started"); - } else { - return status_field.html(job.import_status); - } - }); - }); - }; - })(this)), 4000); - }; + const spinner = '<i class="fa fa-spinner fa-spin"></i>'; - return ImporterStatus; - })(); + switch (job.import_status) { + case 'finished': + jobItem.removeClass('active').addClass('success'); + statusField.html('<span><i class="fa fa-check"></i> done</span>'); + break; + case 'scheduled': + statusField.html(`${spinner} scheduled`); + break; + case 'started': + statusField.html(`${spinner} started`); + break; + default: + statusField.html(job.import_status); + break; + } + })), 4000); + } +} - $(function() { - if ($('.js-importer-status').length) { - var jobsImportPath = $('.js-importer-status').data('jobs-import-path'); - var importPath = $('.js-importer-status').data('import-path'); +// eslint-disable-next-line consistent-return +export default function initImporterStatus() { + const importerStatus = document.querySelector('.js-importer-status'); - new window.ImporterStatus(jobsImportPath, importPath); - } - }); -}).call(window); + if (importerStatus) { + const data = importerStatus.dataset; + return new ImporterStatus(data.jobsImportPath, data.importPath); + } +} diff --git a/app/assets/javascripts/init_issuable_sidebar.js b/app/assets/javascripts/init_issuable_sidebar.js index 32a1a269f9a..6f476f96f72 100644 --- a/app/assets/javascripts/init_issuable_sidebar.js +++ b/app/assets/javascripts/init_issuable_sidebar.js @@ -1,7 +1,7 @@ /* eslint-disable no-new */ /* global MilestoneSelect */ /* global LabelsSelect */ -/* global IssuableContext */ +import IssuableContext from './issuable_context'; /* global Sidebar */ import DueDateSelectors from './due_date_select'; diff --git a/app/assets/javascripts/issuable_bulk_update_actions.js b/app/assets/javascripts/issuable_bulk_update_actions.js index eb15949603f..b124fafec70 100644 --- a/app/assets/javascripts/issuable_bulk_update_actions.js +++ b/app/assets/javascripts/issuable_bulk_update_actions.js @@ -1,5 +1,4 @@ /* eslint-disable comma-dangle, quotes, consistent-return, func-names, array-callback-return, space-before-function-paren, prefer-arrow-callback, max-len, no-unused-expressions, no-sequences, no-underscore-dangle, no-unused-vars, no-param-reassign */ -/* global IssuableIndex */ import _ from 'underscore'; import Flash from './flash'; diff --git a/app/assets/javascripts/issuable_bulk_update_sidebar.js b/app/assets/javascripts/issuable_bulk_update_sidebar.js index 0e8a0519928..bb509089b1d 100644 --- a/app/assets/javascripts/issuable_bulk_update_sidebar.js +++ b/app/assets/javascripts/issuable_bulk_update_sidebar.js @@ -5,6 +5,10 @@ /* global SubscriptionSelect */ import IssuableBulkUpdateActions from './issuable_bulk_update_actions'; +import './milestone_select'; +import './issue_status_select'; +import './subscription_select'; +import './labels_select'; const HIDDEN_CLASS = 'hidden'; const DISABLED_CONTENT_CLASS = 'disabled-content'; diff --git a/app/assets/javascripts/issuable_context.js b/app/assets/javascripts/issuable_context.js index 73791edaebb..5bc7f8d9cb9 100644 --- a/app/assets/javascripts/issuable_context.js +++ b/app/assets/javascripts/issuable_context.js @@ -1,33 +1,35 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, max-len */ import Cookies from 'js-cookie'; import bp from './breakpoints'; import UsersSelect from './users_select'; const PARTICIPANTS_ROW_COUNT = 7; -(function() { - this.IssuableContext = (function() { - function IssuableContext(currentUser) { - this.initParticipants(); - new UsersSelect(currentUser); - $('select.select2').select2({ - width: 'resolve', - dropdownAutoWidth: true - }); - $(".issuable-sidebar .inline-update").on("change", "select", function() { - return $(this).submit(); - }); - $(".issuable-sidebar .inline-update").on("change", ".js-assignee", function() { - return $(this).submit(); - }); - $(document).off('click', '.issuable-sidebar .dropdown-content a').on('click', '.issuable-sidebar .dropdown-content a', function(e) { - return e.preventDefault(); - }); - $(document).off('click', '.edit-link').on('click', '.edit-link', function(e) { - var $block, $selectbox; +export default class IssuableContext { + constructor(currentUser) { + this.initParticipants(); + this.userSelect = new UsersSelect(currentUser); + + $('select.select2').select2({ + width: 'resolve', + dropdownAutoWidth: true, + }); + + $('.issuable-sidebar .inline-update').on('change', 'select', function onClickSelect() { + return $(this).submit(); + }); + $('.issuable-sidebar .inline-update').on('change', '.js-assignee', function onClickAssignee() { + return $(this).submit(); + }); + $(document) + .off('click', '.issuable-sidebar .dropdown-content a') + .on('click', '.issuable-sidebar .dropdown-content a', e => e.preventDefault()); + + $(document) + .off('click', '.edit-link') + .on('click', '.edit-link', function onClickEdit(e) { e.preventDefault(); - $block = $(this).parents('.block'); - $selectbox = $block.find('.selectbox'); + const $block = $(this).parents('.block'); + const $selectbox = $block.find('.selectbox'); if ($selectbox.is(':visible')) { $selectbox.hide(); $block.find('.value').show(); @@ -35,46 +37,43 @@ const PARTICIPANTS_ROW_COUNT = 7; $selectbox.show(); $block.find('.value').hide(); } + if ($selectbox.is(':visible')) { - return setTimeout(function() { - return $block.find('.dropdown-menu-toggle').trigger('click'); - }, 0); + setTimeout(() => $block.find('.dropdown-menu-toggle').trigger('click'), 0); } }); - window.addEventListener('beforeunload', function() { - // collapsed_gutter cookie hides the sidebar - var bpBreakpoint = bp.getBreakpointSize(); - if (bpBreakpoint === 'xs' || bpBreakpoint === 'sm') { - Cookies.set('collapsed_gutter', true); - } - }); - } - IssuableContext.prototype.initParticipants = function() { - $(document).on('click', '.js-participants-more', this.toggleHiddenParticipants); - return $('.js-participants-author').each(function(i) { - if (i >= PARTICIPANTS_ROW_COUNT) { - return $(this).addClass('js-participants-hidden').hide(); - } - }); - }; + window.addEventListener('beforeunload', () => { + // collapsed_gutter cookie hides the sidebar + const bpBreakpoint = bp.getBreakpointSize(); + if (bpBreakpoint === 'xs' || bpBreakpoint === 'sm') { + Cookies.set('collapsed_gutter', true); + } + }); + } - IssuableContext.prototype.toggleHiddenParticipants = function() { - const currentText = $(this).text().trim(); - const lessText = $(this).data('less-text'); - const originalText = $(this).data('original-text'); + initParticipants() { + $(document).on('click', '.js-participants-more', this.toggleHiddenParticipants); + return $('.js-participants-author').each(function forEachAuthor(i) { + if (i >= PARTICIPANTS_ROW_COUNT) { + $(this).addClass('js-participants-hidden').hide(); + } + }); + } - if (currentText === originalText) { - $(this).text(lessText); + toggleHiddenParticipants() { + const currentText = $(this).text().trim(); + const lessText = $(this).data('less-text'); + const originalText = $(this).data('original-text'); - if (gl.lazyLoader) gl.lazyLoader.loadCheck(); - } else { - $(this).text(originalText); - } + if (currentText === originalText) { + $(this).text(lessText); - $('.js-participants-hidden').toggle(); - }; + if (gl.lazyLoader) gl.lazyLoader.loadCheck(); + } else { + $(this).text(originalText); + } - return IssuableContext; - })(); -}).call(window); + $('.js-participants-hidden').toggle(); + } +} diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js index 26dd946984d..57dcaa0e1ac 100644 --- a/app/assets/javascripts/issuable_form.js +++ b/app/assets/javascripts/issuable_form.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-new, quotes, object-shorthand, no-unused-vars, comma-dangle, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, max-len */ +/* eslint-disable func-names, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-new, object-shorthand, no-unused-vars, comma-dangle, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, max-len */ /* global GitLab */ import Pikaday from 'pikaday'; @@ -8,103 +8,100 @@ import GfmAutoComplete from './gfm_auto_complete'; import ZenMode from './zen_mode'; import { parsePikadayDate, pikadayToString } from './lib/utils/datefix'; -(function() { - this.IssuableForm = (function() { - IssuableForm.prototype.wipRegex = /^\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i; - - function IssuableForm(form) { - var $issuableDueDate, calendar; - this.form = form; - this.toggleWip = this.toggleWip.bind(this); - this.renderWipExplanation = this.renderWipExplanation.bind(this); - this.resetAutosave = this.resetAutosave.bind(this); - this.handleSubmit = this.handleSubmit.bind(this); - new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources).setup(); - new UsersSelect(); - new ZenMode(); - this.titleField = this.form.find("input[name*='[title]']"); - this.descriptionField = this.form.find("textarea[name*='[description]']"); - if (!(this.titleField.length && this.descriptionField.length)) { - return; - } - this.initAutosave(); - this.form.on("submit", this.handleSubmit); - this.form.on("click", ".btn-cancel", this.resetAutosave); - this.initWip(); - $issuableDueDate = $('#issuable-due-date'); - if ($issuableDueDate.length) { - calendar = new Pikaday({ - field: $issuableDueDate.get(0), - theme: 'gitlab-theme animate-picker', - format: 'yyyy-mm-dd', - container: $issuableDueDate.parent().get(0), - parse: dateString => parsePikadayDate(dateString), - toString: date => pikadayToString(date), - onSelect: function(dateText) { - $issuableDueDate.val(calendar.toString(dateText)); - } - }); - calendar.setDate(parsePikadayDate($issuableDueDate.val())); - } +export default class IssuableForm { + constructor(form) { + this.form = form; + this.toggleWip = this.toggleWip.bind(this); + this.renderWipExplanation = this.renderWipExplanation.bind(this); + this.resetAutosave = this.resetAutosave.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + this.wipRegex = /^\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i; + + new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources).setup(); + new UsersSelect(); + new ZenMode(); + + this.titleField = this.form.find('input[name*="[title]"]'); + this.descriptionField = this.form.find('textarea[name*="[description]"]'); + if (!(this.titleField.length && this.descriptionField.length)) { + return; } - IssuableForm.prototype.initAutosave = function() { - new Autosave(this.titleField, [document.location.pathname, document.location.search, "title"]); - return new Autosave(this.descriptionField, [document.location.pathname, document.location.search, "description"]); - }; - - IssuableForm.prototype.handleSubmit = function() { - return this.resetAutosave(); - }; - - IssuableForm.prototype.resetAutosave = function() { - this.titleField.data("autosave").reset(); - return this.descriptionField.data("autosave").reset(); - }; - - IssuableForm.prototype.initWip = function() { - this.$wipExplanation = this.form.find(".js-wip-explanation"); - this.$noWipExplanation = this.form.find(".js-no-wip-explanation"); - if (!(this.$wipExplanation.length && this.$noWipExplanation.length)) { - return; - } - this.form.on("click", ".js-toggle-wip", this.toggleWip); - this.titleField.on("keyup blur", this.renderWipExplanation); - return this.renderWipExplanation(); - }; - - IssuableForm.prototype.workInProgress = function() { - return this.wipRegex.test(this.titleField.val()); - }; - - IssuableForm.prototype.renderWipExplanation = function() { - if (this.workInProgress()) { - this.$wipExplanation.show(); - return this.$noWipExplanation.hide(); - } else { - this.$wipExplanation.hide(); - return this.$noWipExplanation.show(); - } - }; - - IssuableForm.prototype.toggleWip = function(event) { - event.preventDefault(); - if (this.workInProgress()) { - this.removeWip(); - } else { - this.addWip(); - } - return this.renderWipExplanation(); - }; - - IssuableForm.prototype.removeWip = function() { - return this.titleField.val(this.titleField.val().replace(this.wipRegex, "")); - }; - - IssuableForm.prototype.addWip = function() { - return this.titleField.val("WIP: " + (this.titleField.val())); - }; - - return IssuableForm; - })(); -}).call(window); + this.initAutosave(); + this.form.on('submit', this.handleSubmit); + this.form.on('click', '.btn-cancel', this.resetAutosave); + this.initWip(); + + const $issuableDueDate = $('#issuable-due-date'); + + if ($issuableDueDate.length) { + const calendar = new Pikaday({ + field: $issuableDueDate.get(0), + theme: 'gitlab-theme animate-picker', + format: 'yyyy-mm-dd', + container: $issuableDueDate.parent().get(0), + parse: dateString => parsePikadayDate(dateString), + toString: date => pikadayToString(date), + onSelect: dateText => $issuableDueDate.val(calendar.toString(dateText)), + }); + calendar.setDate(parsePikadayDate($issuableDueDate.val())); + } + } + + initAutosave() { + new Autosave(this.titleField, [document.location.pathname, document.location.search, 'title']); + return new Autosave(this.descriptionField, [document.location.pathname, document.location.search, 'description']); + } + + handleSubmit() { + return this.resetAutosave(); + } + + resetAutosave() { + this.titleField.data('autosave').reset(); + return this.descriptionField.data('autosave').reset(); + } + + initWip() { + this.$wipExplanation = this.form.find('.js-wip-explanation'); + this.$noWipExplanation = this.form.find('.js-no-wip-explanation'); + if (!(this.$wipExplanation.length && this.$noWipExplanation.length)) { + return; + } + this.form.on('click', '.js-toggle-wip', this.toggleWip); + this.titleField.on('keyup blur', this.renderWipExplanation); + return this.renderWipExplanation(); + } + + workInProgress() { + return this.wipRegex.test(this.titleField.val()); + } + + renderWipExplanation() { + if (this.workInProgress()) { + this.$wipExplanation.show(); + return this.$noWipExplanation.hide(); + } else { + this.$wipExplanation.hide(); + return this.$noWipExplanation.show(); + } + } + + toggleWip(event) { + event.preventDefault(); + if (this.workInProgress()) { + this.removeWip(); + } else { + this.addWip(); + } + return this.renderWipExplanation(); + } + + removeWip() { + return this.titleField.val(this.titleField.val().replace(this.wipRegex, '')); + } + + addWip() { + this.titleField.val(`WIP: ${(this.titleField.val())}`); + } +} diff --git a/app/assets/javascripts/issuable_index.js b/app/assets/javascripts/issuable_index.js index ece0220c927..0b123a11a3b 100644 --- a/app/assets/javascripts/issuable_index.js +++ b/app/assets/javascripts/issuable_index.js @@ -1,171 +1,42 @@ -/* eslint-disable no-param-reassign, func-names, no-var, camelcase, no-unused-vars, object-shorthand, space-before-function-paren, no-return-assign, comma-dangle, consistent-return, one-var, one-var-declaration-per-line, quotes, prefer-template, prefer-arrow-callback, wrap-iife, max-len */ -/* global IssuableIndex */ -import _ from 'underscore'; import IssuableBulkUpdateSidebar from './issuable_bulk_update_sidebar'; import IssuableBulkUpdateActions from './issuable_bulk_update_actions'; -((global) => { - var issuable_created; - - issuable_created = false; - - global.IssuableIndex = { - init: function(pagePrefix) { - IssuableIndex.initTemplates(); - IssuableIndex.initSearch(); - IssuableIndex.initBulkUpdate(pagePrefix); - IssuableIndex.initResetFilters(); - IssuableIndex.resetIncomingEmailToken(); - IssuableIndex.initLabelFilterRemove(); - }, - initTemplates: function() { - return IssuableIndex.labelRow = _.template('<% _.each(labels, function(label){ %> <span class="label-row btn-group" role="group" aria-label="<%- label.title %>" style="color: <%- label.text_color %>;"> <a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%- label.color %>;" title="<%- label.description %>" data-container="body"> <%- label.title %> </a> <button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%- label.color %>;" data-label="<%- label.title %>"> <i class="fa fa-times"></i> </button> </span> <% }); %>'); - }, - initSearch: function() { - const $searchInput = $('#issuable_search'); - - IssuableIndex.initSearchState($searchInput); - - // `immediate` param set to false debounces on the `trailing` edge, lets user finish typing - const debouncedExecSearch = _.debounce(IssuableIndex.executeSearch, 1000, false); - - $searchInput.off('keyup').on('keyup', debouncedExecSearch); - - // ensures existing filters are preserved when manually submitted - $('#issuable_search_form').on('submit', (e) => { - e.preventDefault(); - debouncedExecSearch(e); - }); - }, - initSearchState: function($searchInput) { - const currentSearchVal = $searchInput.val(); - - IssuableIndex.searchState = { - elem: $searchInput, - current: currentSearchVal - }; - - IssuableIndex.maybeFocusOnSearch(); - }, - accessSearchPristine: function(set) { - // store reference to previous value to prevent search on non-mutating keyup - const state = IssuableIndex.searchState; - const currentSearchVal = state.elem.val(); - - if (set) { - state.current = currentSearchVal; - } else { - return state.current === currentSearchVal; - } - }, - maybeFocusOnSearch: function() { - const currentSearchVal = IssuableIndex.searchState.current; - if (currentSearchVal && currentSearchVal !== '') { - const queryLength = currentSearchVal.length; - const $searchInput = IssuableIndex.searchState.elem; - - /* The following ensures that the cursor is initially placed at - * the end of search input when focus is applied. It accounts - * for differences in browser implementations of `setSelectionRange` - * and cursor placement for elements in focus. - */ - $searchInput.focus(); - if ($searchInput.setSelectionRange) { - $searchInput.setSelectionRange(queryLength, queryLength); - } else { - $searchInput.val(currentSearchVal); - } - } - }, - executeSearch: function(e) { - const $search = $('#issuable_search'); - const $searchName = $search.attr('name'); - const $searchValue = $search.val(); - const $filtersForm = $('.js-filter-form'); - const $input = $(`input[name='${$searchName}']`, $filtersForm); - const isPristine = IssuableIndex.accessSearchPristine(); - - if (isPristine) { - return; - } - - if (!$input.length) { - $filtersForm.append(`<input type='hidden' name='${$searchName}' value='${_.escape($searchValue)}'/>`); - } else { - $input.val($searchValue); - } - - IssuableIndex.filterResults($filtersForm); - }, - initLabelFilterRemove: function() { - return $(document).off('click', '.js-label-filter-remove').on('click', '.js-label-filter-remove', function(e) { - var $button; - $button = $(this); - // Remove the label input box - $('input[name="label_name[]"]').filter(function() { - return this.value === $button.data('label'); - }).remove(); - // Submit the form to get new data - IssuableIndex.filterResults($('.filter-form')); - }); - }, - filterResults: (function(_this) { - return function(form) { - var formAction, formData, issuesUrl; - formData = form.serializeArray(); - formData = formData.filter(function(data) { - return data.value !== ''; - }); - formData = $.param(formData); - formAction = form.attr('action'); - issuesUrl = formAction; - issuesUrl += "" + (formAction.indexOf('?') === -1 ? '?' : '&'); - issuesUrl += formData; - return gl.utils.visitUrl(issuesUrl); - }; - })(this), - initResetFilters: function() { - $('.reset-filters').on('click', function(e) { - e.preventDefault(); - const target = e.target; - const $form = $(target).parents('.js-filter-form'); - const baseIssuesUrl = target.href; - - $form.attr('action', baseIssuesUrl); - gl.utils.visitUrl(baseIssuesUrl); +export default class IssuableIndex { + constructor(pagePrefix) { + this.initBulkUpdate(pagePrefix); + IssuableIndex.resetIncomingEmailToken(); + } + initBulkUpdate(pagePrefix) { + const userCanBulkUpdate = $('.issues-bulk-update').length > 0; + const alreadyInitialized = !!this.bulkUpdateSidebar; + + if (userCanBulkUpdate && !alreadyInitialized) { + IssuableBulkUpdateActions.init({ + prefixId: pagePrefix, }); - }, - initBulkUpdate: function(pagePrefix) { - const userCanBulkUpdate = $('.issues-bulk-update').length > 0; - const alreadyInitialized = !!this.bulkUpdateSidebar; - - if (userCanBulkUpdate && !alreadyInitialized) { - IssuableBulkUpdateActions.init({ - prefixId: pagePrefix, - }); - - this.bulkUpdateSidebar = new IssuableBulkUpdateSidebar(); - } - }, - resetIncomingEmailToken: function() { - $('.incoming-email-token-reset').on('click', function(e) { - e.preventDefault(); - $.ajax({ - type: 'PUT', - url: $('.incoming-email-token-reset').attr('href'), - dataType: 'json', - success: function(response) { - $('#issue_email').val(response.new_issue_address).focus(); - }, - beforeSend: function() { - $('.incoming-email-token-reset').text('resetting...'); - }, - complete: function() { - $('.incoming-email-token-reset').text('reset it'); - } - }); - }); + this.bulkUpdateSidebar = new IssuableBulkUpdateSidebar(); } - }; -})(window); + } + + static resetIncomingEmailToken() { + $('.incoming-email-token-reset').on('click', (e) => { + e.preventDefault(); + + $.ajax({ + type: 'PUT', + url: $('.incoming-email-token-reset').attr('href'), + dataType: 'json', + success(response) { + $('#issue_email').val(response.new_issue_address).focus(); + }, + beforeSend() { + $('.incoming-email-token-reset').text('resetting...'); + }, + complete() { + $('.incoming-email-token-reset').text('reset it'); + }, + }); + }); + } +} diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js index 1e52963b1dd..84602cf9207 100644 --- a/app/assets/javascripts/labels_select.js +++ b/app/assets/javascripts/labels_select.js @@ -8,7 +8,7 @@ import CreateLabelDropdown from './create_label'; (function() { this.LabelsSelect = (function() { - function LabelsSelect(els, options = {}) { + function LabelsSelect(els) { var _this, $els; _this = this; @@ -58,7 +58,6 @@ import CreateLabelDropdown from './create_label'; labelHTMLTemplate = _.template('<% _.each(labels, function(label){ %> <a href="<%- ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name[]=<%- encodeURIComponent(label.title) %>"> <span class="label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;"> <%- label.title %> </span> </a> <% }); %>'); labelNoneHTMLTemplate = '<span class="no-value">None</span>'; } - const handleClick = options.handleClick; $sidebarLabelTooltip.tooltip(); @@ -317,9 +316,9 @@ import CreateLabelDropdown from './create_label'; }, multiSelect: $dropdown.hasClass('js-multiselect'), vue: $dropdown.hasClass('js-issue-board-sidebar'), - clicked: function(clickEvent) { - const { $el, e, isMarking } = clickEvent; - const label = clickEvent.selectedObj; + clicked: function(options) { + const { $el, e, isMarking } = options; + const label = options.selectedObj; var isIssueIndex, isMRIndex, page, boardsModel; var fadeOutLoader = () => { @@ -392,10 +391,6 @@ import CreateLabelDropdown from './create_label'; .then(fadeOutLoader) .catch(fadeOutLoader); } - else if (handleClick) { - e.preventDefault(); - handleClick(label); - } else { if ($dropdown.hasClass('js-multiselect')) { diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 7f045338417..fd9d0c335a5 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -55,9 +55,7 @@ import './gl_field_error'; import './gl_field_errors'; import './gl_form'; import './header'; -import './importer_status'; -import './issuable_index'; -import './issuable_context'; +import initImporterStatus from './importer_status'; import './issuable_form'; import './issue'; import './issue_status_select'; @@ -138,6 +136,7 @@ $(function () { var fitSidebarForSize; initBreadcrumbs(); + initImporterStatus(); // Set the default path for all cookies to GitLab's root directory Cookies.defaults.path = gon.relative_url_root || '/'; diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index 74e5a4f1cea..e7d5325a509 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -5,7 +5,7 @@ import _ from 'underscore'; (function() { this.MilestoneSelect = (function() { - function MilestoneSelect(currentProject, els, options = {}) { + function MilestoneSelect(currentProject, els) { var _this, $els; if (currentProject != null) { _this = this; @@ -136,26 +136,19 @@ import _ from 'underscore'; }, opened: function(e) { const $el = $(e.currentTarget); - if ($dropdown.hasClass('js-issue-board-sidebar') || options.handleClick) { + if ($dropdown.hasClass('js-issue-board-sidebar')) { selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault; } $('a.is-active', $el).removeClass('is-active'); $(`[data-milestone-id="${selectedMilestone}"] > a`, $el).addClass('is-active'); }, vue: $dropdown.hasClass('js-issue-board-sidebar'), - clicked: function(clickEvent) { - const { $el, e } = clickEvent; - let selected = clickEvent.selectedObj; + clicked: function(options) { + const { $el, e } = options; + let selected = options.selectedObj; var data, isIssueIndex, isMRIndex, isSelecting, page, boardsStore; if (!selected) return; - - if (options.handleClick) { - e.preventDefault(); - options.handleClick(selected); - return; - } - page = $('body').attr('data-page'); isIssueIndex = page === 'projects:issues:index'; isMRIndex = (page === page && page === 'projects:merge_requests:index'); diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js index fb01390f91c..bffc85e6315 100644 --- a/app/assets/javascripts/project_select.js +++ b/app/assets/javascripts/project_select.js @@ -2,13 +2,15 @@ import Api from './api'; import ProjectSelectComboButton from './project_select_combo_button'; -(function() { - this.ProjectSelect = (function() { +(function () { + this.ProjectSelect = (function () { function ProjectSelect() { $('.ajax-project-select').each(function(i, select) { var placeholder; + const simpleFilter = $(select).data('simple-filter') || false; this.groupId = $(select).data('group-id'); this.includeGroups = $(select).data('include-groups'); + this.allProjects = $(select).data('all-projects') || false; this.orderBy = $(select).data('order-by') || 'id'; this.withIssuesEnabled = $(select).data('with-issues-enabled'); this.withMergeRequestsEnabled = $(select).data('with-merge-requests-enabled'); @@ -21,10 +23,10 @@ import ProjectSelectComboButton from './project_select_combo_button'; $(select).select2({ placeholder: placeholder, minimumInputLength: 0, - query: (function(_this) { - return function(query) { + query: (function (_this) { + return function (query) { var finalCallback, projectsCallback; - finalCallback = function(projects) { + finalCallback = function (projects) { var data; data = { results: projects @@ -32,9 +34,9 @@ import ProjectSelectComboButton from './project_select_combo_button'; return query.callback(data); }; if (_this.includeGroups) { - projectsCallback = function(projects) { + projectsCallback = function (projects) { var groupsCallback; - groupsCallback = function(groups) { + groupsCallback = function (groups) { var data; data = groups.concat(projects); return finalCallback(data); @@ -50,23 +52,25 @@ import ProjectSelectComboButton from './project_select_combo_button'; return Api.projects(query.term, { order_by: _this.orderBy, with_issues_enabled: _this.withIssuesEnabled, - with_merge_requests_enabled: _this.withMergeRequestsEnabled + with_merge_requests_enabled: _this.withMergeRequestsEnabled, + membership: !_this.allProjects, }, projectsCallback); } }; })(this), id: function(project) { + if (simpleFilter) return project.id; return JSON.stringify({ name: project.name, url: project.web_url, }); }, - text: function(project) { + text: function (project) { return project.name_with_namespace || project.name; }, dropdownCssClass: "ajax-project-dropdown" }); - + if (simpleFilter) return select; return new ProjectSelectComboButton(select); }); } diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index 759cc9925f4..a0883b32593 100644 --- a/app/assets/javascripts/users_select.js +++ b/app/assets/javascripts/users_select.js @@ -6,7 +6,7 @@ import _ from 'underscore'; // TODO: remove eventHub hack after code splitting refactor window.emitSidebarEvent = window.emitSidebarEvent || $.noop; -function UsersSelect(currentUser, els, options = {}) { +function UsersSelect(currentUser, els) { var $els; this.users = this.users.bind(this); this.user = this.user.bind(this); @@ -20,8 +20,6 @@ function UsersSelect(currentUser, els, options = {}) { } } - const { handleClick } = options; - $els = $(els); if (!els) { @@ -444,9 +442,6 @@ function UsersSelect(currentUser, els, options = {}) { } if ($el.closest('.add-issues-modal').length) { gl.issueBoards.ModalStore.store.filter[$dropdown.data('field-name')] = user.id; - } else if (handleClick) { - e.preventDefault(); - handleClick(user, isMarking); } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { return Issuable.filterResults($dropdown.closest('form')); } else if ($dropdown.hasClass('js-filter-submit')) { diff --git a/app/assets/javascripts/vue_shared/components/loading_icon.vue b/app/assets/javascripts/vue_shared/components/loading_icon.vue index 494fe4468d9..15581d5c2a0 100644 --- a/app/assets/javascripts/vue_shared/components/loading_icon.vue +++ b/app/assets/javascripts/vue_shared/components/loading_icon.vue @@ -18,12 +18,6 @@ required: false, default: false, }, - - class: { - type: String, - required: false, - default: '', - }, }, computed: { @@ -31,7 +25,7 @@ return this.inline ? 'span' : 'div'; }, cssClass() { - return `fa-${this.size}x ${this.class}`.trim(); + return `fa-${this.size}x`; }, }, }; diff --git a/app/assets/javascripts/vue_shared/components/popup_dialog.vue b/app/assets/javascripts/vue_shared/components/popup_dialog.vue index fc6421fecb9..9e8c10bdc1a 100644 --- a/app/assets/javascripts/vue_shared/components/popup_dialog.vue +++ b/app/assets/javascripts/vue_shared/components/popup_dialog.vue @@ -5,27 +5,17 @@ export default { props: { title: { type: String, - required: false, + required: true, }, text: { type: String, required: false, }, - hideFooter: { - type: Boolean, - required: false, - default: false, - }, kind: { type: String, required: false, default: 'primary', }, - modalDialogClass: { - type: String, - required: false, - default: '', - }, closeKind: { type: String, required: false, @@ -40,11 +30,6 @@ export default { type: String, required: true, }, - submitDisabled: { - type: Boolean, - required: false, - default: false, - }, }, computed: { @@ -72,57 +57,43 @@ export default { </script> <template> -<div class="modal-open"> - <div - class="modal popup-dialog" - role="dialog" - tabindex="-1" - > - <div - :class="modalDialogClass" - class="modal-dialog" - role="document" - > - <div class="modal-content"> - <div class="modal-header"> - <slot name="header"> - <h4 class="modal-title pull-left"> - {{this.title}} - </h4> - <button - type="button" - class="close pull-right" - @click="close" - aria-label="Close" - > - <span aria-hidden="true">×</span> - </button> - </slot> - </div> - <div class="modal-body"> - <slot name="body" :text="text"> - <p>{{this.text}}</p> - </slot> - </div> - <div class="modal-footer" v-if="!hideFooter"> - <button - type="button" - class="btn pull-left" - :class="btnCancelKindClass" - @click="close"> - {{ closeButtonLabel }} - </button> - <button - type="button" - class="btn pull-right" - :class="btnKindClass" - @click="emitSubmit(true)"> - {{ primaryButtonLabel }} - </button> - </div> +<div + class="modal popup-dialog" + role="dialog" + tabindex="-1"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" + class="close" + @click="close" + aria-label="Close"> + <span aria-hidden="true">×</span> + </button> + <h4 class="modal-title">{{this.title}}</h4> + </div> + <div class="modal-body"> + <slot name="body" :text="text"> + <p>{{text}}</p> + </slot> + </div> + <div class="modal-footer"> + <button + type="button" + class="btn" + :class="btnCancelKindClass" + @click="close"> + {{ closeButtonLabel }} + </button> + <button + type="button" + class="btn" + :class="btnKindClass" + @click="emitSubmit(true)"> + {{ primaryButtonLabel }} + </button> </div> </div> </div> - <div class="modal-backdrop fade in" /> </div> </template> diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 1cfd7ef01a8..96f9dda26c4 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -4,9 +4,6 @@ .cred { color: $common-red; } .cgreen { color: $common-green; } .cdark { color: $common-gray-dark; } -.text-secondary { - color: $gl-text-color-secondary; -} /** COMMON CLASSES **/ .prepend-top-0 { margin-top: 0; } diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index 63697fd38a7..a9d804e735d 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -37,7 +37,6 @@ .dropdown-menu-nav { @include set-visible; display: block; - min-height: 40px; @media (max-width: $screen-xs-max) { width: 100%; diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss index 52b87de7a3d..dc591c06c88 100644 --- a/app/assets/stylesheets/framework/gitlab-theme.scss +++ b/app/assets/stylesheets/framework/gitlab-theme.scss @@ -216,12 +216,9 @@ body { color: $theme-gray-900; } - &.active > a { + &.active > a, + &.active > a:hover { color: $white-light; - - &:hover { - color: $white-light; - } } } } diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index d79444fad79..62ba74ff582 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -239,10 +239,8 @@ fill: currentColor; } - &.header-user-dropdown-toggle { - .header-user-avatar { - border-color: $white-light; - } + &.header-user-dropdown-toggle .header-user-avatar { + border-color: $white-light; } } } diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss index d218fb6d702..1cebd02df48 100644 --- a/app/assets/stylesheets/framework/modal.scss +++ b/app/assets/stylesheets/framework/modal.scss @@ -42,11 +42,3 @@ body.modal-open { width: 98%; } } - -.modal.popup-dialog { - display: block; -} - -.modal-body { - background-color: $modal-body-bg; -} diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss index a23131e0818..3ea77eb7a43 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss @@ -164,36 +164,3 @@ $pre-border-color: $border-color; $table-bg-accent: $gray-light; $zindex-popover: 900; - -//== Modals -// -//## - -//** Padding applied to the modal body -$modal-inner-padding: $gl-padding; - -//** Padding applied to the modal title -$modal-title-padding: $gl-padding; -//** Modal title line-height -// $modal-title-line-height: $line-height-base - -//** Background color of modal content area -$modal-content-bg: $gray-light; -$modal-body-bg: $white-light; -//** Modal content border color -// $modal-content-border-color: rgba(0,0,0,.2) -//** Modal content border color **for IE8** -// $modal-content-fallback-border-color: #999 - -//** Modal backdrop background color -// $modal-backdrop-bg: #000 -//** Modal backdrop opacity -// $modal-backdrop-opacity: .5 -//** Modal header border color -// $modal-header-border-color: #e5e5e5 -//** Modal footer border color -// $modal-footer-border-color: $modal-header-border-color - -// $modal-lg: 900px -// $modal-md: 600px -// $modal-sm: 300px diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 3bd0e3ad535..312917bd13a 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -269,7 +269,7 @@ ul.notes { display: none; } - &.system-note-commit-list { + &.system-note-commit-list:not(.hide-shade) { max-height: 70px; overflow: hidden; display: block; @@ -291,16 +291,6 @@ ul.notes { bottom: 0; background: linear-gradient(rgba($white-light, 0.1) -100px, $white-light 100%); } - - &.hide-shade { - max-height: 100%; - overflow: auto; - - &::after { - display: none; - background: transparent; - } - } } } } diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index 45aaeb77a48..1bb4e3cc345 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -1,3 +1,16 @@ +.modal.popup-dialog { + display: block; + background-color: $black-transparent; + z-index: 2100; + + @media (min-width: $screen-md-min) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + } +} + .project-refs-form, .project-refs-target-form { display: inline-block; diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb index c4a621160af..7112c6ee470 100644 --- a/app/helpers/boards_helper.rb +++ b/app/helpers/boards_helper.rb @@ -20,6 +20,17 @@ module BoardsHelper project_issues_path(@project) end + def current_board_json + board = @board || @boards.first + + board.to_json( + only: [:id, :name, :milestone_id], + include: { + milestone: { only: [:title] } + } + ) + end + def board_base_url project_boards_path(@project) end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index f266e7db6da..5e16badabec 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -420,7 +420,7 @@ class ApplicationSetting < ActiveRecord::Base # the enabling/disabling is `performance_bar_allowed_group_id` # - If `enable` is false, we set `performance_bar_allowed_group_id` to `nil` def performance_bar_enabled=(enable) - return if enable + return if Gitlab::Utils.to_boolean(enable) self.performance_bar_allowed_group_id = nil end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 07352db5d2d..d45b9c805a4 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -878,7 +878,7 @@ class MergeRequest < ActiveRecord::Base # def all_commit_shas if persisted? - column_shas = MergeRequestDiffCommit.where(merge_request_diff: merge_request_diffs).pluck('DISTINCT(sha)') + column_shas = MergeRequestDiffCommit.where(merge_request_diff: merge_request_diffs).limit(10_000).pluck('sha') serialised_shas = merge_request_diffs.where.not(st_commits: nil).flat_map(&:commit_shas) (column_shas + serialised_shas).uniq diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb index 35de4337b15..62b4b4b6a1e 100644 --- a/app/services/issues/reopen_service.rb +++ b/app/services/issues/reopen_service.rb @@ -9,6 +9,7 @@ module Issues notification_service.reopen_issue(issue, current_user) execute_hooks(issue, 'reopen') invalidate_cache_counts(issue, users: issue.assignees) + issue.update_project_counter_caches end issue diff --git a/app/services/merge_requests/reopen_service.rb b/app/services/merge_requests/reopen_service.rb index b9c65be36ec..c599a90f9fe 100644 --- a/app/services/merge_requests/reopen_service.rb +++ b/app/services/merge_requests/reopen_service.rb @@ -11,6 +11,7 @@ module MergeRequests merge_request.reload_diff(current_user) merge_request.mark_as_unchecked invalidate_cache_counts(merge_request, users: merge_request.assignees) + merge_request.update_project_counter_caches end merge_request diff --git a/app/views/groups/milestones/_form.html.haml b/app/views/groups/milestones/_form.html.haml index cc879e5a308..a1be0d3220a 100644 --- a/app/views/groups/milestones/_form.html.haml +++ b/app/views/groups/milestones/_form.html.haml @@ -11,7 +11,7 @@ = f.label :description, "Description", class: "control-label" .col-sm-10 = render layout: 'projects/md_preview', locals: { url: group_preview_markdown_path } do - = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: 'Write milestone description...' + = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: 'Write milestone description...', supports_autocomplete: false .clearfix .error-alert diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml index f82207559a3..66146e61263 100644 --- a/app/views/layouts/nav/sidebar/_project.html.haml +++ b/app/views/layouts/nav/sidebar/_project.html.haml @@ -274,7 +274,7 @@ Members %ul.sidebar-sub-level-items.is-fly-out-only = nav_link(path: %w[members#show], html_options: { class: "fly-out-top-item" } ) do - = link_to project_settings_members_path(@project) do + = link_to project_project_members_path(@project) do %strong.fly-out-top-item-name #{ _('Members') } |