diff options
Diffstat (limited to 'app/assets/javascripts')
73 files changed, 411 insertions, 299 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/render_metrics.js b/app/assets/javascripts/behaviors/markdown/render_metrics.js index 252b98610b6..8050604e6e7 100644 --- a/app/assets/javascripts/behaviors/markdown/render_metrics.js +++ b/app/assets/javascripts/behaviors/markdown/render_metrics.js @@ -2,7 +2,7 @@ import Vue from 'vue'; import Metrics from '~/monitoring/components/embed.vue'; import { createStore } from '~/monitoring/stores'; -// TODO: Handle copy-pasting - https://gitlab.com/gitlab-org/gitlab-ce/issues/64369. +// TODO: Handle copy-pasting - https://gitlab.com/gitlab-org/gitlab-foss/issues/64369. export default function renderMetrics(elements) { if (!elements.length) { return; diff --git a/app/assets/javascripts/behaviors/preview_markdown.js b/app/assets/javascripts/behaviors/preview_markdown.js index b2571fb840c..1909830e9ed 100644 --- a/app/assets/javascripts/behaviors/preview_markdown.js +++ b/app/assets/javascripts/behaviors/preview_markdown.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, object-shorthand, prefer-arrow-callback */ +/* eslint-disable func-names, no-var, prefer-arrow-callback */ import $ from 'jquery'; import axios from '~/lib/utils/axios_utils'; @@ -82,7 +82,7 @@ MarkdownPreview.prototype.fetchMarkdownPreview = function(text, url, success) { }) .then(({ data }) => { this.ajaxCache = { - text: text, + text, response: data, }; success(data); diff --git a/app/assets/javascripts/blob/blob_file_dropzone.js b/app/assets/javascripts/blob/blob_file_dropzone.js index 9010cd0c3c1..9f0680cc6a7 100644 --- a/app/assets/javascripts/blob/blob_file_dropzone.js +++ b/app/assets/javascripts/blob/blob_file_dropzone.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, object-shorthand, prefer-arrow-callback */ +/* eslint-disable func-names, prefer-arrow-callback */ import $ from 'jquery'; import Dropzone from 'dropzone'; @@ -32,7 +32,7 @@ export default class BlobFileDropzone { url: form.attr('action'), // Rails uses a hidden input field for PUT // http://stackoverflow.com/questions/21056482/how-to-set-method-put-in-form-tag-in-rails - method: method, + method, clickable: true, uploadMultiple: false, paramName: 'file', @@ -42,7 +42,7 @@ export default class BlobFileDropzone { addRemoveLinks: true, previewsContainer: '.dropzone-previews', headers: csrf.headers, - init: function() { + init() { this.on('addedfile', function() { toggleLoading(submitButton, submitButtonLoadingIcon, false); dropzoneMessage.addClass(HIDDEN_CLASS); @@ -69,7 +69,7 @@ export default class BlobFileDropzone { }); }, // Override behavior of adding error underneath preview - error: function(file, errorMessage) { + error(file, errorMessage) { const stripped = $('<div/>') .html(errorMessage) .text(); diff --git a/app/assets/javascripts/boards/components/board.js b/app/assets/javascripts/boards/components/board.js index c6122fbc686..58759fd1efe 100644 --- a/app/assets/javascripts/boards/components/board.js +++ b/app/assets/javascripts/boards/components/board.js @@ -50,6 +50,9 @@ export default Vue.extend({ }; }, computed: { + isLoggedIn() { + return Boolean(gon.current_user_id); + }, counterTooltip() { const { issuesSize } = this.list; return `${n__('%d issue', '%d issues', issuesSize)}`; @@ -106,7 +109,11 @@ export default Vue.extend({ Sortable.create(this.$el.parentNode, sortableOptions); }, created() { - if (this.list.isExpandable && AccessorUtilities.isLocalStorageAccessSafe()) { + if ( + this.list.isExpandable && + AccessorUtilities.isLocalStorageAccessSafe() && + !this.isLoggedIn + ) { const isCollapsed = localStorage.getItem(`${this.uniqueKey}.expanded`) === 'false'; this.list.isExpanded = !isCollapsed; @@ -120,10 +127,14 @@ export default Vue.extend({ if (this.list.isExpandable) { this.list.isExpanded = !this.list.isExpanded; - if (AccessorUtilities.isLocalStorageAccessSafe()) { + if (AccessorUtilities.isLocalStorageAccessSafe() && !this.isLoggedIn) { localStorage.setItem(`${this.uniqueKey}.expanded`, this.list.isExpanded); } + if (this.isLoggedIn) { + this.list.update(); + } + // When expanding/collapsing, the tooltip on the caret button sometimes stays open. // Close all tooltips manually to prevent dangling tooltips. $('.tooltip').tooltip('hide'); diff --git a/app/assets/javascripts/boards/components/new_list_dropdown.js b/app/assets/javascripts/boards/components/new_list_dropdown.js index c8a9cb1c296..229bb82152b 100644 --- a/app/assets/javascripts/boards/components/new_list_dropdown.js +++ b/app/assets/javascripts/boards/components/new_list_dropdown.js @@ -1,7 +1,9 @@ -/* eslint-disable func-names, no-new, promise/catch-or-return */ +/* eslint-disable func-names, no-new */ import $ from 'jquery'; +import { __ } from '~/locale'; import axios from '~/lib/utils/axios_utils'; +import flash from '~/flash'; import CreateLabelDropdown from '../../create_label'; import boardsStore from '../stores/boards_store'; @@ -26,18 +28,23 @@ $(document) export default function initNewListDropdown() { $('.js-new-board-list').each(function() { - const $this = $(this); + const $dropdownToggle = $(this); + const $dropdown = $dropdownToggle.closest('.dropdown'); new CreateLabelDropdown( - $this.closest('.dropdown').find('.dropdown-new-label'), - $this.data('namespacePath'), - $this.data('projectPath'), + $dropdown.find('.dropdown-new-label'), + $dropdownToggle.data('namespacePath'), + $dropdownToggle.data('projectPath'), ); - $this.glDropdown({ + $dropdownToggle.glDropdown({ data(term, callback) { - axios.get($this.attr('data-list-labels-path')).then(({ data }) => { - callback(data); - }); + axios + .get($dropdownToggle.attr('data-list-labels-path')) + .then(({ data }) => callback(data)) + .catch(() => { + $dropdownToggle.data('bs.dropdown').hide(); + flash(__('Error fetching labels.')); + }); }, renderRow(label) { const active = boardsStore.findListByLabelId(label.id); diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js index 086340105b7..1cee9e5725a 100644 --- a/app/assets/javascripts/boards/models/issue.js +++ b/app/assets/javascripts/boards/models/issue.js @@ -11,11 +11,6 @@ import boardsStore from '../stores/boards_store'; class ListIssue { constructor(obj, defaultAvatar) { - this.id = obj.id; - this.iid = obj.iid; - this.title = obj.title; - this.confidential = obj.confidential; - this.dueDate = obj.due_date; this.subscribed = obj.subscribed; this.labels = []; this.assignees = []; @@ -25,6 +20,16 @@ class ListIssue { subscriptions: true, }; this.isLoading = {}; + + this.refreshData(obj, defaultAvatar); + } + + refreshData(obj, defaultAvatar) { + this.id = obj.id; + this.iid = obj.iid; + this.title = obj.title; + this.confidential = obj.confidential; + this.dueDate = obj.due_date; this.sidebarInfoEndpoint = obj.issue_sidebar_endpoint; this.referencePath = obj.reference_path; this.path = obj.real_path; @@ -42,11 +47,13 @@ class ListIssue { this.milestone_id = obj.milestone.id; } - obj.labels.forEach(label => { - this.labels.push(new ListLabel(label)); - }); + if (obj.labels) { + this.labels = obj.labels.map(label => new ListLabel(label)); + } - this.assignees = obj.assignees.map(a => new ListAssignee(a, defaultAvatar)); + if (obj.assignees) { + this.assignees = obj.assignees.map(a => new ListAssignee(a, defaultAvatar)); + } } addLabel(label) { diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index 1edaf971afd..b3e56a34c28 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -1,4 +1,4 @@ -/* eslint-disable no-underscore-dangle, class-methods-use-this, consistent-return, no-shadow, no-param-reassign */ +/* eslint-disable no-underscore-dangle, class-methods-use-this, consistent-return, no-shadow */ import { __ } from '~/locale'; import ListLabel from './label'; @@ -45,7 +45,7 @@ class List { const typeInfo = this.getTypeInfo(this.type); this.preset = Boolean(typeInfo.isPreset); this.isExpandable = Boolean(typeInfo.isExpandable); - this.isExpanded = true; + this.isExpanded = !obj.collapsed; this.page = 1; this.loading = true; this.loadingMore = false; @@ -113,7 +113,8 @@ class List { } update() { - gl.boardService.updateList(this.id, this.position).catch(() => { + const collapsed = !this.isExpanded; + return gl.boardService.updateList(this.id, this.position, collapsed).catch(() => { // TODO: handle request error }); } @@ -259,12 +260,7 @@ class List { } onNewIssueResponse(issue, data) { - issue.id = data.id; - issue.iid = data.iid; - issue.project = data.project; - issue.path = data.real_path; - issue.referencePath = data.reference_path; - issue.assignableLabelsEndpoint = data.assignable_labels_endpoint; + issue.refreshData(data); if (this.issuesSize > 1) { const moveBeforeId = this.issues[1].id; diff --git a/app/assets/javascripts/boards/services/board_service.js b/app/assets/javascripts/boards/services/board_service.js index 56a6cab6c73..0d11db89511 100644 --- a/app/assets/javascripts/boards/services/board_service.js +++ b/app/assets/javascripts/boards/services/board_service.js @@ -2,7 +2,7 @@ /** * This file is intended to be deleted. * The existing functions will removed one by one in favor of using the board store directly. - * see https://gitlab.com/gitlab-org/gitlab-ce/issues/61621 + * see https://gitlab.com/gitlab-org/gitlab-foss/issues/61621 */ import boardsStore from '~/boards/stores/boards_store'; @@ -32,8 +32,8 @@ export default class BoardService { return boardsStore.createList(entityId, entityType); } - updateList(id, position) { - return boardsStore.updateList(id, position); + updateList(id, position, collapsed) { + return boardsStore.updateList(id, position, collapsed); } destroyList(id) { diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index f57c684691c..6da1cca9628 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -82,7 +82,7 @@ const boardsStore = { this.state.lists = _.sortBy(this.state.lists, 'position'); }) .catch(() => { - // https://gitlab.com/gitlab-org/gitlab-ce/issues/30821 + // https://gitlab.com/gitlab-org/gitlab-foss/issues/30821 }); this.removeBlankState(); }, @@ -278,10 +278,11 @@ const boardsStore = { }); }, - updateList(id, position) { + updateList(id, position, collapsed) { return axios.put(`${this.state.endpoints.listsEndpoint}/${id}`, { list: { position, + collapsed, }, }); }, diff --git a/app/assets/javascripts/boards/stores/boards_store_ee.js b/app/assets/javascripts/boards/stores/boards_store_ee.js index 09e3a938fbe..2a289ce5d0a 100644 --- a/app/assets/javascripts/boards/stores/boards_store_ee.js +++ b/app/assets/javascripts/boards/stores/boards_store_ee.js @@ -1,4 +1,4 @@ -// this is just to make ee_else_ce happy and will be cleaned up in https://gitlab.com/gitlab-org/gitlab-ce/issues/59807 +// this is just to make ee_else_ce happy and will be cleaned up in https://gitlab.com/gitlab-org/gitlab-foss/issues/59807 export default { initEESpecific() {}, diff --git a/app/assets/javascripts/ci_variable_list/ci_variable_list.js b/app/assets/javascripts/ci_variable_list/ci_variable_list.js index 0303e4e51dd..5c79f245f6d 100644 --- a/app/assets/javascripts/ci_variable_list/ci_variable_list.js +++ b/app/assets/javascripts/ci_variable_list/ci_variable_list.js @@ -54,7 +54,7 @@ export default class VariableList { environment_scope: { // We can't use a `.js-` class here because // gl_dropdown replaces the <input> and doesn't copy over the class - // See https://gitlab.com/gitlab-org/gitlab-ce/issues/42458 + // See https://gitlab.com/gitlab-org/gitlab-foss/issues/42458 selector: `input[name="${this.formField}[variables_attributes][][environment_scope]"]`, default: '*', }, diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index 28850710f80..d386960f3b6 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -111,15 +111,25 @@ export default class Clusters { this.initApplications(clusterType); this.initEnvironments(); - if (clusterEnvironmentsPath) { - this.fetchEnvironments(); + if (clusterEnvironmentsPath && this.environments) { + this.store.toggleFetchEnvironments(true); + + this.initPolling( + 'fetchClusterEnvironments', + data => this.handleClusterEnvironmentsSuccess(data), + () => this.handleEnvironmentsPollError(), + ); } this.updateContainer(null, this.store.state.status, this.store.state.statusReason); this.addListeners(); if (statusPath && !this.environments) { - this.initPolling(); + this.initPolling( + 'fetchClusterStatus', + data => this.handleClusterStatusSuccess(data), + () => this.handlePollError(), + ); } } @@ -179,16 +189,9 @@ export default class Clusters { }); } - fetchEnvironments() { - this.store.toggleFetchEnvironments(true); - - this.service - .fetchClusterEnvironments() - .then(data => { - this.store.toggleFetchEnvironments(false); - this.store.updateEnvironments(data.data); - }) - .catch(() => Clusters.handleError()); + handleClusterEnvironmentsSuccess(data) { + this.store.toggleFetchEnvironments(false); + this.store.updateEnvironments(data.data); } static initDismissableCallout() { @@ -224,21 +227,16 @@ export default class Clusters { eventHub.$off('uninstallApplication'); } - initPolling() { + initPolling(method, successCallback, errorCallback) { this.poll = new Poll({ resource: this.service, - method: 'fetchData', - successCallback: data => this.handleSuccess(data), - errorCallback: () => Clusters.handleError(), + method, + successCallback, + errorCallback, }); if (!Visibility.hidden()) { this.poll.makeRequest(); - } else { - this.service - .fetchData() - .then(data => this.handleSuccess(data)) - .catch(() => Clusters.handleError()); } Visibility.change(() => { @@ -250,11 +248,21 @@ export default class Clusters { }); } + handlePollError() { + this.constructor.handleError(); + } + + handleEnvironmentsPollError() { + this.store.toggleFetchEnvironments(false); + + this.handlePollError(); + } + static handleError() { Flash(s__('ClusterIntegration|Something went wrong on our end.')); } - handleSuccess(data) { + handleClusterStatusSuccess(data) { const prevStatus = this.store.state.status; const prevApplicationMap = Object.assign({}, this.store.state.applications); diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js index 9139e0beafb..fa12802b3de 100644 --- a/app/assets/javascripts/clusters/services/clusters_service.js +++ b/app/assets/javascripts/clusters/services/clusters_service.js @@ -17,7 +17,7 @@ export default class ClusterService { }; } - fetchData() { + fetchClusterStatus() { return axios.get(this.options.endpoint); } diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js index a032f589ee4..5cddb4cc098 100644 --- a/app/assets/javascripts/clusters/stores/clusters_store.js +++ b/app/assets/javascripts/clusters/stores/clusters_store.js @@ -218,6 +218,7 @@ export default class ClusterStore { environmentPath: environment.environment_path, lastDeployment: environment.last_deployment, rolloutStatus: { + status: environment.rollout_status ? environment.rollout_status.status : null, instances: environment.rollout_status ? environment.rollout_status.instances : [], }, updatedAt: environment.updated_at, diff --git a/app/assets/javascripts/compare_autocomplete.js b/app/assets/javascripts/compare_autocomplete.js index 5bfe158ceda..81ba15577fb 100644 --- a/app/assets/javascripts/compare_autocomplete.js +++ b/app/assets/javascripts/compare_autocomplete.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, one-var, no-var, object-shorthand, no-else-return */ +/* eslint-disable func-names, one-var, no-var, no-else-return */ import $ from 'jquery'; import { __ } from './locale'; @@ -15,7 +15,7 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = ( const $fieldInput = $(`input[name="${$dropdown.data('fieldName')}"]`, $dropdownContainer); const $filterInput = $('input[type="search"]', $dropdownContainer); $dropdown.glDropdown({ - data: function(term, callback) { + data(term, callback) { const params = { ref: $dropdown.data('ref'), search: term, @@ -43,7 +43,7 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = ( filterRemote: Boolean($dropdown.data('refsUrl')), fieldName: $dropdown.data('fieldName'), filterInput: 'input[type="search"]', - renderRow: function(ref) { + renderRow(ref) { var link; if (ref.header != null) { return $('<li />') @@ -58,10 +58,10 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = ( return $('<li />').append(link); } }, - id: function(obj, $el) { + id(obj, $el) { return $el.attr('data-ref'); }, - toggleLabel: function(obj, $el) { + toggleLabel(obj, $el) { return $el.text().trim(); }, clicked: () => clickHandler($dropdown), diff --git a/app/assets/javascripts/contextual_sidebar.js b/app/assets/javascripts/contextual_sidebar.js index 9263e9b27e4..f43b6f3d777 100644 --- a/app/assets/javascripts/contextual_sidebar.js +++ b/app/assets/javascripts/contextual_sidebar.js @@ -5,7 +5,7 @@ import bp from './breakpoints'; import { parseBoolean } from '~/lib/utils/common_utils'; // NOTE: at 1200px nav sidebar should not overlap the content -// https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/24555#note_134136110 +// https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24555#note_134136110 const NAV_SIDEBAR_BREAKPOINT = 1200; export const SIDEBAR_COLLAPSED_CLASS = 'js-sidebar-collapsed'; diff --git a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue index 333ea111cd6..55e5f4ffad2 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue +++ b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue @@ -32,7 +32,7 @@ export default { <div class="item-details"> <!-- FIXME: Pass an alt attribute here for accessibility --> <user-avatar-image :img-src="mergeRequest.author.avatarUrl" /> - <h5 class="item-title merge-merquest-title"> + <h5 class="item-title merge-request-title"> <a :href="mergeRequest.url"> {{ mergeRequest.title }} </a> </h5> <a :href="mergeRequest.url" class="issue-link"> !{{ mergeRequest.iid }} </a> · diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue index f874f11aff0..a295c8b496b 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue +++ b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue @@ -34,7 +34,7 @@ export default { <div class="item-details"> <!-- FIXME: Pass an alt attribute here for accessibility --> <user-avatar-image :img-src="mergeRequest.author.avatarUrl" /> - <h5 class="item-title merge-merquest-title"> + <h5 class="item-title merge-request-title"> <a :href="mergeRequest.url"> {{ mergeRequest.title }} </a> </h5> <a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a> · diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js index c9a6b10b2f3..7744984edfc 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js @@ -74,7 +74,7 @@ export default () => { // after a group is selected the cycle analyitcs data will be fetched). Once the // old (current) page has been removed this entire created method as well as the // variable itself can be completely removed. - // Follow up issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/64490 + // Follow up issue: https://gitlab.com/gitlab-org/gitlab-foss/issues/64490 if (cycleAnalyticsEl.dataset.requestPath) this.fetchCycleAnalyticsData(); }, methods: { diff --git a/app/assets/javascripts/diff.js b/app/assets/javascripts/diff.js index 245f1a7c558..a343138a9e1 100644 --- a/app/assets/javascripts/diff.js +++ b/app/assets/javascripts/diff.js @@ -5,7 +5,7 @@ import { __ } from '~/locale'; import { getLocationHash } from './lib/utils/url_utility'; import FilesCommentButton from './files_comment_button'; import SingleFileDiff from './single_file_diff'; -import imageDiffHelper from './image_diff/helpers/index'; +import initImageDiffHelper from './image_diff/helpers/init_image_diff'; const UNFOLD_COUNT = 20; let isBound = false; @@ -28,7 +28,7 @@ export default class Diff { .first() .get(0); const canCreateNote = firstFile && firstFile.hasAttribute('data-can-create-note'); - $diffFile.each((index, file) => imageDiffHelper.initImageDiff(file, canCreateNote)); + $diffFile.each((index, file) => initImageDiffHelper.initImageDiff(file, canCreateNote)); if (!isBound) { $(document) diff --git a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js index 7817b41514d..84e07598fed 100644 --- a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js +++ b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js @@ -1,4 +1,4 @@ -/* eslint-disable object-shorthand, func-names, no-else-return, no-lonely-if */ +/* eslint-disable no-else-return, no-lonely-if */ /* global CommentsStore */ import $ from 'jquery'; @@ -19,17 +19,17 @@ const CommentAndResolveBtn = Vue.extend({ }; }, computed: { - showButton: function() { + showButton() { if (this.discussion) { return this.discussion.isResolvable(); } else { return false; } }, - isDiscussionResolved: function() { + isDiscussionResolved() { return this.discussion.isResolved(); }, - buttonText: function() { + buttonText() { if (this.isDiscussionResolved) { if (this.textareaIsEmpty) { return __('Unresolve thread'); @@ -50,7 +50,7 @@ const CommentAndResolveBtn = Vue.extend({ this.discussion = CommentsStore.state[this.discussionId]; } }, - mounted: function() { + mounted() { if (!this.discussionId) return; const $textarea = $( @@ -62,7 +62,7 @@ const CommentAndResolveBtn = Vue.extend({ this.textareaIsEmpty = $textarea.val() === ''; }); }, - destroyed: function() { + destroyed() { if (!this.discussionId) return; $(`.js-discussion-note-form[data-discussion-id=${this.discussionId}] .note-textarea`).off( diff --git a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js index fe4088cadda..092c69a01d3 100644 --- a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js +++ b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js @@ -1,4 +1,4 @@ -/* eslint-disable object-shorthand, func-names, no-else-return, guard-for-in, no-restricted-syntax, no-lonely-if, no-continue */ +/* eslint-disable func-names, no-else-return, guard-for-in, no-restricted-syntax, no-lonely-if, no-continue */ /* global CommentsStore */ import $ from 'jquery'; @@ -15,24 +15,24 @@ const JumpToDiscussion = Vue.extend({ required: true, }, }, - data: function() { + data() { return { discussions: CommentsStore.state, discussion: {}, }; }, computed: { - buttonText: function() { + buttonText() { if (this.discussionId) { return __('Jump to next unresolved discussion'); } else { return __('Jump to first unresolved discussion'); } }, - allResolved: function() { + allResolved() { return this.unresolvedDiscussionCount === 0; }, - showButton: function() { + showButton() { if (this.discussionId) { if (this.unresolvedDiscussionCount > 1) { return true; @@ -43,7 +43,7 @@ const JumpToDiscussion = Vue.extend({ return this.unresolvedDiscussionCount >= 1; } }, - lastResolvedId: function() { + lastResolvedId() { let lastId; for (const discussionId in this.discussions) { const discussion = this.discussions[discussionId]; @@ -59,7 +59,7 @@ const JumpToDiscussion = Vue.extend({ this.discussion = this.discussions[this.discussionId]; }, methods: { - jumpToNextUnresolvedDiscussion: function() { + jumpToNextUnresolvedDiscussion() { let discussionsSelector; let discussionIdsInScope; let firstUnresolvedDiscussionId; diff --git a/app/assets/javascripts/diff_notes/components/resolve_count.js b/app/assets/javascripts/diff_notes/components/resolve_count.js index d8b056096f4..f960853b25b 100644 --- a/app/assets/javascripts/diff_notes/components/resolve_count.js +++ b/app/assets/javascripts/diff_notes/components/resolve_count.js @@ -1,4 +1,3 @@ -/* eslint-disable object-shorthand, func-names */ /* global CommentsStore */ import Vue from 'vue'; @@ -13,13 +12,13 @@ window.ResolveCount = Vue.extend({ required: true, }, }, - data: function() { + data() { return { discussions: CommentsStore.state, }; }, computed: { - allResolved: function() { + allResolved() { return this.resolvedDiscussionCount === this.discussionCount; }, resolvedCountText() { diff --git a/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js b/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js index 4b204fdfeb0..5f2a17da630 100644 --- a/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js +++ b/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js @@ -1,4 +1,4 @@ -/* eslint-disable object-shorthand, func-names, no-else-return */ +/* eslint-disable no-else-return */ /* global CommentsStore */ /* global ResolveService */ @@ -20,34 +20,34 @@ const ResolveDiscussionBtn = Vue.extend({ required: true, }, }, - data: function() { + data() { return { discussion: {}, }; }, computed: { - showButton: function() { + showButton() { if (this.discussion) { return this.discussion.isResolvable(); } else { return false; } }, - isDiscussionResolved: function() { + isDiscussionResolved() { if (this.discussion) { return this.discussion.isResolved(); } else { return false; } }, - buttonText: function() { + buttonText() { if (this.isDiscussionResolved) { return __('Unresolve discussion'); } else { return __('Resolve discussion'); } }, - loading: function() { + loading() { if (this.discussion) { return this.discussion.loading; } else { @@ -55,13 +55,13 @@ const ResolveDiscussionBtn = Vue.extend({ } }, }, - created: function() { + created() { CommentsStore.createDiscussion(this.discussionId, this.canResolve); this.discussion = CommentsStore.state[this.discussionId]; }, methods: { - resolve: function() { + resolve() { ResolveService.toggleResolveForDiscussion(this.mergeRequestId, this.discussionId); }, }, diff --git a/app/assets/javascripts/diff_notes/mixins/discussion.js b/app/assets/javascripts/diff_notes/mixins/discussion.js index dea64dca132..ef3001393cf 100644 --- a/app/assets/javascripts/diff_notes/mixins/discussion.js +++ b/app/assets/javascripts/diff_notes/mixins/discussion.js @@ -1,11 +1,11 @@ -/* eslint-disable object-shorthand, func-names, guard-for-in, no-restricted-syntax, */ +/* eslint-disable guard-for-in, no-restricted-syntax, */ const DiscussionMixins = { computed: { - discussionCount: function() { + discussionCount() { return Object.keys(this.discussions).length; }, - resolvedDiscussionCount: function() { + resolvedDiscussionCount() { let resolvedCount = 0; for (const discussionId in this.discussions) { @@ -18,7 +18,7 @@ const DiscussionMixins = { return resolvedCount; }, - unresolvedDiscussionCount: function() { + unresolvedDiscussionCount() { let unresolvedCount = 0; for (const discussionId in this.discussions) { diff --git a/app/assets/javascripts/diff_notes/stores/comments.js b/app/assets/javascripts/diff_notes/stores/comments.js index 060bb044f78..69a972f644d 100644 --- a/app/assets/javascripts/diff_notes/stores/comments.js +++ b/app/assets/javascripts/diff_notes/stores/comments.js @@ -1,14 +1,14 @@ -/* eslint-disable object-shorthand, func-names, camelcase, no-restricted-syntax, guard-for-in */ +/* eslint-disable camelcase, no-restricted-syntax, guard-for-in */ /* global DiscussionModel */ import Vue from 'vue'; window.CommentsStore = { state: {}, - get: function(discussionId, noteId) { + get(discussionId, noteId) { return this.state[discussionId].getNote(noteId); }, - createDiscussion: function(discussionId, canResolve) { + createDiscussion(discussionId, canResolve) { let discussion = this.state[discussionId]; if (!this.state[discussionId]) { discussion = new DiscussionModel(discussionId); @@ -21,18 +21,18 @@ window.CommentsStore = { return discussion; }, - create: function(noteObj) { + create(noteObj) { const discussion = this.createDiscussion(noteObj.discussionId); discussion.createNote(noteObj); }, - update: function(discussionId, noteId, resolved, resolved_by) { + update(discussionId, noteId, resolved, resolved_by) { const discussion = this.state[discussionId]; const note = discussion.getNote(noteId); note.resolved = resolved; note.resolved_by = resolved_by; }, - delete: function(discussionId, noteId) { + delete(discussionId, noteId) { const discussion = this.state[discussionId]; discussion.deleteNote(noteId); @@ -40,7 +40,7 @@ window.CommentsStore = { Vue.delete(this.state, discussionId); } }, - unresolvedDiscussionIds: function() { + unresolvedDiscussionIds() { const ids = []; for (const discussionId in this.state) { diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue index c82b4a7abc6..761fd1583ed 100644 --- a/app/assets/javascripts/diffs/components/commit_item.vue +++ b/app/assets/javascripts/diffs/components/commit_item.vue @@ -17,7 +17,7 @@ import initUserPopovers from '../../user_popovers'; * * This Component was cloned from a HAML view. For the time being they * coexist, but there is an issue to remove the duplication. - * https://gitlab.com/gitlab-org/gitlab-ce/issues/51613 + * https://gitlab.com/gitlab-org/gitlab-foss/issues/51613 * */ export default { diff --git a/app/assets/javascripts/diffs/components/commit_widget.vue b/app/assets/javascripts/diffs/components/commit_widget.vue index d45f91c7023..31ed003cc0f 100644 --- a/app/assets/javascripts/diffs/components/commit_widget.vue +++ b/app/assets/javascripts/diffs/components/commit_widget.vue @@ -11,7 +11,7 @@ import CommitItem from './commit_item.vue'; * * This Component was cloned from a HAML view. For the time being, * they coexist, but there is an issue to remove the duplication. - * https://gitlab.com/gitlab-org/gitlab-ce/issues/51613 + * https://gitlab.com/gitlab-org/gitlab-foss/issues/51613 * */ export default { diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue index d59b1136677..9a1e59ec045 100644 --- a/app/assets/javascripts/diffs/components/diff_content.vue +++ b/app/assets/javascripts/diffs/components/diff_content.vue @@ -45,7 +45,6 @@ export default { computed: { ...mapState({ projectPath: state => state.diffs.projectPath, - endpoint: state => state.diffs.endpoint, }), ...mapGetters('diffs', ['isInlineView', 'isParallelView']), ...mapGetters('diffs', ['getCommentFormForDiffFile']), diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue index 21244c14977..22bba21526c 100644 --- a/app/assets/javascripts/environments/components/environment_actions.vue +++ b/app/assets/javascripts/environments/components/environment_actions.vue @@ -40,7 +40,7 @@ export default { ), { jobName: action.name }, ); - // https://gitlab.com/gitlab-org/gitlab-ce/issues/52156 + // https://gitlab.com/gitlab-org/gitlab-foss/issues/52156 // eslint-disable-next-line no-alert if (!window.confirm(confirmationMessage)) { return; diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index 1d4a6e64f9d..c94039326aa 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -278,7 +278,7 @@ export default { */ isLastDeployment() { // name: 'last?' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives - // Vue i18n ESLint rules issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/63560 + // Vue i18n ESLint rules issue: https://gitlab.com/gitlab-org/gitlab-foss/issues/63560 // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings return this.model && this.model.last_deployment && this.model.last_deployment['last?']; }, diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js index d1f52b91d9e..fd335362e5b 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js @@ -474,7 +474,7 @@ export default class FilteredSearchManager { } }) .catch(() => { - // https://gitlab.com/gitlab-org/gitlab-ce/issues/30821 + // https://gitlab.com/gitlab-org/gitlab-foss/issues/30821 }); } diff --git a/app/assets/javascripts/image_diff/helpers/badge_helper.js b/app/assets/javascripts/image_diff/helpers/badge_helper.js index 000157efad0..7921650e8a0 100644 --- a/app/assets/javascripts/image_diff/helpers/badge_helper.js +++ b/app/assets/javascripts/image_diff/helpers/badge_helper.js @@ -1,3 +1,5 @@ +import { spriteIcon } from '~/lib/utils/common_utils'; + export function createImageBadge(noteId, { x, y }, classNames = []) { const buttonEl = document.createElement('button'); const classList = classNames.concat(['js-image-badge']); @@ -20,7 +22,7 @@ export function addImageBadge(containerEl, { coordinate, badgeText, noteId }) { export function addImageCommentBadge(containerEl, { coordinate, noteId }) { const buttonEl = createImageBadge(noteId, coordinate, ['image-comment-badge']); - buttonEl.innerHTML = gl.utils.spriteIcon('image-comment-dark'); + buttonEl.innerHTML = spriteIcon('image-comment-dark'); containerEl.appendChild(buttonEl); } diff --git a/app/assets/javascripts/image_diff/helpers/comment_indicator_helper.js b/app/assets/javascripts/image_diff/helpers/comment_indicator_helper.js index 7051a968dac..df3d90cff68 100644 --- a/app/assets/javascripts/image_diff/helpers/comment_indicator_helper.js +++ b/app/assets/javascripts/image_diff/helpers/comment_indicator_helper.js @@ -1,3 +1,5 @@ +import { spriteIcon } from '~/lib/utils/common_utils'; + export function addCommentIndicator(containerEl, { x, y }) { const buttonEl = document.createElement('button'); buttonEl.classList.add('btn-transparent'); @@ -6,7 +8,7 @@ export function addCommentIndicator(containerEl, { x, y }) { buttonEl.style.left = `${x}px`; buttonEl.style.top = `${y}px`; - buttonEl.innerHTML = gl.utils.spriteIcon('image-comment-dark'); + buttonEl.innerHTML = spriteIcon('image-comment-dark'); containerEl.appendChild(buttonEl); } diff --git a/app/assets/javascripts/image_diff/helpers/index.js b/app/assets/javascripts/image_diff/helpers/index.js index 4a100631003..feeb0e8fa16 100644 --- a/app/assets/javascripts/image_diff/helpers/index.js +++ b/app/assets/javascripts/image_diff/helpers/index.js @@ -21,5 +21,4 @@ export default { resizeCoordinatesToImageElement: utilsHelper.resizeCoordinatesToImageElement, generateBadgeFromDiscussionDOM: utilsHelper.generateBadgeFromDiscussionDOM, getTargetSelection: utilsHelper.getTargetSelection, - initImageDiff: utilsHelper.initImageDiff, }; diff --git a/app/assets/javascripts/image_diff/helpers/init_image_diff.js b/app/assets/javascripts/image_diff/helpers/init_image_diff.js new file mode 100644 index 00000000000..8eef930c372 --- /dev/null +++ b/app/assets/javascripts/image_diff/helpers/init_image_diff.js @@ -0,0 +1,27 @@ +import ImageDiff from '../image_diff'; +import ReplacedImageDiff from '../replaced_image_diff'; +import ImageFile from '../../commit/image_file'; + +function initImageDiff(fileEl, canCreateNote, renderCommentBadge) { + const options = { + canCreateNote, + renderCommentBadge, + }; + let diff; + + // ImageFile needs to be invoked before initImageDiff so that badges + // can mount to the correct location + new ImageFile(fileEl); // eslint-disable-line no-new + + if (fileEl.querySelector('.diff-file .js-single-image')) { + diff = new ImageDiff(fileEl, options); + diff.init(); + } else if (fileEl.querySelector('.diff-file .js-replaced-image')) { + diff = new ReplacedImageDiff(fileEl, options); + diff.init(); + } + + return diff; +} + +export default { initImageDiff }; diff --git a/app/assets/javascripts/image_diff/helpers/utils_helper.js b/app/assets/javascripts/image_diff/helpers/utils_helper.js index beec99e6934..4b383b42dff 100644 --- a/app/assets/javascripts/image_diff/helpers/utils_helper.js +++ b/app/assets/javascripts/image_diff/helpers/utils_helper.js @@ -1,7 +1,4 @@ import ImageBadge from '../image_badge'; -import ImageDiff from '../image_diff'; -import ReplacedImageDiff from '../replaced_image_diff'; -import ImageFile from '../../commit/image_file'; export function resizeCoordinatesToImageElement(imageEl, meta) { const { x, y, width, height } = meta; @@ -70,25 +67,3 @@ export function getTargetSelection(event) { }, }; } - -export function initImageDiff(fileEl, canCreateNote, renderCommentBadge) { - const options = { - canCreateNote, - renderCommentBadge, - }; - let diff; - - // ImageFile needs to be invoked before initImageDiff so that badges - // can mount to the correct location - new ImageFile(fileEl); // eslint-disable-line no-new - - if (fileEl.querySelector('.diff-file .js-single-image')) { - diff = new ImageDiff(fileEl, options); - diff.init(); - } else if (fileEl.querySelector('.diff-file .js-replaced-image')) { - diff = new ReplacedImageDiff(fileEl, options); - diff.init(); - } - - return diff; -} diff --git a/app/assets/javascripts/image_diff/init_discussion_tab.js b/app/assets/javascripts/image_diff/init_discussion_tab.js index dbe4c06a4e9..54ff2858206 100644 --- a/app/assets/javascripts/image_diff/init_discussion_tab.js +++ b/app/assets/javascripts/image_diff/init_discussion_tab.js @@ -1,4 +1,4 @@ -import imageDiffHelper from './helpers/index'; +import initImageDiffHelper from './helpers/init_image_diff'; export default () => { // Always pass can-create-note as false because a user @@ -8,6 +8,6 @@ export default () => { const diffFileEls = document.querySelectorAll('.timeline-content .diff-file.js-image-file'); [...diffFileEls].forEach(diffFileEl => - imageDiffHelper.initImageDiff(diffFileEl, canCreateNote, renderCommentBadge), + initImageDiffHelper.initImageDiff(diffFileEl, canCreateNote, renderCommentBadge), ); }; diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index 88975c2cc73..b8b3a4f44fd 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -102,10 +102,10 @@ export default { required: false, default: '', }, - issuableTemplates: { - type: Array, + issuableTemplateNamesPath: { + type: String, required: false, - default: () => [], + default: '', }, markdownPreviewPath: { type: String, @@ -156,9 +156,13 @@ export default { store, state: store.state, showForm: false, + templatesRequested: false, }; }, computed: { + issuableTemplates() { + return this.store.formState.issuableTemplates; + }, formState() { return this.store.formState; }, @@ -233,6 +237,7 @@ export default { } return undefined; }, + updateStoreState() { return this.service .getData() @@ -245,7 +250,7 @@ export default { }); }, - openForm() { + updateAndShowForm(templates = []) { if (!this.showForm) { this.showForm = true; this.store.setFormState({ @@ -254,9 +259,32 @@ export default { lock_version: this.state.lock_version, lockedWarningVisible: false, updateLoading: false, + issuableTemplates: templates, + }); + } + }, + + requestTemplatesAndShowForm() { + return this.service + .loadTemplates(this.issuableTemplateNamesPath) + .then(res => { + this.updateAndShowForm(res.data); + }) + .catch(() => { + createFlash(this.defaultErrorMessage); + this.updateAndShowForm(); }); + }, + + openForm() { + if (!this.templatesRequested) { + this.templatesRequested = true; + this.requestTemplatesAndShowForm(); + } else { + this.updateAndShowForm(this.issuableTemplates); } }, + closeForm() { this.showForm = false; }, diff --git a/app/assets/javascripts/issue_show/services/index.js b/app/assets/javascripts/issue_show/services/index.js index 3c8334bee50..b1deeaae0fc 100644 --- a/app/assets/javascripts/issue_show/services/index.js +++ b/app/assets/javascripts/issue_show/services/index.js @@ -17,4 +17,13 @@ export default class Service { updateIssuable(data) { return axios.put(this.endpoint, data); } + + // eslint-disable-next-line class-methods-use-this + loadTemplates(templateNamesEndpoint) { + if (!templateNamesEndpoint) { + return Promise.resolve([]); + } + + return axios.get(templateNamesEndpoint); + } } diff --git a/app/assets/javascripts/issue_show/stores/index.js b/app/assets/javascripts/issue_show/stores/index.js index 3c17e73ccec..d32747b5053 100644 --- a/app/assets/javascripts/issue_show/stores/index.js +++ b/app/assets/javascripts/issue_show/stores/index.js @@ -9,6 +9,7 @@ export default class Store { lockedWarningVisible: false, updateLoading: false, lock_version: 0, + issuableTemplates: [], }; } diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js index 8cc3bc8373f..b028e9564c9 100644 --- a/app/assets/javascripts/labels_select.js +++ b/app/assets/javascripts/labels_select.js @@ -1,4 +1,4 @@ -/* eslint-disable no-useless-return, func-names, no-var, no-underscore-dangle, prefer-arrow-callback, one-var, prefer-template, no-new, consistent-return, object-shorthand, no-shadow, no-param-reassign, vars-on-top, no-lonely-if, no-else-return, dot-notation, no-empty */ +/* eslint-disable no-useless-return, func-names, no-var, no-underscore-dangle, prefer-arrow-callback, one-var, prefer-template, no-new, consistent-return, no-shadow, no-param-reassign, vars-on-top, no-lonely-if, no-else-return, dot-notation, no-empty */ /* global Issuable */ /* global ListLabel */ @@ -197,8 +197,8 @@ export default class LabelsSelect { .catch(() => flash(__('Error saving label update.'))); }; $dropdown.glDropdown({ - showMenuAbove: showMenuAbove, - data: function(term, callback) { + showMenuAbove, + data(term, callback) { labelUrl = $dropdown.attr('data-labels'); axios .get(labelUrl) @@ -231,7 +231,7 @@ export default class LabelsSelect { }) .catch(() => flash(__('Error fetching labels.'))); }, - renderRow: function(label) { + renderRow(label) { var linkEl, listItemEl, colorEl, @@ -316,7 +316,7 @@ export default class LabelsSelect { selectable: true, filterable: true, selected: $dropdown.data('selected') || [], - toggleLabel: function(selected, el) { + toggleLabel(selected, el) { var $dropdownParent = $dropdown.parent(); var $dropdownInputField = $dropdownParent.find('.dropdown-input-field'); var isSelected = el !== null ? el.hasClass('is-active') : false; @@ -350,7 +350,7 @@ export default class LabelsSelect { } }, fieldName: $dropdown.data('fieldName'), - id: function(label) { + id(label) { if (label.id <= 0) return label.title; if ($dropdown.hasClass('js-issuable-form-dropdown')) { @@ -363,7 +363,7 @@ export default class LabelsSelect { return label.id; } }, - hidden: function() { + hidden() { var isIssueIndex, isMRIndex, page; page = $('body').attr('data-page'); isIssueIndex = page === 'projects:issues:index'; @@ -394,7 +394,7 @@ export default class LabelsSelect { }, multiSelect: $dropdown.hasClass('js-multiselect'), vue: $dropdown.hasClass('js-issue-board-sidebar'), - clicked: function(clickEvent) { + clicked(clickEvent) { const { $el, e, isMarking } = clickEvent; const label = clickEvent.selectedObj; @@ -478,7 +478,7 @@ export default class LabelsSelect { } } }, - opened: function() { + opened() { if ($dropdown.hasClass('js-issue-board-sidebar')) { const previousSelection = $dropdown.attr('data-selected'); this.selected = previousSelection ? previousSelection.split(',') : []; diff --git a/app/assets/javascripts/lazy_loader.js b/app/assets/javascripts/lazy_loader.js index 66f25b622e0..9e8edd05b88 100644 --- a/app/assets/javascripts/lazy_loader.js +++ b/app/assets/javascripts/lazy_loader.js @@ -92,7 +92,7 @@ export default class LazyLoader { onIntersection = entries => { entries.forEach(entry => { // We are using `intersectionRatio > 0` over `isIntersecting`, as some browsers did not ship the latter - // See: https://gitlab.com/gitlab-org/gitlab-ce/issues/54407 + // See: https://gitlab.com/gitlab-org/gitlab-foss/issues/54407 if (entry.intersectionRatio > 0) { this.intersectionObserver.unobserve(entry.target); this.lazyImages.push(entry.target); diff --git a/app/assets/javascripts/lib/utils/notify.js b/app/assets/javascripts/lib/utils/notify.js index e7f6255e5f1..3439db1e326 100644 --- a/app/assets/javascripts/lib/utils/notify.js +++ b/app/assets/javascripts/lib/utils/notify.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, consistent-return, prefer-arrow-callback, no-return-assign, object-shorthand */ +/* eslint-disable func-names, no-var, consistent-return, prefer-arrow-callback, no-return-assign */ function notificationGranted(message, opts, onclick) { var notification; @@ -21,8 +21,8 @@ function notifyPermissions() { function notifyMe(message, body, icon, onclick) { var opts; opts = { - body: body, - icon: icon, + body, + icon, }; // Let's check if the browser supports notifications /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ diff --git a/app/assets/javascripts/locale/sprintf.js b/app/assets/javascripts/locale/sprintf.js index 68b64a3a16a..a3557fbf3fb 100644 --- a/app/assets/javascripts/locale/sprintf.js +++ b/app/assets/javascripts/locale/sprintf.js @@ -9,7 +9,7 @@ import _ from 'underscore'; @returns {String} the text with parameters replaces (e.g. '5 users use us') @see https://ruby-doc.org/core-2.3.3/Kernel.html#method-i-sprintf - @see https://gitlab.com/gitlab-org/gitlab-ce/issues/37992 + @see https://gitlab.com/gitlab-org/gitlab-foss/issues/37992 */ export default (input, parameters, escapeParameters = true) => { let output = input; diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 0ddf40b0405..49be11d466d 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -37,6 +37,7 @@ import GlFieldErrors from './gl_field_errors'; import initUserPopovers from './user_popovers'; import { initUserTracking } from './tracking'; import { __ } from './locale'; +import initPrivacyPolicyUpdateCallout from './privacy_policy_update_callout'; import 'ee_else_ce/main_ee'; @@ -96,6 +97,7 @@ function deferredInitialisation() { initUsagePingConsent(); initUserPopovers(); initUserTracking(); + initPrivacyPolicyUpdateCallout(); if (document.querySelector('.search')) initSearchAutocomplete(); diff --git a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js index a62ebe23646..70b18d9728d 100644 --- a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js +++ b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js @@ -1,4 +1,4 @@ -/* eslint-disable no-useless-computed-key, object-shorthand, no-param-reassign */ +/* eslint-disable no-param-reassign */ /* global ace */ import Vue from 'vue'; @@ -42,7 +42,7 @@ import getModeByFileExtension from '~/lib/utils/ace_utils'; }, }, watch: { - ['file.showEditor'](val) { + 'file.showEditor': function showEditorWatcher(val) { this.resetEditorContent(); if (!val || this.fileLoaded || this.loading) { diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js index 88bc0940741..e7fcc183715 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js +++ b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js @@ -1,4 +1,4 @@ -/* eslint-disable object-shorthand, no-param-reassign, camelcase, no-nested-ternary, no-continue */ +/* eslint-disable no-param-reassign, camelcase, no-nested-ternary, no-continue */ import $ from 'jquery'; import Vue from 'vue'; @@ -31,7 +31,7 @@ import { s__ } from '~/locale'; hasError: false, isSubmitting: false, isParallel: diffViewType === VIEW_TYPES.PARALLEL, - diffViewType: diffViewType, + diffViewType, conflictsData: {}, }, @@ -188,7 +188,7 @@ import { s__ } from '~/locale'; getHeadHeaderLine(id) { return { - id: id, + id, richText: HEAD_HEADER_TEXT, buttonTitle: HEAD_BUTTON_TITLE, type: 'new', @@ -233,7 +233,7 @@ import { s__ } from '~/locale'; getOriginHeaderLine(id) { return { - id: id, + id, richText: ORIGIN_HEADER_TEXT, buttonTitle: ORIGIN_BUTTON_TITLE, type: 'old', diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index 9c0d55326ee..1738dbe439c 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -1,4 +1,4 @@ -/* eslint-disable one-var, object-shorthand, no-else-return, no-self-compare, consistent-return, no-param-reassign, no-shadow */ +/* eslint-disable one-var, no-else-return, no-self-compare, consistent-return, no-param-reassign, no-shadow */ /* global Issuable */ /* global ListMilestone */ @@ -65,7 +65,7 @@ export default class MilestoneSelect { milestoneLinkNoneTemplate = `<span class="no-value">${__('None')}</span>`; } return $dropdown.glDropdown({ - showMenuAbove: showMenuAbove, + showMenuAbove, data: (term, callback) => axios.get(milestonesUrl).then(({ data }) => { const extraOptions = []; @@ -126,7 +126,7 @@ export default class MilestoneSelect { return defaultLabel; } }, - defaultLabel: defaultLabel, + defaultLabel, fieldName: $dropdown.data('fieldName'), text: milestone => _.escape(milestone.title), id: milestone => { diff --git a/app/assets/javascripts/monitoring/components/charts/time_series.vue b/app/assets/javascripts/monitoring/components/charts/time_series.vue index 5f1d742d952..f3f3bf15295 100644 --- a/app/assets/javascripts/monitoring/components/charts/time_series.vue +++ b/app/assets/javascripts/monitoring/components/charts/time_series.vue @@ -1,6 +1,5 @@ <script> import { __ } from '~/locale'; -import { mapState } from 'vuex'; import { GlLink, GlButton } from '@gitlab/ui'; import { GlAreaChart, GlLineChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts'; import dateFormat from 'dateformat'; @@ -70,7 +69,6 @@ export default { }; }, computed: { - ...mapState('monitoringDashboard', ['exportMetricsToCsvEnabled']), chartData() { // Transforms & supplements query data to render appropriate labels & styles // Input: [{ queryAttributes1 }, { queryAttributes2 }] @@ -190,18 +188,6 @@ export default { yAxisLabel() { return `${this.graphData.y_label}`; }, - csvText() { - const chartData = this.chartData[0].data; - const header = `timestamp,${this.graphData.y_label}\r\n`; // eslint-disable-line @gitlab/i18n/no-non-i18n-strings - return chartData.reduce((csv, data) => { - const row = data.join(','); - return `${csv}${row}\r\n`; - }, header); - }, - downloadLink() { - const data = new Blob([this.csvText], { type: 'text/plain' }); - return window.URL.createObjectURL(data); - }, }, watch: { containerWidth: 'onResize', @@ -270,16 +256,6 @@ export default { <div class="prometheus-graph"> <div class="prometheus-graph-header"> <h5 class="prometheus-graph-title js-graph-title">{{ graphData.title }}</h5> - <gl-button - v-if="exportMetricsToCsvEnabled" - :href="downloadLink" - :title="__('Download CSV')" - :aria-label="__('Download CSV')" - style="margin-left: 200px;" - download="chart_metrics.csv" - > - {{ __('Download CSV') }} - </gl-button> <div class="prometheus-graph-widgets js-graph-widgets"> <slot></slot> </div> diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 7a5a3789bd6..12a4c83e053 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -262,7 +262,7 @@ export default { return window.URL.createObjectURL(data); }, // TODO: BEGIN, Duplicated code with panel_type until feature flag is removed - // Issue number: https://gitlab.com/gitlab-org/gitlab-ce/issues/63845 + // Issue number: https://gitlab.com/gitlab-org/gitlab-foss/issues/63845 getGraphAlerts(queries) { if (!this.allAlerts) return {}; const metricIdsForChart = queries.map(q => q.metricId); diff --git a/app/assets/javascripts/namespace_select.js b/app/assets/javascripts/namespace_select.js index 2ef081837e6..4ddbec71ba6 100644 --- a/app/assets/javascripts/namespace_select.js +++ b/app/assets/javascripts/namespace_select.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, object-shorthand, no-else-return, prefer-template, prefer-arrow-callback */ +/* eslint-disable func-names, no-else-return, prefer-template, prefer-arrow-callback */ import $ from 'jquery'; import Api from './api'; @@ -18,15 +18,15 @@ export default class NamespaceSelect { search: { fields: ['path'], }, - fieldName: fieldName, - toggleLabel: function(selected) { + fieldName, + toggleLabel(selected) { if (selected.id == null) { return selected.text; } else { return selected.kind + ': ' + selected.full_path; } }, - data: function(term, dataCallback) { + data(term, dataCallback) { return Api.namespaces(term, function(namespaces) { if (isFilter) { const anyNamespace = { @@ -39,7 +39,7 @@ export default class NamespaceSelect { return dataCallback(namespaces); }); }, - text: function(namespace) { + text(namespace) { if (namespace.id == null) { return namespace.text; } else { diff --git a/app/assets/javascripts/notes/components/discussion_actions.vue b/app/assets/javascripts/notes/components/discussion_actions.vue index e3be91a4966..6bbf2fa6ee4 100644 --- a/app/assets/javascripts/notes/components/discussion_actions.vue +++ b/app/assets/javascripts/notes/components/discussion_actions.vue @@ -36,10 +36,11 @@ export default { }, }, computed: { + resolvableNotes() { + return this.discussion.notes.filter(x => x.resolvable); + }, userCanResolveDiscussion() { - return this.discussion.notes.every( - note => note.current_user && note.current_user.can_resolve, - ); + return this.resolvableNotes.every(note => note.current_user && note.current_user.can_resolve); }, }, }; diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue index 9019f0542b6..fa8fc7d02e4 100644 --- a/app/assets/javascripts/notes/components/noteable_note.vue +++ b/app/assets/javascripts/notes/components/noteable_note.vue @@ -98,7 +98,7 @@ export default { // We need to do this to ensure we have the correct sentence order // when translating this as the sentence order may change from one // language to the next. See: - // https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/24427#note_133713771 + // https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24427#note_133713771 const { id, url } = this.commit; const commitLink = `<a class="commit-sha monospace" href="${escape(url)}">${truncateSha( id, diff --git a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_util.js b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_util.js index ec3919dd073..505ca938f40 100644 --- a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_util.js +++ b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_util.js @@ -1,8 +1,8 @@ -/* eslint-disable func-names, object-shorthand, no-var, one-var, camelcase, no-param-reassign, no-return-assign, prefer-arrow-callback, consistent-return, no-cond-assign, no-else-return */ +/* eslint-disable func-names, no-var, one-var, camelcase, no-param-reassign, no-return-assign, prefer-arrow-callback, consistent-return, no-cond-assign, no-else-return */ import _ from 'underscore'; export default { - parse_log: function(log) { + parse_log(log) { var by_author, by_email, data, entry, i, len, total, normalized_email; total = {}; by_author = {}; @@ -25,15 +25,15 @@ export default { total = _.toArray(total); by_author = _.toArray(by_author); return { - total: total, - by_author: by_author, + total, + by_author, }; }, - add_date: function(date, collection) { + add_date(date, collection) { collection[date] = {}; return (collection[date].date = date); }, - add_author: function(author, by_author, by_email) { + add_author(author, by_author, by_email) { var data, normalized_email; data = {}; data.author_name = author.author_name; @@ -43,36 +43,36 @@ export default { by_email[normalized_email] = data; return data; }, - store_data: function(entry, total, by_author) { + store_data(entry, total, by_author) { this.store_commits(total, by_author); this.store_additions(entry, total, by_author); return this.store_deletions(entry, total, by_author); }, - store_commits: function(total, by_author) { + store_commits(total, by_author) { this.add(total, 'commits', 1); return this.add(by_author, 'commits', 1); }, - add: function(collection, field, value) { + add(collection, field, value) { if (collection[field] == null) { collection[field] = 0; } return (collection[field] += value); }, - store_additions: function(entry, total, by_author) { + store_additions(entry, total, by_author) { if (entry.additions == null) { entry.additions = 0; } this.add(total, 'additions', entry.additions); return this.add(by_author, 'additions', entry.additions); }, - store_deletions: function(entry, total, by_author) { + store_deletions(entry, total, by_author) { if (entry.deletions == null) { entry.deletions = 0; } this.add(total, 'deletions', entry.deletions); return this.add(by_author, 'deletions', entry.deletions); }, - get_total_data: function(parsed_log, field) { + get_total_data(parsed_log, field) { var log, total_data; log = parsed_log.total; total_data = this.pick_field(log, field); @@ -80,7 +80,7 @@ export default { return d.date; }); }, - pick_field: function(log, field) { + pick_field(log, field) { var total_data; total_data = []; _.each(log, function(d) { @@ -88,7 +88,7 @@ export default { }); return total_data; }, - get_author_data: function(parsed_log, field, date_range) { + get_author_data(parsed_log, field, date_range) { var author_data, log; if (date_range == null) { date_range = null; @@ -111,7 +111,7 @@ export default { return d[field]; }).reverse(); }, - parse_log_entry: function(log_entry, field, date_range) { + parse_log_entry(log_entry, field, date_range) { var parsed_entry; parsed_entry = {}; @@ -138,7 +138,7 @@ export default { ); return parsed_entry; }, - in_range: function(date, date_range) { + in_range(date, date_range) { var ref; if (date_range === null || (date_range[0] <= (ref = new Date(date)) && ref <= date_range[1])) { return true; diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js index 33e9a8e9d56..b99408e3609 100644 --- a/app/assets/javascripts/pages/projects/project.js +++ b/app/assets/javascripts/pages/projects/project.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, no-return-assign, object-shorthand, vars-on-top */ +/* eslint-disable func-names, no-var, no-return-assign, vars-on-top */ import $ from 'jquery'; import Cookies from 'js-cookie'; @@ -123,7 +123,7 @@ export default class Project { filterByText: true, inputFieldName: $dropdown.data('inputFieldName'), fieldName, - renderRow: function(ref) { + renderRow(ref) { var li = refListItem.cloneNode(false); if (ref.header != null) { @@ -144,13 +144,13 @@ export default class Project { return li; }, - id: function(obj, $el) { + id(obj, $el) { return $el.attr('data-ref'); }, - toggleLabel: function(obj, $el) { + toggleLabel(obj, $el) { return $el.text().trim(); }, - clicked: function(options) { + clicked(options) { const { e } = options; e.preventDefault(); if ($(`input[name="${fieldName}"]`).length) { diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue index 27c1b639889..cfc72327ef7 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue @@ -2,35 +2,43 @@ import { GlLoadingIcon } from '@gitlab/ui'; import StageColumnComponent from './stage_column_component.vue'; import GraphMixin from '../../mixins/graph_component_mixin'; +import GraphWidthMixin from '~/pipelines/mixins/graph_width_mixin'; export default { components: { StageColumnComponent, GlLoadingIcon, }, - mixins: [GraphMixin], + mixins: [GraphMixin, GraphWidthMixin], }; </script> <template> <div class="build-content middle-block js-pipeline-graph"> <div class="pipeline-visualization pipeline-graph pipeline-tab-content"> - <div v-if="isLoading" class="m-auto"><gl-loading-icon :size="3" /></div> + <div + :style="{ + paddingLeft: `${graphLeftPadding}px`, + paddingRight: `${graphRightPadding}px`, + }" + > + <gl-loading-icon v-if="isLoading" class="m-auto" :size="3" /> - <ul v-if="!isLoading" class="stage-column-list"> - <stage-column-component - v-for="(stage, index) in graph" - :key="stage.name" - :class="{ - 'append-right-48': shouldAddRightMargin(index), - }" - :title="capitalizeStageName(stage.name)" - :groups="stage.groups" - :stage-connector-class="stageConnectorClass(index, stage)" - :is-first-column="isFirstColumn(index)" - :action="stage.status.action" - @refreshPipelineGraph="refreshPipelineGraph" - /> - </ul> + <ul v-if="!isLoading" class="stage-column-list"> + <stage-column-component + v-for="(stage, index) in graph" + :key="stage.name" + :class="{ + 'append-right-48': shouldAddRightMargin(index), + }" + :title="capitalizeStageName(stage.name)" + :groups="stage.groups" + :stage-connector-class="stageConnectorClass(index, stage)" + :is-first-column="isFirstColumn(index)" + :action="stage.status.action" + @refreshPipelineGraph="refreshPipelineGraph" + /> + </ul> + </div> </div> </div> </template> diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_actions.vue index 4b2d816c6a0..9764e32955c 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_actions.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_actions.vue @@ -37,7 +37,7 @@ export default { ), { jobName: action.name }, ); - // https://gitlab.com/gitlab-org/gitlab-ce/issues/52156 + // https://gitlab.com/gitlab-org/gitlab-foss/issues/52156 // eslint-disable-next-line no-alert if (!window.confirm(confirmationMessage)) { return; diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js index eaa11a84cb9..d27829db50c 100644 --- a/app/assets/javascripts/pipelines/constants.js +++ b/app/assets/javascripts/pipelines/constants.js @@ -1,2 +1,3 @@ export const CANCEL_REQUEST = 'CANCEL_REQUEST'; export const PIPELINES_TABLE = 'PIPELINES_TABLE'; +export const LAYOUT_CHANGE_DELAY = 300; diff --git a/app/assets/javascripts/pipelines/mixins/graph_width_mixin.js b/app/assets/javascripts/pipelines/mixins/graph_width_mixin.js new file mode 100644 index 00000000000..2dbaa5a5c9a --- /dev/null +++ b/app/assets/javascripts/pipelines/mixins/graph_width_mixin.js @@ -0,0 +1,50 @@ +import { debounceByAnimationFrame } from '~/lib/utils/common_utils'; +import { LAYOUT_CHANGE_DELAY } from '~/pipelines/constants'; + +export default { + debouncedResize: null, + sidebarMutationObserver: null, + data() { + return { + graphLeftPadding: 0, + graphRightPadding: 0, + }; + }, + beforeDestroy() { + window.removeEventListener('resize', this.$options.debouncedResize); + + if (this.$options.sidebarMutationObserver) { + this.$options.sidebarMutationObserver.disconnect(); + } + }, + created() { + this.$options.debouncedResize = debounceByAnimationFrame(this.setGraphPadding); + window.addEventListener('resize', this.$options.debouncedResize); + }, + mounted() { + this.setGraphPadding(); + + this.$options.sidebarMutationObserver = new MutationObserver(this.handleLayoutChange); + this.$options.sidebarMutationObserver.observe(document.querySelector('.layout-page'), { + attributes: true, + childList: false, + subtree: false, + }); + }, + methods: { + setGraphPadding() { + // only add padding to main graph (not inline upstream/downstream graphs) + if (this.type && this.type !== 'main') return; + + const container = document.querySelector('.js-pipeline-container'); + if (!container) return; + + this.graphLeftPadding = container.offsetLeft; + this.graphRightPadding = window.innerWidth - container.offsetLeft - container.offsetWidth; + }, + handleLayoutChange() { + // wait until animations finish, then recalculate padding + window.setTimeout(this.setGraphPadding, LAYOUT_CHANGE_DELAY); + }, + }, +}; diff --git a/app/assets/javascripts/privacy_policy_update_callout.js b/app/assets/javascripts/privacy_policy_update_callout.js index 126b1ee1132..97f41deb30f 100644 --- a/app/assets/javascripts/privacy_policy_update_callout.js +++ b/app/assets/javascripts/privacy_policy_update_callout.js @@ -1,7 +1,7 @@ import PersistentUserCallout from '~/persistent_user_callout'; function initPrivacyPolicyUpdateCallout() { - const callout = document.querySelector('.privacy-policy-update-64341'); + const callout = document.querySelector('.js-privacy-policy-update'); PersistentUserCallout.factory(callout); } diff --git a/app/assets/javascripts/profile/gl_crop.js b/app/assets/javascripts/profile/gl_crop.js index 6a07ccc7586..44bc2d9f5f8 100644 --- a/app/assets/javascripts/profile/gl_crop.js +++ b/app/assets/javascripts/profile/gl_crop.js @@ -1,4 +1,4 @@ -/* eslint-disable no-useless-escape, no-var, no-underscore-dangle, func-names, no-return-assign, object-shorthand, one-var, consistent-return, class-methods-use-this */ +/* eslint-disable no-useless-escape, no-var, no-underscore-dangle, func-names, no-return-assign, one-var, consistent-return, class-methods-use-this */ import $ from 'jquery'; import 'cropper'; @@ -100,7 +100,7 @@ import _ from 'underscore'; cropBoxMovable: false, cropBoxResizable: false, toggleDragModeOnDblclick: false, - built: function() { + built() { const $image = $(this); const container = $image.cropper('getContainerData'); const { cropBoxWidth, cropBoxHeight } = _this; diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js index dbe354a547b..88665ed2ab7 100644 --- a/app/assets/javascripts/project_select.js +++ b/app/assets/javascripts/project_select.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, object-shorthand, one-var, no-else-return */ +/* eslint-disable func-names, no-var, one-var, no-else-return */ import $ from 'jquery'; import Api from './api'; @@ -28,7 +28,7 @@ export default function projectSelect() { } $(select).select2({ - placeholder: placeholder, + placeholder, minimumInputLength: 0, query: (function(_this) { return function(query) { @@ -79,18 +79,18 @@ export default function projectSelect() { } }; })(this), - id: function(project) { + id(project) { if (simpleFilter) return project.id; return JSON.stringify({ name: project.name, url: project.web_url, }); }, - text: function(project) { + text(project) { return project.name_with_namespace || project.name; }, - initSelection: function(el, callback) { + initSelection(el, callback) { return Api.project(el.val()).then(({ data }) => callback(data)); }, diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js index f02c55c3d5b..2f37dcec197 100644 --- a/app/assets/javascripts/search_autocomplete.js +++ b/app/assets/javascripts/search_autocomplete.js @@ -1,4 +1,4 @@ -/* eslint-disable no-return-assign, one-var, no-var, consistent-return, object-shorthand, prefer-template, class-methods-use-this, no-lonely-if, vars-on-top */ +/* eslint-disable no-return-assign, one-var, no-var, consistent-return, prefer-template, class-methods-use-this, no-lonely-if, vars-on-top */ import $ from 'jquery'; import { escape, throttle } from 'underscore'; @@ -171,7 +171,7 @@ export class SearchAutocomplete { params: { project_id: this.projectId, project_ref: this.projectRef, - term: term, + term, }, }) .then(response => { diff --git a/app/assets/javascripts/single_file_diff.js b/app/assets/javascripts/single_file_diff.js index f2b9d75dd00..b70e384fae5 100644 --- a/app/assets/javascripts/single_file_diff.js +++ b/app/assets/javascripts/single_file_diff.js @@ -5,7 +5,7 @@ import { __ } from './locale'; import axios from './lib/utils/axios_utils'; import createFlash from './flash'; import FilesCommentButton from './files_comment_button'; -import imageDiffHelper from './image_diff/helpers/index'; +import initImageDiffHelper from './image_diff/helpers/init_image_diff'; import syntaxHighlight from './syntax_highlight'; const WRAPPER = '<div class="diff-content"></div>'; @@ -101,7 +101,7 @@ export default class SingleFileDiff { FilesCommentButton.init($file); const canCreateNote = $file.closest('.files').is('[data-can-create-note]'); - imageDiffHelper.initImageDiff($file[0], canCreateNote); + initImageDiffHelper.initImageDiff($file[0], canCreateNote); if (cb) cb(); }) diff --git a/app/assets/javascripts/tracking.js b/app/assets/javascripts/tracking.js index 03281b5ef49..1b4ca1d5741 100644 --- a/app/assets/javascripts/tracking.js +++ b/app/assets/javascripts/tracking.js @@ -10,12 +10,8 @@ const DEFAULT_SNOWPLOW_OPTIONS = { forceSecureTracker: true, eventMethod: 'post', contexts: { webPage: true }, - // Page tracking tracks a single event when the page loads. - pageTrackingEnabled: false, - // Activity tracking tracks when a user is still interacting with the page. - // Events like scrolling and mouse movements are used to determine if the - // user has the tab active and is still actively engaging. - activityTrackingEnabled: false, + formTracking: false, + linkClickTracking: false, }; const extractData = (el, opts = {}) => { @@ -96,6 +92,9 @@ export function initUserTracking() { const opts = Object.assign({}, DEFAULT_SNOWPLOW_OPTIONS, window.snowplowOptions); window.snowplow('newTracker', opts.namespace, opts.hostname, opts); - if (opts.activityTrackingEnabled) window.snowplow('enableActivityTracking', 30, 30); - if (opts.pageTrackingEnabled) window.snowplow('trackPageView'); // must be after enableActivityTracking + window.snowplow('enableActivityTracking', 30, 30); + window.snowplow('trackPageView'); // must be after enableActivityTracking + + if (opts.formTracking) window.snowplow('enableFormTracking'); + if (opts.linkClickTracking) window.snowplow('enableLinkClickTracking'); } diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index 4b3c42ae848..e78ca56be0e 100644 --- a/app/assets/javascripts/users_select.js +++ b/app/assets/javascripts/users_select.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, one-var, no-var, prefer-rest-params, vars-on-top, prefer-arrow-callback, consistent-return, object-shorthand, no-shadow, no-else-return, no-self-compare, prefer-template, no-unused-expressions, yoda, prefer-spread, camelcase, no-param-reassign */ +/* eslint-disable func-names, one-var, no-var, prefer-rest-params, vars-on-top, prefer-arrow-callback, consistent-return, no-shadow, no-else-return, no-self-compare, prefer-template, no-unused-expressions, yoda, prefer-spread, camelcase, no-param-reassign */ /* global Issuable */ /* global emitSidebarEvent */ @@ -248,8 +248,8 @@ function UsersSelect(currentUser, els, options = {}) { })}</span> <% } %>`, ); return $dropdown.glDropdown({ - showMenuAbove: showMenuAbove, - data: function(term, callback) { + showMenuAbove, + data(term, callback) { return _this.users( term, options, @@ -261,7 +261,7 @@ function UsersSelect(currentUser, els, options = {}) { }.bind(this), ); }, - processData: function(term, data, callback) { + processData(term, data, callback) { let users = data; // Only show assigned user list when there is no search term @@ -326,7 +326,7 @@ function UsersSelect(currentUser, els, options = {}) { } anyUser = { beforeDivider: true, - name: name, + name, id: null, }; users.unshift(anyUser); @@ -376,7 +376,7 @@ function UsersSelect(currentUser, els, options = {}) { }, selectable: true, fieldName: $dropdown.data('fieldName'), - toggleLabel: function(selected, el, glDropdown) { + toggleLabel(selected, el, glDropdown) { const inputValue = glDropdown.filterInput.val(); if (this.multiSelect && inputValue === '') { @@ -404,8 +404,8 @@ function UsersSelect(currentUser, els, options = {}) { return defaultLabel; } }, - defaultLabel: defaultLabel, - hidden: function() { + defaultLabel, + hidden() { if ($dropdown.hasClass('js-multiselect')) { emitSidebarEvent('sidebar.saveAssignees'); } @@ -422,7 +422,7 @@ function UsersSelect(currentUser, els, options = {}) { }, multiSelect: $dropdown.hasClass('js-multiselect'), inputMeta: $dropdown.data('inputMeta'), - clicked: function(options) { + clicked(options) { const { $el, e, isMarking } = options; const user = options.selectedObj; @@ -522,10 +522,10 @@ function UsersSelect(currentUser, els, options = {}) { $dropdown.dropdown('toggle'); } }, - id: function(user) { + id(user) { return user.id; }, - opened: function(e) { + opened(e) { const $el = $(e.currentTarget); const selected = getSelected(); if ($dropdown.hasClass('js-issue-board-sidebar') && selected.length === 0) { @@ -546,7 +546,7 @@ function UsersSelect(currentUser, els, options = {}) { } }, updateLabel: $dropdown.data('dropdownTitle'), - renderRow: function(user) { + renderRow(user) { var avatar, img, username; username = user.username ? '@' + user.username : ''; avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url; @@ -605,7 +605,7 @@ function UsersSelect(currentUser, els, options = {}) { placeholder: __('Search for a user'), multiple: $(select).hasClass('multiselect'), minimumInputLength: 0, - query: function(query) { + query(query) { return _this.users(query.term, options, function(users) { var anyUser, data, emailUser, index, len, name, nullUser, obj, ref; data = { @@ -638,7 +638,7 @@ function UsersSelect(currentUser, els, options = {}) { name = s__('UsersSelect|Any User'); } anyUser = { - name: name, + name, id: null, }; data.results.unshift(anyUser); @@ -661,24 +661,24 @@ function UsersSelect(currentUser, els, options = {}) { return query.callback(data); }); }, - initSelection: function() { + initSelection() { var args; args = 1 <= arguments.length ? [].slice.call(arguments, 0) : []; return _this.initSelection.apply(_this, args); }, - formatResult: function() { + formatResult() { var args; args = 1 <= arguments.length ? [].slice.call(arguments, 0) : []; return _this.formatResult.apply(_this, args); }, - formatSelection: function() { + formatSelection() { var args; args = 1 <= arguments.length ? [].slice.call(arguments, 0) : []; return _this.formatSelection.apply(_this, args); }, dropdownCssClass: 'ajax-users-dropdown', // we do not want to escape markup since we are displaying html in results - escapeMarkup: function(m) { + escapeMarkup(m) { return m; }, }); diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue index e294e1de976..2c113770d8b 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue @@ -88,7 +88,8 @@ export default { mergeButtonText() { if (this.isMergingImmediately) { return __('Merge in progress'); - } else if (this.isAutoMergeAvailable) { + } + if (this.isAutoMergeAvailable) { return this.autoMergeText; } @@ -306,7 +307,7 @@ export default { </template> <template v-else> <span class="bold js-resolve-mr-widget-items-message"> - {{ __('You can only merge once the items above are resolved') }} + {{ mergeDisabledText }} </span> </template> </div> diff --git a/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js index eef49e20159..40e6203599f 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js +++ b/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js @@ -1,5 +1,7 @@ import { __ } from '~/locale'; +export const MERGE_DISABLED_TEXT = __('You can only merge once the items above are resolved.'); + export default { computed: { isMergeButtonDisabled() { @@ -11,6 +13,9 @@ export default { this.mr.preventMerge, ); }, + mergeDisabledText() { + return MERGE_DISABLED_TEXT; + }, autoMergeText() { // MWPS is currently the only auto merge strategy available in CE return __('Merge when pipeline succeeds'); diff --git a/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js b/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js index f637a44bf2d..8a229d80954 100644 --- a/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js +++ b/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js @@ -37,7 +37,7 @@ export default class MRWidgetService { // two endpoints are requested in order to get MR info: // one which is etag-cached and invalidated and another one which is not cached // the idea is to move all the fields to etag-cached endpoint and then perform only one request - // https://gitlab.com/gitlab-org/gitlab-ce/issues/61559#note_188801390 + // https://gitlab.com/gitlab-org/gitlab-foss/issues/61559#note_188801390 const getData = axios.get(this.endpoints.mergeRequestWidgetPath); const getCachedData = axios.get(this.endpoints.mergeRequestCachedWidgetPath); diff --git a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue index b0962684430..0e0bb8735b4 100644 --- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue +++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue @@ -7,7 +7,7 @@ import CiIcon from './ci_icon.vue'; * * Receives status object containing: * status: { - * details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url + * details_path: "/gitlab-org/gitlab-foss/pipelines/8150156" // url * group:"running" // used for CSS class * icon: "icon_status_running" // used to render the icon * label:"running" // used for potential tooltip diff --git a/app/assets/javascripts/vue_shared/components/ci_icon.vue b/app/assets/javascripts/vue_shared/components/ci_icon.vue index 25f80219993..5d373e179b2 100644 --- a/app/assets/javascripts/vue_shared/components/ci_icon.vue +++ b/app/assets/javascripts/vue_shared/components/ci_icon.vue @@ -6,7 +6,7 @@ import Icon from '../../vue_shared/components/icon.vue'; * * Receives status object containing: * status: { - * details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url + * details_path: "/gitlab-org/gitlab-foss/pipelines/8150156" // url * group:"running" // used for CSS class * icon: "icon_status_running" // used to render the icon * label:"running" // used for potential tooltip diff --git a/app/assets/javascripts/vue_shared/components/project_selector/project_selector.vue b/app/assets/javascripts/vue_shared/components/project_selector/project_selector.vue index 596fd48f96a..7f0345c7ec0 100644 --- a/app/assets/javascripts/vue_shared/components/project_selector/project_selector.vue +++ b/app/assets/javascripts/vue_shared/components/project_selector/project_selector.vue @@ -1,6 +1,6 @@ <script> import _ from 'underscore'; -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlLoadingIcon, GlSearchBoxByType } from '@gitlab/ui'; import ProjectListItem from './project_list_item.vue'; const SEARCH_INPUT_TIMEOUT_MS = 500; @@ -9,6 +9,7 @@ export default { name: 'ProjectSelector', components: { GlLoadingIcon, + GlSearchBoxByType, ProjectListItem, }, props: { @@ -53,9 +54,6 @@ export default { isSelected(project) { return Boolean(_.findWhere(this.selectedProjects, { id: project.id })); }, - focusSearchInput() { - this.$refs.searchInput.focus(); - }, onInput: _.debounce(function debouncedOnInput() { this.$emit('searched', this.searchQuery); }, SEARCH_INPUT_TIMEOUT_MS), @@ -64,12 +62,11 @@ export default { </script> <template> <div> - <input - ref="searchInput" + <gl-search-box-by-type v-model="searchQuery" :placeholder="__('Search your projects')" type="search" - class="form-control mb-3 js-project-selector-input" + class="mb-3" autofocus @input="onInput" /> |