diff options
Diffstat (limited to 'app')
189 files changed, 2104 insertions, 2173 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js b/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js index 5d7a3bed301..0d7e8a5a3cb 100644 --- a/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js +++ b/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js @@ -1,4 +1,4 @@ -/* eslint-disable object-shorthand, no-unused-vars, no-use-before-define, max-len, no-restricted-syntax, guard-for-in, no-continue */ +/* eslint-disable object-shorthand, no-unused-vars, no-use-before-define, no-restricted-syntax, guard-for-in, no-continue */ import $ from 'jquery'; import _ from 'underscore'; diff --git a/app/assets/javascripts/boards/components/board.js b/app/assets/javascripts/boards/components/board.js index 9ad451fa375..75477ebb3b3 100644 --- a/app/assets/javascripts/boards/components/board.js +++ b/app/assets/javascripts/boards/components/board.js @@ -1,25 +1,20 @@ -/* eslint-disable comma-dangle */ - import Sortable from 'sortablejs'; import Vue from 'vue'; import { n__ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; import Tooltip from '~/vue_shared/directives/tooltip'; import AccessorUtilities from '../../lib/utils/accessor'; -import boardList from './board_list.vue'; import BoardBlankState from './board_blank_state.vue'; -import './board_delete'; - -const Store = gl.issueBoards.BoardsStore; - -window.gl = window.gl || {}; -window.gl.issueBoards = window.gl.issueBoards || {}; +import BoardDelete from './board_delete'; +import BoardList from './board_list.vue'; +import boardsStore from '../stores/boards_store'; +import { getBoardSortableDefaultOptions, sortableEnd } from '../mixins/sortable_default_options'; -gl.issueBoards.Board = Vue.extend({ +export default Vue.extend({ components: { - boardList, - 'board-delete': gl.issueBoards.BoardDelete, BoardBlankState, + BoardDelete, + BoardList, Icon, }, directives: { @@ -49,8 +44,8 @@ gl.issueBoards.Board = Vue.extend({ }, data () { return { - detailIssue: Store.detail, - filter: Store.filter, + detailIssue: boardsStore.detail, + filter: boardsStore.filter, }; }, computed: { @@ -72,20 +67,20 @@ gl.issueBoards.Board = Vue.extend({ } }, mounted () { - this.sortableOptions = gl.issueBoards.getBoardSortableDefaultOptions({ + this.sortableOptions = getBoardSortableDefaultOptions({ disabled: this.disabled, group: 'boards', draggable: '.is-draggable', handle: '.js-board-handle', onEnd: (e) => { - gl.issueBoards.onEnd(); + sortableEnd(); if (e.newIndex !== undefined && e.oldIndex !== e.newIndex) { const order = this.sortable.toArray(); - const list = Store.findList('id', parseInt(e.item.dataset.id, 10)); + const list = boardsStore.findList('id', parseInt(e.item.dataset.id, 10)); this.$nextTick(() => { - Store.moveList(list, order); + boardsStore.moveList(list, order); }); } } diff --git a/app/assets/javascripts/boards/components/board_blank_state.vue b/app/assets/javascripts/boards/components/board_blank_state.vue index cde22725a89..38aaec73d7d 100644 --- a/app/assets/javascripts/boards/components/board_blank_state.vue +++ b/app/assets/javascripts/boards/components/board_blank_state.vue @@ -2,8 +2,7 @@ /* global ListLabel */ import _ from 'underscore'; import Cookies from 'js-cookie'; - -const Store = gl.issueBoards.BoardsStore; +import boardsStore from '../stores/boards_store'; export default { data() { @@ -19,7 +18,7 @@ export default { this.clearBlankState(); this.predefinedLabels.forEach((label, i) => { - Store.addList({ + boardsStore.addList({ title: label.title, position: i, list_type: 'label', @@ -30,14 +29,14 @@ export default { }); }); - Store.state.lists = _.sortBy(Store.state.lists, 'position'); + boardsStore.state.lists = _.sortBy(boardsStore.state.lists, 'position'); // Save the labels gl.boardService.generateDefaultLists() .then(res => res.data) .then((data) => { data.forEach((listObj) => { - const list = Store.findList('title', listObj.title); + const list = boardsStore.findList('title', listObj.title); list.id = listObj.id; list.label.id = listObj.label.id; @@ -48,14 +47,14 @@ export default { }); }) .catch(() => { - Store.removeList(undefined, 'label'); + boardsStore.removeList(undefined, 'label'); Cookies.remove('issue_board_welcome_hidden', { path: '', }); - Store.addBlankState(); + boardsStore.addBlankState(); }); }, - clearBlankState: Store.removeBlankState.bind(Store), + clearBlankState: boardsStore.removeBlankState.bind(boardsStore), }, }; diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index 0398102ad02..843498f0d06 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -2,8 +2,7 @@ /* eslint-disable vue/require-default-prop */ import IssueCardInner from './issue_card_inner.vue'; import eventHub from '../eventhub'; - - const Store = gl.issueBoards.BoardsStore; + import boardsStore from '../stores/boards_store'; export default { name: 'BoardsIssueCard', @@ -42,7 +41,7 @@ data() { return { showDetail: false, - detailIssue: Store.detail, + detailIssue: boardsStore.detail, }; }, computed: { @@ -63,11 +62,11 @@ if (this.showDetail) { this.showDetail = false; - if (Store.detail.issue && Store.detail.issue.id === this.issue.id) { + if (boardsStore.detail.issue && boardsStore.detail.issue.id === this.issue.id) { eventHub.$emit('clearDetailIssue'); } else { eventHub.$emit('newDetailIssue', this.issue); - Store.detail.list = this.list; + boardsStore.detail.list = this.list; } } }, diff --git a/app/assets/javascripts/boards/components/board_delete.js b/app/assets/javascripts/boards/components/board_delete.js index c5945e8098d..a5f9d65e4d5 100644 --- a/app/assets/javascripts/boards/components/board_delete.js +++ b/app/assets/javascripts/boards/components/board_delete.js @@ -1,12 +1,7 @@ -/* eslint-disable comma-dangle, no-alert */ - import $ from 'jquery'; import Vue from 'vue'; -window.gl = window.gl || {}; -window.gl.issueBoards = window.gl.issueBoards || {}; - -gl.issueBoards.BoardDelete = Vue.extend({ +export default Vue.extend({ props: { list: { type: Object, @@ -14,12 +9,13 @@ gl.issueBoards.BoardDelete = Vue.extend({ }, }, methods: { - deleteBoard () { + deleteBoard() { $(this.$el).tooltip('hide'); + // eslint-disable-next-line no-alert if (window.confirm('Are you sure you want to delete this list?')) { this.list.destroy(); } - } - } + }, + }, }); diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index 7ddb22ad824..4dc56c670f0 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -3,8 +3,8 @@ import Sortable from 'sortablejs'; import boardNewIssue from './board_new_issue.vue'; import boardCard from './board_card.vue'; import eventHub from '../eventhub'; - -const Store = gl.issueBoards.BoardsStore; +import boardsStore from '../stores/boards_store'; +import { getBoardSortableDefaultOptions, sortableStart } from '../mixins/sortable_default_options'; export default { name: 'BoardList', @@ -46,7 +46,7 @@ export default { data() { return { scrollOffset: 250, - filters: Store.state.filters, + filters: boardsStore.state.filters, showCount: false, showIssueForm: false, }; @@ -61,13 +61,14 @@ export default { }, issues() { this.$nextTick(() => { - if (this.scrollHeight() <= this.listHeight() && - this.list.issuesSize > this.list.issues.length) { + if ( + this.scrollHeight() <= this.listHeight() && + this.list.issuesSize > this.list.issues.length + ) { this.list.page += 1; - this.list.getIssues(false) - .catch(() => { - // TODO: handle request error - }); + this.list.getIssues(false).catch(() => { + // TODO: handle request error + }); } if (this.scrollHeight() > Math.ceil(this.listHeight())) { @@ -83,7 +84,7 @@ export default { eventHub.$on(`scroll-board-list-${this.list.id}`, this.scrollToTop); }, mounted() { - const options = gl.issueBoards.getBoardSortableDefaultOptions({ + const options = getBoardSortableDefaultOptions({ scroll: true, disabled: this.disabled, filter: '.board-list-count, .is-disabled', @@ -108,7 +109,8 @@ export default { // So from there, we can get reference to actual container // and thus the container type to enable Copy or Move if (e.target) { - const containerEl = e.target.closest('.js-board-list') || e.target.querySelector('.js-board-list'); + const containerEl = + e.target.closest('.js-board-list') || e.target.querySelector('.js-board-list'); const toBoardType = containerEl.dataset.boardType; const cloneActions = { label: ['milestone', 'assignee'], @@ -120,8 +122,9 @@ export default { const fromBoardType = this.list.type; // For each list we check if the destination list is // a the list were we should clone the issue - const shouldClone = Object.entries(cloneActions).some(entry => ( - fromBoardType === entry[0] && entry[1].includes(toBoardType))); + const shouldClone = Object.entries(cloneActions).some( + entry => fromBoardType === entry[0] && entry[1].includes(toBoardType), + ); if (shouldClone) { return 'clone'; @@ -133,28 +136,36 @@ export default { }, revertClone: true, }, - onStart: (e) => { + onStart: e => { const card = this.$refs.issue[e.oldIndex]; card.showDetail = false; - Store.moving.list = card.list; - Store.moving.issue = Store.moving.list.findIssue(+e.item.dataset.issueId); + boardsStore.moving.list = card.list; + boardsStore.moving.issue = boardsStore.moving.list.findIssue(+e.item.dataset.issueId); - gl.issueBoards.onStart(); + sortableStart(); }, - onAdd: (e) => { - gl.issueBoards.BoardsStore - .moveIssueToList(Store.moving.list, this.list, Store.moving.issue, e.newIndex); + onAdd: e => { + boardsStore.moveIssueToList( + boardsStore.moving.list, + this.list, + boardsStore.moving.issue, + e.newIndex, + ); this.$nextTick(() => { e.item.remove(); }); }, - onUpdate: (e) => { - const sortedArray = this.sortable.toArray() - .filter(id => id !== '-1'); - gl.issueBoards.BoardsStore - .moveIssueInList(this.list, Store.moving.issue, e.oldIndex, e.newIndex, sortedArray); + onUpdate: e => { + const sortedArray = this.sortable.toArray().filter(id => id !== '-1'); + boardsStore.moveIssueInList( + this.list, + boardsStore.moving.issue, + e.oldIndex, + e.newIndex, + sortedArray, + ); }, onMove(e) { return !e.related.classList.contains('board-list-count'); @@ -192,16 +203,14 @@ export default { if (getIssues) { this.list.loadingMore = true; - getIssues - .then(loadingDone) - .catch(loadingDone); + getIssues.then(loadingDone).catch(loadingDone); } }, toggleForm() { this.showIssueForm = !this.showIssueForm; }, onScroll() { - if (!this.list.loadingMore && (this.scrollTop() > this.scrollHeight() - this.scrollOffset)) { + if (!this.list.loadingMore && this.scrollTop() > this.scrollHeight() - this.scrollOffset) { this.loadNextPage(); } }, diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue index f7ce5128964..030288a1c9d 100644 --- a/app/assets/javascripts/boards/components/board_new_issue.vue +++ b/app/assets/javascripts/boards/components/board_new_issue.vue @@ -4,8 +4,7 @@ import { Button } from '@gitlab-org/gitlab-ui'; import eventHub from '../eventhub'; import ProjectSelect from './project_select.vue'; import ListIssue from '../models/issue'; - -const Store = gl.issueBoards.BoardsStore; +import boardsStore from '../stores/boards_store'; export default { name: 'BoardNewIssue', @@ -68,8 +67,8 @@ export default { // Need this because our jQuery very kindly disables buttons on ALL form submissions $(this.$refs.submitButton).enable(); - Store.detail.issue = issue; - Store.detail.list = this.list; + boardsStore.detail.issue = issue; + boardsStore.detail.list = this.list; }) .catch(() => { // Need this because our jQuery very kindly disables buttons on ALL form submissions diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js index 109e60cbde2..62666954de0 100644 --- a/app/assets/javascripts/boards/components/board_sidebar.js +++ b/app/assets/javascripts/boards/components/board_sidebar.js @@ -1,4 +1,4 @@ -/* eslint-disable comma-dangle, no-new */ +/* eslint-disable no-new */ import $ from 'jquery'; import Vue from 'vue'; @@ -14,13 +14,9 @@ import IssuableContext from '../../issuable_context'; import LabelsSelect from '../../labels_select'; import Subscriptions from '../../sidebar/components/subscriptions/subscriptions.vue'; import MilestoneSelect from '../../milestone_select'; +import boardsStore from '../stores/boards_store'; -const Store = gl.issueBoards.BoardsStore; - -window.gl = window.gl || {}; -window.gl.issueBoards = window.gl.issueBoards || {}; - -gl.issueBoards.BoardSidebar = Vue.extend({ +export default Vue.extend({ components: { AssigneeTitle, Assignees, @@ -35,7 +31,7 @@ gl.issueBoards.BoardSidebar = Vue.extend({ }, data() { return { - detail: Store.detail, + detail: boardsStore.detail, issue: {}, list: {}, loadingAssignees: false, @@ -117,18 +113,18 @@ gl.issueBoards.BoardSidebar = Vue.extend({ this.saveAssignees(); }, removeAssignee (a) { - gl.issueBoards.BoardsStore.detail.issue.removeAssignee(a); + boardsStore.detail.issue.removeAssignee(a); }, addAssignee (a) { - gl.issueBoards.BoardsStore.detail.issue.addAssignee(a); + boardsStore.detail.issue.addAssignee(a); }, removeAllAssignees () { - gl.issueBoards.BoardsStore.detail.issue.removeAllAssignees(); + boardsStore.detail.issue.removeAllAssignees(); }, saveAssignees () { this.loadingAssignees = true; - gl.issueBoards.BoardsStore.detail.issue.update() + boardsStore.detail.issue.update() .then(() => { this.loadingAssignees = false; }) diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue index 8b5536200e1..28956c2f3c5 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.vue +++ b/app/assets/javascripts/boards/components/issue_card_inner.vue @@ -3,8 +3,7 @@ import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; import eventHub from '../eventhub'; import tooltip from '../../vue_shared/directives/tooltip'; - - const Store = gl.issueBoards.BoardsStore; + import boardsStore from '../stores/boards_store'; export default { components: { @@ -110,7 +109,7 @@ filterByLabel(label, e) { if (!this.updateFilters) return; - const filterPath = gl.issueBoards.BoardsStore.filter.path.split('&'); + const filterPath = boardsStore.filter.path.split('&'); const labelTitle = encodeURIComponent(label.title); const param = `label_name[]=${labelTitle}`; const labelIndex = filterPath.indexOf(param); @@ -122,9 +121,9 @@ filterPath.splice(labelIndex, 1); } - gl.issueBoards.BoardsStore.filter.path = filterPath.join('&'); + boardsStore.filter.path = filterPath.join('&'); - Store.updateFiltersUrl(); + boardsStore.updateFiltersUrl(); eventHub.$emit('updateTokens'); }, diff --git a/app/assets/javascripts/boards/components/modal/footer.vue b/app/assets/javascripts/boards/components/modal/footer.vue index d4affc8c3de..268ca6bca13 100644 --- a/app/assets/javascripts/boards/components/modal/footer.vue +++ b/app/assets/javascripts/boards/components/modal/footer.vue @@ -5,6 +5,7 @@ import ListsDropdown from './lists_dropdown.vue'; import { pluralize } from '../../../lib/utils/text_utility'; import ModalStore from '../../stores/modal_store'; import modalMixin from '../../mixins/modal_mixins'; +import boardsStore from '../../stores/boards_store'; export default { components: { @@ -14,7 +15,7 @@ export default { data() { return { modal: ModalStore.store, - state: gl.issueBoards.BoardsStore.state, + state: boardsStore.state, }; }, computed: { diff --git a/app/assets/javascripts/boards/components/modal/lists_dropdown.vue b/app/assets/javascripts/boards/components/modal/lists_dropdown.vue index 4f23e5db35c..4622fd28220 100644 --- a/app/assets/javascripts/boards/components/modal/lists_dropdown.vue +++ b/app/assets/javascripts/boards/components/modal/lists_dropdown.vue @@ -1,6 +1,7 @@ <script> import { Link } from '@gitlab-org/gitlab-ui'; import ModalStore from '../../stores/modal_store'; +import boardsStore from '../../stores/boards_store'; export default { components: { @@ -9,7 +10,7 @@ export default { data() { return { modal: ModalStore.store, - state: gl.issueBoards.BoardsStore.state, + state: boardsStore.state, }; }, computed: { diff --git a/app/assets/javascripts/boards/components/new_list_dropdown.js b/app/assets/javascripts/boards/components/new_list_dropdown.js index 448ab9ed135..2c2045f8901 100644 --- a/app/assets/javascripts/boards/components/new_list_dropdown.js +++ b/app/assets/javascripts/boards/components/new_list_dropdown.js @@ -4,16 +4,12 @@ import $ from 'jquery'; import axios from '~/lib/utils/axios_utils'; import _ from 'underscore'; import CreateLabelDropdown from '../../create_label'; - -window.gl = window.gl || {}; -window.gl.issueBoards = window.gl.issueBoards || {}; - -const Store = gl.issueBoards.BoardsStore; +import boardsStore from '../stores/boards_store'; $(document).off('created.label').on('created.label', (e, label) => { - Store.new({ + boardsStore.new({ title: label.title, - position: Store.state.lists.length - 2, + position: boardsStore.state.lists.length - 2, list_type: 'label', label: { id: label.id, @@ -23,7 +19,7 @@ $(document).off('created.label').on('created.label', (e, label) => { }); }); -gl.issueBoards.newListDropdownInit = () => { +export default function initNewListDropdown() { $('.js-new-board-list').each(function () { const $this = $(this); new CreateLabelDropdown($this.closest('.dropdown').find('.dropdown-new-label'), $this.data('namespacePath'), $this.data('projectPath')); @@ -36,7 +32,7 @@ gl.issueBoards.newListDropdownInit = () => { }); }, renderRow (label) { - const active = Store.findList('title', label.title); + const active = boardsStore.findList('title', label.title); const $li = $('<li />'); const $a = $('<a />', { class: (active ? `is-active js-board-list-${active.id}` : ''), @@ -62,10 +58,10 @@ gl.issueBoards.newListDropdownInit = () => { const label = options.selectedObj; e.preventDefault(); - if (!Store.findList('title', label.title)) { - Store.new({ + if (!boardsStore.findList('title', label.title)) { + boardsStore.new({ title: label.title, - position: Store.state.lists.length - 2, + position: boardsStore.state.lists.length - 2, list_type: 'label', label: { id: label.id, @@ -74,9 +70,9 @@ gl.issueBoards.newListDropdownInit = () => { }, }); - Store.state.lists = _.sortBy(Store.state.lists, 'position'); + boardsStore.state.lists = _.sortBy(boardsStore.state.lists, 'position'); } }, }); }); -}; +} diff --git a/app/assets/javascripts/boards/components/sidebar/remove_issue.vue b/app/assets/javascripts/boards/components/sidebar/remove_issue.vue index 90d4c710daf..b8f2e324d43 100644 --- a/app/assets/javascripts/boards/components/sidebar/remove_issue.vue +++ b/app/assets/javascripts/boards/components/sidebar/remove_issue.vue @@ -2,8 +2,7 @@ import Vue from 'vue'; import Flash from '../../../flash'; import { __ } from '../../../locale'; - - const Store = gl.issueBoards.BoardsStore; + import boardsStore from '../../stores/boards_store'; export default Vue.extend({ props: { @@ -49,7 +48,7 @@ list.removeIssue(issue); }); - Store.detail.issue = {}; + boardsStore.detail.issue = {}; }, /** * Build the default patch request. diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index 46d61ebbf24..acf41e5689e 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -1,5 +1,6 @@ import FilteredSearchContainer from '../filtered_search/container'; import FilteredSearchManager from '../filtered_search/filtered_search_manager'; +import boardsStore from './stores/boards_store'; export default class FilteredSearchBoards extends FilteredSearchManager { constructor(store, updateUrl = false, cantEdit = []) { @@ -23,7 +24,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager { this.store.path = path.substr(1); if (this.updateUrl) { - gl.issueBoards.BoardsStore.updateFiltersUrl(); + boardsStore.updateFiltersUrl(); } } diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index caa6ce84335..91861f2f9ee 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -14,24 +14,22 @@ import './models/issue'; import './models/list'; import './models/milestone'; import './models/project'; -import './stores/boards_store'; +import boardsStore from './stores/boards_store'; import ModalStore from './stores/modal_store'; import BoardService from './services/board_service'; import modalMixin from './mixins/modal_mixins'; -import './mixins/sortable_default_options'; import './filters/due_date_filters'; -import './components/board'; -import './components/board_sidebar'; -import './components/new_list_dropdown'; +import Board from './components/board'; +import BoardSidebar from './components/board_sidebar'; +import initNewListDropdown from './components/new_list_dropdown'; import BoardAddIssuesModal from './components/modal/index.vue'; import '~/vue_shared/vue_resource_interceptor'; import { NavigationType } from '~/lib/utils/common_utils'; +let issueBoardsApp; + export default () => { const $boardApp = document.getElementById('board-app'); - const Store = gl.issueBoards.BoardsStore; - - window.gl = window.gl || {}; // check for browser back and trigger a hard reload to circumvent browser caching. window.addEventListener('pageshow', (event) => { @@ -43,25 +41,21 @@ export default () => { } }); - if (gl.IssueBoardsApp) { - gl.IssueBoardsApp.$destroy(true); + if (issueBoardsApp) { + issueBoardsApp.$destroy(true); } - Store.create(); - - // hack to allow sidebar scripts like milestone_select manipulate the BoardsStore - gl.issueBoards.boardStoreIssueSet = (...args) => Vue.set(Store.detail.issue, ...args); - gl.issueBoards.boardStoreIssueDelete = (...args) => Vue.delete(Store.detail.issue, ...args); + boardsStore.create(); - gl.IssueBoardsApp = new Vue({ + issueBoardsApp = new Vue({ el: $boardApp, components: { - board: gl.issueBoards.Board, - 'board-sidebar': gl.issueBoards.BoardSidebar, + Board, + BoardSidebar, BoardAddIssuesModal, }, data: { - state: Store.state, + state: boardsStore.state, loading: true, boardsEndpoint: $boardApp.dataset.boardsEndpoint, listsEndpoint: $boardApp.dataset.listsEndpoint, @@ -70,7 +64,7 @@ export default () => { issueLinkBase: $boardApp.dataset.issueLinkBase, rootPath: $boardApp.dataset.rootPath, bulkUpdatePath: $boardApp.dataset.bulkUpdatePath, - detailIssue: Store.detail, + detailIssue: boardsStore.detail, defaultAvatar: $boardApp.dataset.defaultAvatar, }, computed: { @@ -85,7 +79,7 @@ export default () => { bulkUpdatePath: this.bulkUpdatePath, boardId: this.boardId, }); - Store.rootPath = this.boardsEndpoint; + boardsStore.rootPath = this.boardsEndpoint; eventHub.$on('updateTokens', this.updateTokens); eventHub.$on('newDetailIssue', this.updateDetailIssue); @@ -99,16 +93,16 @@ export default () => { sidebarEventHub.$off('toggleSubscription', this.toggleSubscription); }, mounted() { - this.filterManager = new FilteredSearchBoards(Store.filter, true, Store.cantEdit); + this.filterManager = new FilteredSearchBoards(boardsStore.filter, true, boardsStore.cantEdit); this.filterManager.setup(); - Store.disabled = this.disabled; + boardsStore.disabled = this.disabled; gl.boardService .all() .then(res => res.data) .then(data => { data.forEach(board => { - const list = Store.addList(board, this.defaultAvatar); + const list = boardsStore.addList(board, this.defaultAvatar); if (list.type === 'closed') { list.position = Infinity; @@ -119,7 +113,7 @@ export default () => { this.state.lists = _.sortBy(this.state.lists, 'position'); - Store.addBlankState(); + boardsStore.addBlankState(); this.loading = false; }) .catch(() => { @@ -148,13 +142,13 @@ export default () => { }); } - Store.detail.issue = newIssue; + boardsStore.detail.issue = newIssue; }, clearDetailIssue() { - Store.detail.issue = {}; + boardsStore.detail.issue = {}; }, toggleSubscription(id) { - const { issue } = Store.detail; + const { issue } = boardsStore.detail; if (issue.id === id && issue.toggleSubscriptionEndpoint) { issue.setFetchingState('subscriptions', true); BoardService.toggleIssueSubscription(issue.toggleSubscriptionEndpoint) @@ -173,26 +167,28 @@ export default () => { }, }); - gl.IssueBoardsSearch = new Vue({ + // eslint-disable-next-line no-new + new Vue({ el: document.getElementById('js-add-list'), data: { - filters: Store.state.filters, + filters: boardsStore.state.filters, }, mounted() { - gl.issueBoards.newListDropdownInit(); + initNewListDropdown(); }, }); const issueBoardsModal = document.getElementById('js-add-issues-btn'); if (issueBoardsModal) { - gl.IssueBoardsModalAddBtn = new Vue({ + // eslint-disable-next-line no-new + new Vue({ el: issueBoardsModal, mixins: [modalMixin], data() { return { modal: ModalStore.store, - store: Store.state, + store: boardsStore.state, canAdminList: this.$options.el.hasAttribute('data-can-admin-list'), }; }, diff --git a/app/assets/javascripts/boards/mixins/sortable_default_options.js b/app/assets/javascripts/boards/mixins/sortable_default_options.js index a8df45fc473..c9cde4effb9 100644 --- a/app/assets/javascripts/boards/mixins/sortable_default_options.js +++ b/app/assets/javascripts/boards/mixins/sortable_default_options.js @@ -3,32 +3,29 @@ import $ from 'jquery'; import sortableConfig from '../../sortable/sortable_config'; -window.gl = window.gl || {}; -window.gl.issueBoards = window.gl.issueBoards || {}; - -gl.issueBoards.onStart = () => { +export function sortableStart() { $('.has-tooltip').tooltip('hide') .tooltip('disable'); document.body.classList.add('is-dragging'); -}; +} -gl.issueBoards.onEnd = () => { +export function sortableEnd() { $('.has-tooltip').tooltip('enable'); document.body.classList.remove('is-dragging'); -}; +} -gl.issueBoards.touchEnabled = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch; +export function getBoardSortableDefaultOptions(obj) { + const touchEnabled = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch; -gl.issueBoards.getBoardSortableDefaultOptions = (obj) => { const defaultSortOptions = Object.assign({}, sortableConfig, { filter: '.board-delete, .btn', - delay: gl.issueBoards.touchEnabled ? 100 : 0, - scrollSensitivity: gl.issueBoards.touchEnabled ? 60 : 100, + delay: touchEnabled ? 100 : 0, + scrollSensitivity: touchEnabled ? 60 : 100, scrollSpeed: 20, - onStart: gl.issueBoards.onStart, - onEnd: gl.issueBoards.onEnd, + onStart: sortableStart, + onEnd: sortableEnd, }); Object.keys(obj).forEach((key) => { defaultSortOptions[key] = obj[key]; }); return defaultSortOptions; -}; +} diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js index c7cfb72067c..52d04389b88 100644 --- a/app/assets/javascripts/boards/models/issue.js +++ b/app/assets/javascripts/boards/models/issue.js @@ -1,4 +1,4 @@ -/* eslint-disable no-unused-vars, comma-dangle */ +/* eslint-disable no-unused-vars */ /* global ListLabel */ /* global ListMilestone */ /* global ListAssignee */ @@ -6,6 +6,7 @@ import Vue from 'vue'; import '~/vue_shared/models/label'; import IssueProject from './project'; +import boardsStore from '../stores/boards_store'; class ListIssue { constructor (obj, defaultAvatar) { @@ -86,7 +87,7 @@ class ListIssue { } getLists () { - return gl.issueBoards.BoardsStore.state.lists.filter(list => list.findIssue(this.id)); + return boardsStore.state.lists.filter(list => list.findIssue(this.id)); } updateData(newData) { diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index d416b76f0f4..3161f1da8c9 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -1,10 +1,11 @@ -/* eslint-disable no-underscore-dangle, class-methods-use-this, consistent-return, no-shadow, no-param-reassign, max-len */ +/* eslint-disable no-underscore-dangle, class-methods-use-this, consistent-return, no-shadow, no-param-reassign */ /* global ListIssue */ import { __ } from '~/locale'; import ListLabel from '~/vue_shared/models/label'; import ListAssignee from '~/vue_shared/models/assignee'; import { urlParamsToObject } from '~/lib/utils/common_utils'; +import boardsStore from '../stores/boards_store'; const PER_PAGE = 20; @@ -89,9 +90,9 @@ class List { } destroy() { - const index = gl.issueBoards.BoardsStore.state.lists.indexOf(this); - gl.issueBoards.BoardsStore.state.lists.splice(index, 1); - gl.issueBoards.BoardsStore.updateNewListDropdown(this.id); + const index = boardsStore.state.lists.indexOf(this); + boardsStore.state.lists.splice(index, 1); + boardsStore.updateNewListDropdown(this.id); gl.boardService.destroyList(this.id).catch(() => { // TODO: handle request error @@ -116,7 +117,7 @@ class List { getIssues(emptyIssues = true) { const data = { - ...urlParamsToObject(gl.issueBoards.BoardsStore.filter.path), + ...urlParamsToObject(boardsStore.filter.path), page: this.page, }; diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index 957114cf420..471955747fd 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -1,15 +1,13 @@ -/* eslint-disable comma-dangle, no-shadow */ +/* eslint-disable no-shadow */ /* global List */ import $ from 'jquery'; import _ from 'underscore'; +import Vue from 'vue'; import Cookies from 'js-cookie'; import { getUrlParamsArray } from '~/lib/utils/common_utils'; -window.gl = window.gl || {}; -window.gl.issueBoards = window.gl.issueBoards || {}; - -gl.issueBoards.BoardsStore = { +const boardsStore = { disabled: false, filter: { path: '', @@ -167,3 +165,16 @@ gl.issueBoards.BoardsStore = { window.history.pushState(null, null, `?${this.filter.path}`); } }; + +// hacks added in order to allow milestone_select to function properly +// TODO: remove these + +export function boardStoreIssueSet(...args) { + Vue.set(boardsStore.detail.issue, ...args); +} + +export function boardStoreIssueDelete(...args) { + Vue.delete(boardsStore.detail.issue, ...args); +} + +export default boardsStore; diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index a1069985178..6e7b5eb5526 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -1,6 +1,6 @@ <script> import _ from 'underscore'; -import helmInstallIllustration from '@gitlab-org/gitlab-svgs/illustrations/kubernetes-installation.svg'; +import helmInstallIllustration from '@gitlab-org/gitlab-svgs/dist/illustrations/kubernetes-installation.svg'; import elasticsearchLogo from 'images/cluster_app_logos/elasticsearch.png'; import gitlabLogo from 'images/cluster_app_logos/gitlab.png'; import helmLogo from 'images/cluster_app_logos/helm.png'; diff --git a/app/assets/javascripts/commit/image_file.js b/app/assets/javascripts/commit/image_file.js index 410580b4c25..30d9b656fec 100644 --- a/app/assets/javascripts/commit/image_file.js +++ b/app/assets/javascripts/commit/image_file.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, wrap-iife, no-var, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, quotes, one-var, one-var-declaration-per-line, no-unused-vars, no-return-assign, comma-dangle, quote-props, no-unused-expressions, no-sequences, max-len */ +/* eslint-disable func-names, no-var, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, one-var, no-unused-vars, no-return-assign, no-unused-expressions, no-sequences */ import $ from 'jquery'; diff --git a/app/assets/javascripts/compare_autocomplete.js b/app/assets/javascripts/compare_autocomplete.js index a252036d657..852d71f4e84 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, one-var-declaration-per-line, object-shorthand, no-else-return, max-len */ +/* eslint-disable func-names, one-var, no-var, object-shorthand, no-else-return */ import $ from 'jquery'; import { __ } from './locale'; 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 ed24d1775f4..87621761500 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 comma-dangle, object-shorthand, func-names, no-else-return, quotes, no-lonely-if, max-len */ +/* eslint-disable object-shorthand, func-names, no-else-return, no-lonely-if */ /* global CommentsStore */ import $ from 'jquery'; 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 2b893e35b6d..2b78bb58735 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 comma-dangle, object-shorthand, func-names, no-else-return, guard-for-in, no-restricted-syntax, no-lonely-if, no-continue, brace-style, max-len, quotes */ +/* eslint-disable object-shorthand, func-names, no-else-return, guard-for-in, no-restricted-syntax, no-lonely-if, no-continue */ /* global CommentsStore */ import $ from 'jquery'; diff --git a/app/assets/javascripts/diff_notes/components/resolve_count.js b/app/assets/javascripts/diff_notes/components/resolve_count.js index e2683e09f40..eb539c6b348 100644 --- a/app/assets/javascripts/diff_notes/components/resolve_count.js +++ b/app/assets/javascripts/diff_notes/components/resolve_count.js @@ -1,4 +1,4 @@ -/* eslint-disable comma-dangle, object-shorthand, func-names */ +/* eslint-disable object-shorthand, func-names */ /* global CommentsStore */ import Vue from 'vue'; diff --git a/app/assets/javascripts/diff_notes/mixins/discussion.js b/app/assets/javascripts/diff_notes/mixins/discussion.js index ef35b589e58..7589f9dd6e0 100644 --- a/app/assets/javascripts/diff_notes/mixins/discussion.js +++ b/app/assets/javascripts/diff_notes/mixins/discussion.js @@ -1,4 +1,4 @@ -/* eslint-disable object-shorthand, func-names, guard-for-in, no-restricted-syntax, comma-dangle, */ +/* eslint-disable object-shorthand, func-names, guard-for-in, no-restricted-syntax, */ const DiscussionMixins = { computed: { diff --git a/app/assets/javascripts/diff_notes/stores/comments.js b/app/assets/javascripts/diff_notes/stores/comments.js index d7da7d974f3..d012cd02d10 100644 --- a/app/assets/javascripts/diff_notes/stores/comments.js +++ b/app/assets/javascripts/diff_notes/stores/comments.js @@ -1,4 +1,4 @@ -/* eslint-disable object-shorthand, func-names, camelcase, no-restricted-syntax, guard-for-in, comma-dangle, max-len */ +/* eslint-disable object-shorthand, func-names, camelcase, no-restricted-syntax, guard-for-in */ /* global DiscussionModel */ import Vue from 'vue'; diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index 15b37243030..dcf1057eb84 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -20,6 +20,11 @@ export default { Tooltip, }, props: { + discussionPath: { + type: String, + required: false, + default: '', + }, diffFile: { type: Object, required: true, @@ -65,8 +70,7 @@ export default { if (this.diffFile.submodule) { return this.diffFile.submoduleTreeUrl || this.diffFile.submoduleLink; } - - return `#${this.diffFile.fileHash}`; + return this.discussionPath; }, filePath() { if (this.diffFile.submodule) { @@ -152,7 +156,7 @@ export default { v-once ref="titleWrapper" :href="titleLink" - class="append-right-4" + class="append-right-4 js-title-wrapper" > <file-icon :file-name="filePath" diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js index ae8930c8968..1c5c35071de 100644 --- a/app/assets/javascripts/diffs/store/modules/diff_state.js +++ b/app/assets/javascripts/diffs/store/modules/diff_state.js @@ -1,5 +1,6 @@ import Cookies from 'js-cookie'; import { getParameterValues } from '~/lib/utils/url_utility'; +import bp from '~/breakpoints'; import { INLINE_DIFF_VIEW_TYPE, DIFF_VIEW_COOKIE_NAME, MR_TREE_SHOW_KEY } from '../../constants'; const viewTypeFromQueryString = getParameterValues('view')[0]; @@ -20,6 +21,7 @@ export default () => ({ diffViewType: viewTypeFromQueryString || viewTypeFromCookie || defaultViewType, tree: [], treeEntries: {}, - showTreeList: storedTreeShow === null ? true : storedTreeShow === 'true', + showTreeList: + storedTreeShow === null ? bp.getBreakpointSize() !== 'xs' : storedTreeShow === 'true', currentDiffFileId: '', }); diff --git a/app/assets/javascripts/due_date_select.js b/app/assets/javascripts/due_date_select.js index 8abd8bc581a..c7b5a35cc14 100644 --- a/app/assets/javascripts/due_date_select.js +++ b/app/assets/javascripts/due_date_select.js @@ -5,6 +5,7 @@ import { __ } from '~/locale'; import axios from './lib/utils/axios_utils'; import { timeFor } from './lib/utils/datetime_utility'; import { parsePikadayDate, pikadayToString } from './lib/utils/datefix'; +import boardsStore from './boards/stores/boards_store'; class DueDateSelect { constructor({ $dropdown, $loading } = {}) { @@ -58,7 +59,7 @@ class DueDateSelect { $dueDateInput.val(calendar.toString(dateText)); if (this.$dropdown.hasClass('js-issue-boards-due-date')) { - gl.issueBoards.BoardsStore.detail.issue.dueDate = $dueDateInput.val(); + boardsStore.detail.issue.dueDate = $dueDateInput.val(); this.updateIssueBoardIssue(); } else { this.saveDueDate(true); @@ -79,7 +80,7 @@ class DueDateSelect { calendar.setDate(null); if (this.$dropdown.hasClass('js-issue-boards-due-date')) { - gl.issueBoards.BoardsStore.detail.issue.dueDate = ''; + boardsStore.detail.issue.dueDate = ''; this.updateIssueBoardIssue(); } else { $(`input[name='${this.fieldName}']`).val(''); @@ -123,7 +124,7 @@ class DueDateSelect { this.$loading.fadeOut(); }; - gl.issueBoards.BoardsStore.detail.issue + boardsStore.detail.issue .update(this.$dropdown.attr('data-issue-update')) .then(fadeOutLoader) .catch(fadeOutLoader); diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index a1d8e531940..ad5d16874f3 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -482,6 +482,7 @@ export default { v-if="!model.isFolder" class="environment-name table-mobile-content"> <a + class="qa-environment-link" :href="environmentPath" > {{ model.name }} diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index c3959ef3e9e..a8ac2f510a4 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-underscore-dangle, no-var, one-var, one-var-declaration-per-line, max-len, vars-on-top, wrap-iife, no-unused-vars, no-shadow, no-cond-assign, prefer-arrow-callback, no-return-assign, no-else-return, camelcase, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, prefer-template, no-param-reassign, no-loop-func */ +/* eslint-disable func-names, no-underscore-dangle, no-var, one-var, vars-on-top, no-unused-vars, no-shadow, no-cond-assign, prefer-arrow-callback, no-return-assign, no-else-return, camelcase, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, prefer-template, no-param-reassign, no-loop-func */ /* global fuzzaldrinPlus */ import $ from 'jquery'; diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue index ee8eb206980..802827fce76 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue @@ -117,7 +117,7 @@ export default { <button :disabled="!hasChanges" type="button" - class="btn btn-primary btn-sm btn-block" + class="btn btn-primary btn-sm btn-block qa-begin-commit-button" @click="toggleIsSmall" > {{ __('Commit…') }} @@ -147,7 +147,7 @@ export default { <loading-button :loading="submitCommitLoading" :label="commitButtonText" - container-class="btn btn-success btn-sm float-left" + container-class="btn btn-success btn-sm float-left qa-commit-button" @click="commitChanges" /> <button diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue index d376a004e84..699fa7dc937 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue @@ -38,14 +38,18 @@ export default { return this.modifiedFilesLength ? 'multi-file-modified' : ''; }, additionsTooltip() { - return sprintf(n__('1 %{type} addition', '%{count} %{type} additions', this.addedFilesLength), { - type: this.title.toLowerCase(), - count: this.addedFilesLength, - }); + return sprintf( + n__('1 %{type} addition', '%{count} %{type} additions', this.addedFilesLength), + { + type: this.title.toLowerCase(), + count: this.addedFilesLength, + }, + ); }, modifiedTooltip() { return sprintf( - n__('1 %{type} modification', '%{count} %{type} modifications', this.modifiedFilesLength), { + n__('1 %{type} modification', '%{count} %{type} modifications', this.modifiedFilesLength), + { type: this.title.toLowerCase(), count: this.modifiedFilesLength, }, diff --git a/app/assets/javascripts/ide/components/commit_sidebar/stage_button.vue b/app/assets/javascripts/ide/components/commit_sidebar/stage_button.vue index 8a1836a5c92..adf4b479c97 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/stage_button.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/stage_button.vue @@ -25,10 +25,7 @@ export default { return `discard-file-${this.path}`; }, modalTitle() { - return sprintf( - __('Discard changes to %{path}?'), - { path: this.path }, - ); + return sprintf(__('Discard changes to %{path}?'), { path: this.path }); }, }, methods: { diff --git a/app/assets/javascripts/ide/components/file_templates/bar.vue b/app/assets/javascripts/ide/components/file_templates/bar.vue index 23be5f45f16..3587626c580 100644 --- a/app/assets/javascripts/ide/components/file_templates/bar.vue +++ b/app/assets/javascripts/ide/components/file_templates/bar.vue @@ -47,7 +47,7 @@ export default { </script> <template> - <div class="d-flex align-items-center ide-file-templates"> + <div class="d-flex align-items-center ide-file-templates qa-file-templates-bar"> <strong class="append-right-default"> {{ __('File templates') }} </strong> @@ -63,7 +63,7 @@ export default { :is-async-data="true" :searchable="true" :title="__('File templates')" - class="mr-2" + class="mr-2 qa-file-template-dropdown" @click="selectTemplate" /> <transition name="fade"> diff --git a/app/assets/javascripts/ide/components/file_templates/dropdown.vue b/app/assets/javascripts/ide/components/file_templates/dropdown.vue index ef1f6de3a86..94222c08e91 100644 --- a/app/assets/javascripts/ide/components/file_templates/dropdown.vue +++ b/app/assets/javascripts/ide/components/file_templates/dropdown.vue @@ -92,7 +92,7 @@ export default { v-model="search" :placeholder="__('Filter...')" type="search" - class="dropdown-input-field" + class="dropdown-input-field qa-dropdown-filter-input" /> <i aria-hidden="true" diff --git a/app/assets/javascripts/ide/components/ide_side_bar.vue b/app/assets/javascripts/ide/components/ide_side_bar.vue index f99ff6d6da8..dc84ee12f1e 100644 --- a/app/assets/javascripts/ide/components/ide_side_bar.vue +++ b/app/assets/javascripts/ide/components/ide_side_bar.vue @@ -24,13 +24,7 @@ export default { IdeProjectHeader, }, computed: { - ...mapState([ - 'loading', - 'currentActivityView', - 'changedFiles', - 'stagedFiles', - 'lastCommitMsg', - ]), + ...mapState(['loading', 'currentActivityView', 'changedFiles', 'stagedFiles', 'lastCommitMsg']), ...mapGetters(['currentProject', 'someUncommitedChanges']), showSuccessMessage() { return ( diff --git a/app/assets/javascripts/ide/components/ide_tree.vue b/app/assets/javascripts/ide/components/ide_tree.vue index 39d46a91731..9f9e638f1aa 100644 --- a/app/assets/javascripts/ide/components/ide_tree.vue +++ b/app/assets/javascripts/ide/components/ide_tree.vue @@ -45,7 +45,7 @@ export default { <new-entry-button :label="__('New file')" :show-label="false" - class="d-flex border-0 p-0 mr-3" + class="d-flex border-0 p-0 mr-3 qa-new-file" icon="doc-new" @click="openNewEntryModal({ type: 'blob' })" /> diff --git a/app/assets/javascripts/ide/components/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue index cfe25084b42..e88f01fb4f4 100644 --- a/app/assets/javascripts/ide/components/ide_tree_list.vue +++ b/app/assets/javascripts/ide/components/ide_tree_list.vue @@ -43,7 +43,7 @@ export default { <template> <div - class="ide-file-list" + class="ide-file-list qa-file-list" > <template v-if="showLoading"> <div diff --git a/app/assets/javascripts/ide/components/merge_requests/list.vue b/app/assets/javascripts/ide/components/merge_requests/list.vue index c8343e77860..f5e42e87f1b 100644 --- a/app/assets/javascripts/ide/components/merge_requests/list.vue +++ b/app/assets/javascripts/ide/components/merge_requests/list.vue @@ -37,14 +37,10 @@ export default { return this.hasSearchFocus && !this.search && !this.currentSearchType; }, type() { - return this.currentSearchType - ? this.currentSearchType.type - : ''; + return this.currentSearchType ? this.currentSearchType.type : ''; }, searchTokens() { - return this.currentSearchType - ? [this.currentSearchType] - : []; + return this.currentSearchType ? [this.currentSearchType] : []; }, }, watch: { diff --git a/app/assets/javascripts/ide/components/nav_dropdown_button.vue b/app/assets/javascripts/ide/components/nav_dropdown_button.vue index 7f98769d484..6cee4e9a8f0 100644 --- a/app/assets/javascripts/ide/components/nav_dropdown_button.vue +++ b/app/assets/javascripts/ide/components/nav_dropdown_button.vue @@ -13,9 +13,7 @@ export default { computed: { ...mapState(['currentBranchId', 'currentMergeRequestId']), mergeRequestLabel() { - return this.currentMergeRequestId - ? `!${this.currentMergeRequestId}` - : EMPTY_LABEL; + return this.currentMergeRequestId ? `!${this.currentMergeRequestId}` : EMPTY_LABEL; }, branchLabel() { return this.currentBranchId || EMPTY_LABEL; diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue index bcd53ac1ba2..f0a04011a3e 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue @@ -110,12 +110,12 @@ export default { ref="fieldName" v-model="entryName" type="text" - class="form-control" + class="form-control qa-full-file-path" placeholder="/dir/file_name" /> <ul v-if="isCreatingNew" - class="prepend-top-default list-inline" + class="prepend-top-default list-inline qa-template-list" > <li v-for="(template, index) in templateTypes" diff --git a/app/assets/javascripts/ide/components/panes/right.vue b/app/assets/javascripts/ide/components/panes/right.vue index bd07f372177..10aa96dffaf 100644 --- a/app/assets/javascripts/ide/components/panes/right.vue +++ b/app/assets/javascripts/ide/components/panes/right.vue @@ -43,34 +43,25 @@ export default { { show: this.currentMergeRequestId, title: __('Merge Request'), - views: [ - rightSidebarViews.mergeRequestInfo, - ], + views: [rightSidebarViews.mergeRequestInfo], icon: 'text-description', }, { show: true, title: __('Pipelines'), - views: [ - rightSidebarViews.pipelines, - rightSidebarViews.jobsDetail, - ], + views: [rightSidebarViews.pipelines, rightSidebarViews.jobsDetail], icon: 'rocket', }, { show: this.showLivePreview, title: __('Live preview'), - views: [ - rightSidebarViews.clientSidePreview, - ], + views: [rightSidebarViews.clientSidePreview], icon: 'live-preview', }, ]; }, tabs() { - return this.defaultTabs - .concat(this.extensionTabs) - .filter(tab => tab.show); + return this.defaultTabs.concat(this.extensionTabs).filter(tab => tab.show); }, tabViews() { return _.flatten(this.tabs.map(tab => tab.views)); diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index b2599128213..7b0f717962e 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -25,12 +25,7 @@ export default { ...mapState('rightPane', { rightPaneIsOpen: 'isOpen', }), - ...mapState([ - 'rightPanelCollapsed', - 'viewer', - 'panelResizing', - 'currentActivityView', - ]), + ...mapState(['rightPanelCollapsed', 'viewer', 'panelResizing', 'currentActivityView']), ...mapGetters([ 'currentMergeRequest', 'getStagedFile', diff --git a/app/assets/javascripts/ide/components/shared/tokened_input.vue b/app/assets/javascripts/ide/components/shared/tokened_input.vue index a7a12f6785d..30010957a16 100644 --- a/app/assets/javascripts/ide/components/shared/tokened_input.vue +++ b/app/assets/javascripts/ide/components/shared/tokened_input.vue @@ -30,9 +30,7 @@ export default { }, computed: { placeholderText() { - return this.tokens.length - ? '' - : this.placeholder; + return this.tokens.length ? '' : this.placeholder; }, }, watch: { diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js index c0550116633..7a5a227db30 100644 --- a/app/assets/javascripts/ide/index.js +++ b/app/assets/javascripts/ide/index.js @@ -21,10 +21,7 @@ Vue.use(Translate); export function initIde(el, options = {}) { if (!el) return null; - const { - extraInitialData = () => ({}), - rootComponent = ide, - } = options; + const { extraInitialData = () => ({}), rootComponent = ide } = options; return new Vue({ el, diff --git a/app/assets/javascripts/ide/lib/diff/diff.js b/app/assets/javascripts/ide/lib/diff/diff.js index 0e37f5c4704..9b7ed68b893 100644 --- a/app/assets/javascripts/ide/lib/diff/diff.js +++ b/app/assets/javascripts/ide/lib/diff/diff.js @@ -11,14 +11,16 @@ export const computeDiff = (originalContent, newContent) => { if (findOnLine) { Object.assign(findOnLine, change, { modified: true, - endLineNumber: (lineNumber + change.count) - 1, + endLineNumber: lineNumber + change.count - 1, }); } else if ('added' in change || 'removed' in change) { - acc.push(Object.assign({}, change, { - lineNumber, - modified: undefined, - endLineNumber: (lineNumber + change.count) - 1, - })); + acc.push( + Object.assign({}, change, { + lineNumber, + modified: undefined, + endLineNumber: lineNumber + change.count - 1, + }), + ); } if (!change.removed) { diff --git a/app/assets/javascripts/ide/lib/diff/diff_worker.js b/app/assets/javascripts/ide/lib/diff/diff_worker.js index 78b2eab6399..77416a8de9d 100644 --- a/app/assets/javascripts/ide/lib/diff/diff_worker.js +++ b/app/assets/javascripts/ide/lib/diff/diff_worker.js @@ -1,7 +1,7 @@ import { computeDiff } from './diff'; // eslint-disable-next-line no-restricted-globals -self.addEventListener('message', (e) => { +self.addEventListener('message', e => { const { data } = e; // eslint-disable-next-line no-restricted-globals diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js index 187f8c75d07..3ac2f8b3698 100644 --- a/app/assets/javascripts/ide/stores/actions/merge_request.js +++ b/app/assets/javascripts/ide/stores/actions/merge_request.js @@ -116,57 +116,57 @@ export const openMergeRequest = ( targetProjectId, mergeRequestId, }) - .then(mr => { - dispatch('setCurrentBranchId', mr.source_branch); + .then(mr => { + dispatch('setCurrentBranchId', mr.source_branch); - dispatch('getBranchData', { - projectId, - branchId: mr.source_branch, - }); + dispatch('getBranchData', { + projectId, + branchId: mr.source_branch, + }); - return dispatch('getFiles', { - projectId, - branchId: mr.source_branch, - }); - }) - .then(() => - dispatch('getMergeRequestVersions', { - projectId, - targetProjectId, - mergeRequestId, - }), - ) - .then(() => - dispatch('getMergeRequestChanges', { - projectId, - targetProjectId, - mergeRequestId, - }), - ) - .then(mrChanges => { - if (mrChanges.changes.length) { - dispatch('updateActivityBarView', activityBarViews.review); - } + return dispatch('getFiles', { + projectId, + branchId: mr.source_branch, + }); + }) + .then(() => + dispatch('getMergeRequestVersions', { + projectId, + targetProjectId, + mergeRequestId, + }), + ) + .then(() => + dispatch('getMergeRequestChanges', { + projectId, + targetProjectId, + mergeRequestId, + }), + ) + .then(mrChanges => { + if (mrChanges.changes.length) { + dispatch('updateActivityBarView', activityBarViews.review); + } - mrChanges.changes.forEach((change, ind) => { - const changeTreeEntry = state.entries[change.new_path]; + mrChanges.changes.forEach((change, ind) => { + const changeTreeEntry = state.entries[change.new_path]; - if (changeTreeEntry) { - dispatch('setFileMrChange', { - file: changeTreeEntry, - mrChange: change, - }); - - if (ind < 10) { - dispatch('getFileData', { - path: change.new_path, - makeFileActive: ind === 0, + if (changeTreeEntry) { + dispatch('setFileMrChange', { + file: changeTreeEntry, + mrChange: change, }); + + if (ind < 10) { + dispatch('getFileData', { + path: change.new_path, + makeFileActive: ind === 0, + }); + } } - } + }); + }) + .catch(e => { + flash(__('Error while loading the merge request. Please try again.')); + throw e; }); - }) - .catch(e => { - flash(__('Error while loading the merge request. Please try again.')); - throw e; - }); diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js index 543dc6c0461..2cb08ab2945 100644 --- a/app/assets/javascripts/ide/stores/actions/project.js +++ b/app/assets/javascripts/ide/stores/actions/project.js @@ -125,10 +125,7 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => { }); }; -export const openBranch = ( - { dispatch, state }, - { projectId, branchId, basePath }, -) => { +export const openBranch = ({ dispatch, state }, { projectId, branchId, basePath }) => { dispatch('setCurrentBranchId', branchId); dispatch('getBranchData', { @@ -136,23 +133,20 @@ export const openBranch = ( branchId, }); - return ( - dispatch('getFiles', { - projectId, - branchId, - }) - .then(() => { - if (basePath) { - const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath; - const treeEntryKey = Object.keys(state.entries).find( - key => key === path && !state.entries[key].pending, - ); - const treeEntry = state.entries[treeEntryKey]; + return dispatch('getFiles', { + projectId, + branchId, + }).then(() => { + if (basePath) { + const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath; + const treeEntryKey = Object.keys(state.entries).find( + key => key === path && !state.entries[key].pending, + ); + const treeEntry = state.entries[treeEntryKey]; - if (treeEntry) { - dispatch('handleTreeEntryAction', treeEntry); - } + if (treeEntry) { + dispatch('handleTreeEntryAction', treeEntry); } - }) - ); + } + }); }; diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js index 462ca45db9b..d97a950a8b2 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/actions.js +++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js @@ -30,9 +30,9 @@ export const setLastCommitMessage = ({ rootState, commit }, data) => { const currentProject = rootState.projects[rootState.currentProjectId]; const commitStats = data.stats ? sprintf(__('with %{additions} additions, %{deletions} deletions.'), { - additions: data.stats.additions, // eslint-disable-line indent-legacy - deletions: data.stats.deletions, // eslint-disable-line indent-legacy - }) // eslint-disable-line indent-legacy + additions: data.stats.additions, + deletions: data.stats.deletions, + }) : ''; const commitMsg = sprintf( __('Your changes have been committed. Commit %{commitId} %{commitStats}'), diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js index baa2497ec5b..4565c11a83f 100644 --- a/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js @@ -3,8 +3,7 @@ import Api from '../../../../api'; import { scopes } from './constants'; import * as types from './mutation_types'; -export const requestMergeRequests = ({ commit }) => - commit(types.REQUEST_MERGE_REQUESTS); +export const requestMergeRequests = ({ commit }) => commit(types.REQUEST_MERGE_REQUESTS); export const receiveMergeRequestsError = ({ commit, dispatch }, { type, search }) => { dispatch( 'setErrorMessage', diff --git a/app/assets/javascripts/issuable_bulk_update_actions.js b/app/assets/javascripts/issuable_bulk_update_actions.js index 9e848699163..9848bcc2e64 100644 --- a/app/assets/javascripts/issuable_bulk_update_actions.js +++ b/app/assets/javascripts/issuable_bulk_update_actions.js @@ -1,4 +1,4 @@ -/* eslint-disable comma-dangle, quotes, consistent-return, func-names, array-callback-return, prefer-arrow-callback, max-len, no-unused-vars */ +/* eslint-disable consistent-return, func-names, array-callback-return, prefer-arrow-callback, no-unused-vars */ import $ from 'jquery'; import _ from 'underscore'; diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js index 8c225cd7d91..4b4e9aa48ab 100644 --- a/app/assets/javascripts/issue.js +++ b/app/assets/javascripts/issue.js @@ -1,4 +1,4 @@ -/* eslint-disable no-var, one-var, one-var-declaration-per-line, no-unused-vars, consistent-return, quotes, max-len */ +/* eslint-disable no-var, one-var, no-unused-vars, consistent-return */ import $ from 'jquery'; import axios from './lib/utils/axios_utils'; diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index c6ad3aa3e0d..04c1cf021d9 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -1,281 +1,279 @@ <script> - import Visibility from 'visibilityjs'; - import { visitUrl } from '../../lib/utils/url_utility'; - import Poll from '../../lib/utils/poll'; - import eventHub from '../event_hub'; - import Service from '../services/index'; - import Store from '../stores'; - import titleComponent from './title.vue'; - import descriptionComponent from './description.vue'; - import editedComponent from './edited.vue'; - import formComponent from './form.vue'; - import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor'; +import Visibility from 'visibilityjs'; +import { visitUrl } from '../../lib/utils/url_utility'; +import Poll from '../../lib/utils/poll'; +import eventHub from '../event_hub'; +import Service from '../services/index'; +import Store from '../stores'; +import titleComponent from './title.vue'; +import descriptionComponent from './description.vue'; +import editedComponent from './edited.vue'; +import formComponent from './form.vue'; +import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor'; - export default { - components: { - descriptionComponent, - titleComponent, - editedComponent, - formComponent, - }, - mixins: [ - recaptchaModalImplementor, - ], - props: { - endpoint: { - required: true, - type: String, - }, - updateEndpoint: { - required: true, - type: String, - }, - canUpdate: { - required: true, - type: Boolean, - }, - canDestroy: { - required: true, - type: Boolean, - }, - showInlineEditButton: { - type: Boolean, - required: false, - default: true, - }, - showDeleteButton: { - type: Boolean, - required: false, - default: true, - }, - enableAutocomplete: { - type: Boolean, - required: false, - default: true, - }, - issuableRef: { - type: String, - required: true, - }, - initialTitleHtml: { - type: String, - required: true, - }, - initialTitleText: { - type: String, - required: true, - }, - initialDescriptionHtml: { - type: String, - required: false, - default: '', - }, - initialDescriptionText: { - type: String, - required: false, - default: '', - }, - initialTaskStatus: { - type: String, - required: false, - default: '', - }, - updatedAt: { - type: String, - required: false, - default: '', - }, - updatedByName: { - type: String, - required: false, - default: '', - }, - updatedByPath: { - type: String, - required: false, - default: '', - }, - issuableTemplates: { - type: Array, - required: false, - default: () => [], - }, - markdownPreviewPath: { - type: String, - required: true, - }, - markdownDocsPath: { - type: String, - required: true, - }, - markdownVersion: { - type: Number, - required: false, - default: 0, - }, - projectPath: { - type: String, - required: true, - }, - projectNamespace: { - type: String, - required: true, - }, - issuableType: { - type: String, - required: false, - default: 'issue', - }, - canAttachFile: { - type: Boolean, - required: false, - default: true, - }, +export default { + components: { + descriptionComponent, + titleComponent, + editedComponent, + formComponent, + }, + mixins: [recaptchaModalImplementor], + props: { + endpoint: { + required: true, + type: String, }, - data() { - const store = new Store({ - titleHtml: this.initialTitleHtml, - titleText: this.initialTitleText, - descriptionHtml: this.initialDescriptionHtml, - descriptionText: this.initialDescriptionText, - updatedAt: this.updatedAt, - updatedByName: this.updatedByName, - updatedByPath: this.updatedByPath, - taskStatus: this.initialTaskStatus, - }); + updateEndpoint: { + required: true, + type: String, + }, + canUpdate: { + required: true, + type: Boolean, + }, + canDestroy: { + required: true, + type: Boolean, + }, + showInlineEditButton: { + type: Boolean, + required: false, + default: true, + }, + showDeleteButton: { + type: Boolean, + required: false, + default: true, + }, + enableAutocomplete: { + type: Boolean, + required: false, + default: true, + }, + issuableRef: { + type: String, + required: true, + }, + initialTitleHtml: { + type: String, + required: true, + }, + initialTitleText: { + type: String, + required: true, + }, + initialDescriptionHtml: { + type: String, + required: false, + default: '', + }, + initialDescriptionText: { + type: String, + required: false, + default: '', + }, + initialTaskStatus: { + type: String, + required: false, + default: '', + }, + updatedAt: { + type: String, + required: false, + default: '', + }, + updatedByName: { + type: String, + required: false, + default: '', + }, + updatedByPath: { + type: String, + required: false, + default: '', + }, + issuableTemplates: { + type: Array, + required: false, + default: () => [], + }, + markdownPreviewPath: { + type: String, + required: true, + }, + markdownDocsPath: { + type: String, + required: true, + }, + markdownVersion: { + type: Number, + required: false, + default: 0, + }, + projectPath: { + type: String, + required: true, + }, + projectNamespace: { + type: String, + required: true, + }, + issuableType: { + type: String, + required: false, + default: 'issue', + }, + canAttachFile: { + type: Boolean, + required: false, + default: true, + }, + }, + data() { + const store = new Store({ + titleHtml: this.initialTitleHtml, + titleText: this.initialTitleText, + descriptionHtml: this.initialDescriptionHtml, + descriptionText: this.initialDescriptionText, + updatedAt: this.updatedAt, + updatedByName: this.updatedByName, + updatedByPath: this.updatedByPath, + taskStatus: this.initialTaskStatus, + }); - return { - store, - state: store.state, - showForm: false, - }; - }, - computed: { - formState() { - return this.store.formState; - }, - hasUpdated() { - return !!this.state.updatedAt; - }, - issueChanged() { - const descriptionChanged = - this.initialDescriptionText !== this.store.formState.description; - const titleChanged = - this.initialTitleText !== this.store.formState.title; - return descriptionChanged || titleChanged; - }, + return { + store, + state: store.state, + showForm: false, + }; + }, + computed: { + formState() { + return this.store.formState; }, - created() { - this.service = new Service(this.endpoint); - this.poll = new Poll({ - resource: this.service, - method: 'getData', - successCallback: res => this.store.updateState(res.data), - errorCallback(err) { - throw new Error(err); - }, - }); + hasUpdated() { + return !!this.state.updatedAt; + }, + issueChanged() { + const descriptionChanged = this.initialDescriptionText !== this.store.formState.description; + const titleChanged = this.initialTitleText !== this.store.formState.title; + return descriptionChanged || titleChanged; + }, + }, + created() { + this.service = new Service(this.endpoint); + this.poll = new Poll({ + resource: this.service, + method: 'getData', + successCallback: res => this.store.updateState(res.data), + errorCallback(err) { + throw new Error(err); + }, + }); + + if (!Visibility.hidden()) { + this.poll.makeRequest(); + } + Visibility.change(() => { if (!Visibility.hidden()) { - this.poll.makeRequest(); + this.poll.restart(); + } else { + this.poll.stop(); } + }); - Visibility.change(() => { - if (!Visibility.hidden()) { - this.poll.restart(); - } else { - this.poll.stop(); - } - }); - - window.addEventListener('beforeunload', this.handleBeforeUnloadEvent); + window.addEventListener('beforeunload', this.handleBeforeUnloadEvent); - eventHub.$on('delete.issuable', this.deleteIssuable); - eventHub.$on('update.issuable', this.updateIssuable); - eventHub.$on('close.form', this.closeForm); - eventHub.$on('open.form', this.openForm); - }, - beforeDestroy() { - eventHub.$off('delete.issuable', this.deleteIssuable); - eventHub.$off('update.issuable', this.updateIssuable); - eventHub.$off('close.form', this.closeForm); - eventHub.$off('open.form', this.openForm); - window.removeEventListener('beforeunload', this.handleBeforeUnloadEvent); - }, - methods: { - handleBeforeUnloadEvent(e) { - const event = e; - if (this.showForm && this.issueChanged) { - event.returnValue = 'Are you sure you want to lose your issue information?'; - } - return undefined; - }, + eventHub.$on('delete.issuable', this.deleteIssuable); + eventHub.$on('update.issuable', this.updateIssuable); + eventHub.$on('close.form', this.closeForm); + eventHub.$on('open.form', this.openForm); + }, + beforeDestroy() { + eventHub.$off('delete.issuable', this.deleteIssuable); + eventHub.$off('update.issuable', this.updateIssuable); + eventHub.$off('close.form', this.closeForm); + eventHub.$off('open.form', this.openForm); + window.removeEventListener('beforeunload', this.handleBeforeUnloadEvent); + }, + methods: { + handleBeforeUnloadEvent(e) { + const event = e; + if (this.showForm && this.issueChanged) { + event.returnValue = 'Are you sure you want to lose your issue information?'; + } + return undefined; + }, - openForm() { - if (!this.showForm) { - this.showForm = true; - this.store.setFormState({ - title: this.state.titleText, - description: this.state.descriptionText, - lockedWarningVisible: false, - updateLoading: false, - }); - } - }, - closeForm() { - this.showForm = false; - }, + openForm() { + if (!this.showForm) { + this.showForm = true; + this.store.setFormState({ + title: this.state.titleText, + description: this.state.descriptionText, + lockedWarningVisible: false, + updateLoading: false, + }); + } + }, + closeForm() { + this.showForm = false; + }, - updateIssuable() { - return this.service.updateIssuable(this.store.formState) - .then(res => res.data) - .then(data => this.checkForSpam(data)) - .then((data) => { - if (window.location.pathname !== data.web_url) { - visitUrl(data.web_url); - } + updateIssuable() { + return this.service + .updateIssuable(this.store.formState) + .then(res => res.data) + .then(data => this.checkForSpam(data)) + .then(data => { + if (window.location.pathname !== data.web_url) { + visitUrl(data.web_url); + } - return this.service.getData(); - }) - .then(res => res.data) - .then((data) => { - this.store.updateState(data); + return this.service.getData(); + }) + .then(res => res.data) + .then(data => { + this.store.updateState(data); + eventHub.$emit('close.form'); + }) + .catch(error => { + if (error && error.name === 'SpamError') { + this.openRecaptcha(); + } else { eventHub.$emit('close.form'); - }) - .catch((error) => { - if (error && error.name === 'SpamError') { - this.openRecaptcha(); - } else { - eventHub.$emit('close.form'); - window.Flash(`Error updating ${this.issuableType}`); - } - }); - }, - - closeRecaptchaModal() { - this.store.setFormState({ - updateLoading: false, + window.Flash(`Error updating ${this.issuableType}`); + } }); + }, - this.closeRecaptcha(); - }, + closeRecaptchaModal() { + this.store.setFormState({ + updateLoading: false, + }); - deleteIssuable() { - this.service.deleteIssuable() - .then(res => res.data) - .then((data) => { - // Stop the poll so we don't get 404's with the issuable not existing - this.poll.stop(); + this.closeRecaptcha(); + }, - visitUrl(data.web_url); - }) - .catch(() => { - eventHub.$emit('close.form'); - window.Flash(`Error deleting ${this.issuableType}`); - }); - }, + deleteIssuable() { + this.service + .deleteIssuable() + .then(res => res.data) + .then(data => { + // Stop the poll so we don't get 404's with the issuable not existing + this.poll.stop(); + + visitUrl(data.web_url); + }) + .catch(() => { + eventHub.$emit('close.form'); + window.Flash(`Error deleting ${this.issuableType}`); + }); }, - }; + }, +}; </script> <template> diff --git a/app/assets/javascripts/issue_show/components/description.vue b/app/assets/javascripts/issue_show/components/description.vue index 1174177f561..461cb3271b7 100644 --- a/app/assets/javascripts/issue_show/components/description.vue +++ b/app/assets/javascripts/issue_show/components/description.vue @@ -1,110 +1,105 @@ <script> - import $ from 'jquery'; - import animateMixin from '../mixins/animate'; - import TaskList from '../../task_list'; - import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor'; +import $ from 'jquery'; +import animateMixin from '../mixins/animate'; +import TaskList from '../../task_list'; +import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor'; - export default { - mixins: [ - animateMixin, - recaptchaModalImplementor, - ], +export default { + mixins: [animateMixin, recaptchaModalImplementor], - props: { - canUpdate: { - type: Boolean, - required: true, - }, - descriptionHtml: { - type: String, - required: true, - }, - descriptionText: { - type: String, - required: true, - }, - taskStatus: { - type: String, - required: false, - default: '', - }, - issuableType: { - type: String, - required: false, - default: 'issue', - }, - updateUrl: { - type: String, - required: false, - default: null, - }, + props: { + canUpdate: { + type: Boolean, + required: true, }, - data() { - return { - preAnimation: false, - pulseAnimation: false, - }; + descriptionHtml: { + type: String, + required: true, }, - watch: { - descriptionHtml() { - this.animateChange(); + descriptionText: { + type: String, + required: true, + }, + taskStatus: { + type: String, + required: false, + default: '', + }, + issuableType: { + type: String, + required: false, + default: 'issue', + }, + updateUrl: { + type: String, + required: false, + default: null, + }, + }, + data() { + return { + preAnimation: false, + pulseAnimation: false, + }; + }, + watch: { + descriptionHtml() { + this.animateChange(); - this.$nextTick(() => { - this.renderGFM(); - }); - }, - taskStatus() { - this.updateTaskStatusText(); - }, + this.$nextTick(() => { + this.renderGFM(); + }); }, - mounted() { - this.renderGFM(); + taskStatus() { this.updateTaskStatusText(); }, - methods: { - renderGFM() { - $(this.$refs['gfm-content']).renderGFM(); + }, + mounted() { + this.renderGFM(); + this.updateTaskStatusText(); + }, + methods: { + renderGFM() { + $(this.$refs['gfm-content']).renderGFM(); - if (this.canUpdate) { - // eslint-disable-next-line no-new - new TaskList({ - dataType: this.issuableType, - fieldName: 'description', - selector: '.detail-page-description', - onSuccess: this.taskListUpdateSuccess.bind(this), - }); - } - }, + if (this.canUpdate) { + // eslint-disable-next-line no-new + new TaskList({ + dataType: this.issuableType, + fieldName: 'description', + selector: '.detail-page-description', + onSuccess: this.taskListUpdateSuccess.bind(this), + }); + } + }, - taskListUpdateSuccess(data) { - try { - this.checkForSpam(data); - this.closeRecaptcha(); - } catch (error) { - if (error && error.name === 'SpamError') this.openRecaptcha(); - } - }, + taskListUpdateSuccess(data) { + try { + this.checkForSpam(data); + this.closeRecaptcha(); + } catch (error) { + if (error && error.name === 'SpamError') this.openRecaptcha(); + } + }, - updateTaskStatusText() { - const taskRegexMatches = this.taskStatus.match(/(\d+) of ((?!0)\d+)/); - const $issuableHeader = $('.issuable-meta'); - const $tasks = $('#task_status', $issuableHeader); - const $tasksShort = $('#task_status_short', $issuableHeader); + updateTaskStatusText() { + const taskRegexMatches = this.taskStatus.match(/(\d+) of ((?!0)\d+)/); + const $issuableHeader = $('.issuable-meta'); + const $tasks = $('#task_status', $issuableHeader); + const $tasksShort = $('#task_status_short', $issuableHeader); - if (taskRegexMatches) { - $tasks.text(this.taskStatus); - $tasksShort.text( - `${taskRegexMatches[1]}/${taskRegexMatches[2]} task${taskRegexMatches[2] > 1 ? - 's' : - ''}`, - ); - } else { - $tasks.text(''); - $tasksShort.text(''); - } - }, + if (taskRegexMatches) { + $tasks.text(this.taskStatus); + $tasksShort.text( + `${taskRegexMatches[1]}/${taskRegexMatches[2]} task${taskRegexMatches[2] > 1 ? 's' : ''}`, + ); + } else { + $tasks.text(''); + $tasksShort.text(''); + } }, - }; + }, +}; </script> <template> diff --git a/app/assets/javascripts/issue_show/components/edit_actions.vue b/app/assets/javascripts/issue_show/components/edit_actions.vue index c3d39082714..5dda35d64bb 100644 --- a/app/assets/javascripts/issue_show/components/edit_actions.vue +++ b/app/assets/javascripts/issue_show/components/edit_actions.vue @@ -1,64 +1,64 @@ <script> - import { __, sprintf } from '~/locale'; - import updateMixin from '../mixins/update'; - import eventHub from '../event_hub'; +import { __, sprintf } from '~/locale'; +import updateMixin from '../mixins/update'; +import eventHub from '../event_hub'; - const issuableTypes = { - issue: __('Issue'), - epic: __('Epic'), - }; +const issuableTypes = { + issue: __('Issue'), + epic: __('Epic'), +}; - export default { - mixins: [updateMixin], - props: { - canDestroy: { - type: Boolean, - required: true, - }, - formState: { - type: Object, - required: true, - }, - showDeleteButton: { - type: Boolean, - required: false, - default: true, - }, - issuableType: { - type: String, - required: true, - }, +export default { + mixins: [updateMixin], + props: { + canDestroy: { + type: Boolean, + required: true, }, - data() { - return { - deleteLoading: false, - }; + formState: { + type: Object, + required: true, }, - computed: { - isSubmitEnabled() { - return this.formState.title.trim() !== ''; - }, - shouldShowDeleteButton() { - return this.canDestroy && this.showDeleteButton; - }, + showDeleteButton: { + type: Boolean, + required: false, + default: true, }, - methods: { - closeForm() { - eventHub.$emit('close.form'); - }, - deleteIssuable() { - const confirmMessage = sprintf(__('%{issuableType} will be removed! Are you sure?'), { - issuableType: issuableTypes[this.issuableType], - }); - // eslint-disable-next-line no-alert - if (window.confirm(confirmMessage)) { - this.deleteLoading = true; + issuableType: { + type: String, + required: true, + }, + }, + data() { + return { + deleteLoading: false, + }; + }, + computed: { + isSubmitEnabled() { + return this.formState.title.trim() !== ''; + }, + shouldShowDeleteButton() { + return this.canDestroy && this.showDeleteButton; + }, + }, + methods: { + closeForm() { + eventHub.$emit('close.form'); + }, + deleteIssuable() { + const confirmMessage = sprintf(__('%{issuableType} will be removed! Are you sure?'), { + issuableType: issuableTypes[this.issuableType], + }); + // eslint-disable-next-line no-alert + if (window.confirm(confirmMessage)) { + this.deleteLoading = true; - eventHub.$emit('delete.issuable'); - } - }, + eventHub.$emit('delete.issuable'); + } }, - }; + }, +}; </script> <template> diff --git a/app/assets/javascripts/issue_show/components/edited.vue b/app/assets/javascripts/issue_show/components/edited.vue index 05cd976f196..73ecb26c28d 100644 --- a/app/assets/javascripts/issue_show/components/edited.vue +++ b/app/assets/javascripts/issue_show/components/edited.vue @@ -1,33 +1,33 @@ <script> - import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; +import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; - export default { - components: { - timeAgoTooltip, +export default { + components: { + timeAgoTooltip, + }, + props: { + updatedAt: { + type: String, + required: false, + default: '', }, - props: { - updatedAt: { - type: String, - required: false, - default: '', - }, - updatedByName: { - type: String, - required: false, - default: '', - }, - updatedByPath: { - type: String, - required: false, - default: '', - }, + updatedByName: { + type: String, + required: false, + default: '', }, - computed: { - hasUpdatedBy() { - return this.updatedByName && this.updatedByPath; - }, + updatedByPath: { + type: String, + required: false, + default: '', }, - }; + }, + computed: { + hasUpdatedBy() { + return this.updatedByName && this.updatedByPath; + }, + }, +}; </script> <template> @@ -53,4 +53,3 @@ </span> </small> </template> - diff --git a/app/assets/javascripts/issue_show/components/fields/description.vue b/app/assets/javascripts/issue_show/components/fields/description.vue index 1a78c59d715..e9e96a985a7 100644 --- a/app/assets/javascripts/issue_show/components/fields/description.vue +++ b/app/assets/javascripts/issue_show/components/fields/description.vue @@ -1,45 +1,45 @@ <script> - import updateMixin from '../../mixins/update'; - import markdownField from '../../../vue_shared/components/markdown/field.vue'; +import updateMixin from '../../mixins/update'; +import markdownField from '../../../vue_shared/components/markdown/field.vue'; - export default { - components: { - markdownField, +export default { + components: { + markdownField, + }, + mixins: [updateMixin], + props: { + formState: { + type: Object, + required: true, }, - mixins: [updateMixin], - props: { - formState: { - type: Object, - required: true, - }, - markdownPreviewPath: { - type: String, - required: true, - }, - markdownDocsPath: { - type: String, - required: true, - }, - markdownVersion: { - type: Number, - required: false, - default: 0, - }, - canAttachFile: { - type: Boolean, - required: false, - default: true, - }, - enableAutocomplete: { - type: Boolean, - required: false, - default: true, - }, + markdownPreviewPath: { + type: String, + required: true, }, - mounted() { - this.$refs.textarea.focus(); + markdownDocsPath: { + type: String, + required: true, }, - }; + markdownVersion: { + type: Number, + required: false, + default: 0, + }, + canAttachFile: { + type: Boolean, + required: false, + default: true, + }, + enableAutocomplete: { + type: Boolean, + required: false, + default: true, + }, + }, + mounted() { + this.$refs.textarea.focus(); + }, +}; </script> <template> diff --git a/app/assets/javascripts/issue_show/components/fields/description_template.vue b/app/assets/javascripts/issue_show/components/fields/description_template.vue index e90d9fad94e..e433bf66cfc 100644 --- a/app/assets/javascripts/issue_show/components/fields/description_template.vue +++ b/app/assets/javascripts/issue_show/components/fields/description_template.vue @@ -1,46 +1,46 @@ <script> - import $ from 'jquery'; - import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors'; +import $ from 'jquery'; +import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors'; - export default { - props: { - formState: { - type: Object, - required: true, - }, - issuableTemplates: { - type: Array, - required: false, - default: () => [], - }, - projectPath: { - type: String, - required: true, - }, - projectNamespace: { - type: String, - required: true, - }, +export default { + props: { + formState: { + type: Object, + required: true, }, - computed: { - issuableTemplatesJson() { - return JSON.stringify(this.issuableTemplates); - }, + issuableTemplates: { + type: Array, + required: false, + default: () => [], }, - mounted() { - // Create the editor for the template - const editor = document.querySelector('.detail-page-description .note-textarea') || {}; - editor.setValue = (val) => { - this.formState.description = val; - }; - editor.getValue = () => this.formState.description; - - this.issuableTemplate = new IssuableTemplateSelectors({ - $dropdowns: $(this.$refs.toggle), - editor, - }); + projectPath: { + type: String, + required: true, + }, + projectNamespace: { + type: String, + required: true, }, - }; + }, + computed: { + issuableTemplatesJson() { + return JSON.stringify(this.issuableTemplates); + }, + }, + mounted() { + // Create the editor for the template + const editor = document.querySelector('.detail-page-description .note-textarea') || {}; + editor.setValue = val => { + this.formState.description = val; + }; + editor.getValue = () => this.formState.description; + + this.issuableTemplate = new IssuableTemplateSelectors({ + $dropdowns: $(this.$refs.toggle), + editor, + }); + }, +}; </script> <template> diff --git a/app/assets/javascripts/issue_show/components/fields/title.vue b/app/assets/javascripts/issue_show/components/fields/title.vue index b7f2b1a6050..11f4153b8d5 100644 --- a/app/assets/javascripts/issue_show/components/fields/title.vue +++ b/app/assets/javascripts/issue_show/components/fields/title.vue @@ -1,15 +1,15 @@ <script> - import updateMixin from '../../mixins/update'; +import updateMixin from '../../mixins/update'; - export default { - mixins: [updateMixin], - props: { - formState: { - type: Object, - required: true, - }, +export default { + mixins: [updateMixin], + props: { + formState: { + type: Object, + required: true, }, - }; + }, +}; </script> <template> diff --git a/app/assets/javascripts/issue_show/components/form.vue b/app/assets/javascripts/issue_show/components/form.vue index 03d8d0ec67c..3b430d92912 100644 --- a/app/assets/javascripts/issue_show/components/form.vue +++ b/app/assets/javascripts/issue_show/components/form.vue @@ -1,79 +1,79 @@ <script> - import lockedWarning from './locked_warning.vue'; - import titleField from './fields/title.vue'; - import descriptionField from './fields/description.vue'; - import editActions from './edit_actions.vue'; - import descriptionTemplate from './fields/description_template.vue'; +import lockedWarning from './locked_warning.vue'; +import titleField from './fields/title.vue'; +import descriptionField from './fields/description.vue'; +import editActions from './edit_actions.vue'; +import descriptionTemplate from './fields/description_template.vue'; - export default { - components: { - lockedWarning, - titleField, - descriptionField, - descriptionTemplate, - editActions, +export default { + components: { + lockedWarning, + titleField, + descriptionField, + descriptionTemplate, + editActions, + }, + props: { + canDestroy: { + type: Boolean, + required: true, }, - props: { - canDestroy: { - type: Boolean, - required: true, - }, - formState: { - type: Object, - required: true, - }, - issuableTemplates: { - type: Array, - required: false, - default: () => [], - }, - issuableType: { - type: String, - required: true, - }, - markdownPreviewPath: { - type: String, - required: true, - }, - markdownDocsPath: { - type: String, - required: true, - }, - markdownVersion: { - type: Number, - required: false, - default: 0, - }, - projectPath: { - type: String, - required: true, - }, - projectNamespace: { - type: String, - required: true, - }, - showDeleteButton: { - type: Boolean, - required: false, - default: true, - }, - canAttachFile: { - type: Boolean, - required: false, - default: true, - }, - enableAutocomplete: { - type: Boolean, - required: false, - default: true, - }, + formState: { + type: Object, + required: true, }, - computed: { - hasIssuableTemplates() { - return this.issuableTemplates.length; - }, + issuableTemplates: { + type: Array, + required: false, + default: () => [], }, - }; + issuableType: { + type: String, + required: true, + }, + markdownPreviewPath: { + type: String, + required: true, + }, + markdownDocsPath: { + type: String, + required: true, + }, + markdownVersion: { + type: Number, + required: false, + default: 0, + }, + projectPath: { + type: String, + required: true, + }, + projectNamespace: { + type: String, + required: true, + }, + showDeleteButton: { + type: Boolean, + required: false, + default: true, + }, + canAttachFile: { + type: Boolean, + required: false, + default: true, + }, + enableAutocomplete: { + type: Boolean, + required: false, + default: true, + }, + }, + computed: { + hasIssuableTemplates() { + return this.issuableTemplates.length; + }, + }, +}; </script> <template> diff --git a/app/assets/javascripts/issue_show/components/locked_warning.vue b/app/assets/javascripts/issue_show/components/locked_warning.vue index ad0d40faf32..0682c6f2a35 100644 --- a/app/assets/javascripts/issue_show/components/locked_warning.vue +++ b/app/assets/javascripts/issue_show/components/locked_warning.vue @@ -1,11 +1,11 @@ <script> - export default { - computed: { - currentPath() { - return window.location.pathname; - }, +export default { + computed: { + currentPath() { + return window.location.pathname; }, - }; + }, +}; </script> <template> diff --git a/app/assets/javascripts/issue_show/stores/index.js b/app/assets/javascripts/issue_show/stores/index.js index af8b0414266..32044d6da25 100644 --- a/app/assets/javascripts/issue_show/stores/index.js +++ b/app/assets/javascripts/issue_show/stores/index.js @@ -25,8 +25,10 @@ export default class Store { } stateShouldUpdate(data) { - return this.state.titleText !== data.title_text || - this.state.descriptionText !== data.description_text; + return ( + this.state.titleText !== data.title_text || + this.state.descriptionText !== data.description_text + ); } setFormState(state) { diff --git a/app/assets/javascripts/jobs/components/artifacts_block.vue b/app/assets/javascripts/jobs/components/artifacts_block.vue index d5866f9b9f1..17fd5321642 100644 --- a/app/assets/javascripts/jobs/components/artifacts_block.vue +++ b/app/assets/javascripts/jobs/components/artifacts_block.vue @@ -1,30 +1,28 @@ <script> - import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; - import timeagoMixin from '~/vue_shared/mixins/timeago'; +import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import timeagoMixin from '~/vue_shared/mixins/timeago'; - export default { - components: { - TimeagoTooltip, +export default { + components: { + TimeagoTooltip, + }, + mixins: [timeagoMixin], + props: { + artifact: { + type: Object, + required: true, }, - mixins: [ - timeagoMixin, - ], - props: { - artifact: { - type: Object, - required: true, - }, + }, + computed: { + isExpired() { + return this.artifact.expired; }, - computed: { - isExpired() { - return this.artifact.expired; - }, - // Only when the key is `false` we can render this block - willExpire() { - return this.artifact.expired === false; - }, + // Only when the key is `false` we can render this block + willExpire() { + return this.artifact.expired === false; }, - }; + }, +}; </script> <template> <div class="block"> diff --git a/app/assets/javascripts/jobs/components/commit_block.vue b/app/assets/javascripts/jobs/components/commit_block.vue index 4b1788a1c16..7d51f6afd10 100644 --- a/app/assets/javascripts/jobs/components/commit_block.vue +++ b/app/assets/javascripts/jobs/components/commit_block.vue @@ -1,26 +1,26 @@ <script> - import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; - export default { - components: { - ClipboardButton, +export default { + components: { + ClipboardButton, + }, + props: { + commit: { + type: Object, + required: true, }, - props: { - commit: { - type: Object, - required: true, - }, - mergeRequest: { - type: Object, - required: false, - default: null, - }, - isLastBlock: { - type: Boolean, - required: true, - }, + mergeRequest: { + type: Object, + required: false, + default: null, }, - }; + isLastBlock: { + type: Boolean, + required: true, + }, + }, +}; </script> <template> <div diff --git a/app/assets/javascripts/jobs/components/empty_state.vue b/app/assets/javascripts/jobs/components/empty_state.vue index ff500eddddb..ee5ceb99b0a 100644 --- a/app/assets/javascripts/jobs/components/empty_state.vue +++ b/app/assets/javascripts/jobs/components/empty_state.vue @@ -1,38 +1,38 @@ <script> - export default { - props: { - illustrationPath: { - type: String, - required: true, - }, - illustrationSizeClass: { - type: String, - required: true, - }, - title: { - type: String, - required: true, - }, - content: { - type: String, - required: false, - default: null, - }, - action: { - type: Object, - required: false, - default: null, - validator(value) { - return ( - value === null || - (Object.prototype.hasOwnProperty.call(value, 'path') && - Object.prototype.hasOwnProperty.call(value, 'method') && - Object.prototype.hasOwnProperty.call(value, 'button_title')) - ); - }, +export default { + props: { + illustrationPath: { + type: String, + required: true, + }, + illustrationSizeClass: { + type: String, + required: true, + }, + title: { + type: String, + required: true, + }, + content: { + type: String, + required: false, + default: null, + }, + action: { + type: Object, + required: false, + default: null, + validator(value) { + return ( + value === null || + (Object.prototype.hasOwnProperty.call(value, 'path') && + Object.prototype.hasOwnProperty.call(value, 'method') && + Object.prototype.hasOwnProperty.call(value, 'button_title')) + ); }, }, - }; + }, +}; </script> <template> <div class="row empty-state"> diff --git a/app/assets/javascripts/jobs/components/environments_block.vue b/app/assets/javascripts/jobs/components/environments_block.vue index e6e1d418194..6d1eb713886 100644 --- a/app/assets/javascripts/jobs/components/environments_block.vue +++ b/app/assets/javascripts/jobs/components/environments_block.vue @@ -1,129 +1,131 @@ <script> - import _ from 'underscore'; - import CiIcon from '~/vue_shared/components/ci_icon.vue'; - import { sprintf, __ } from '../../locale'; +import _ from 'underscore'; +import CiIcon from '~/vue_shared/components/ci_icon.vue'; +import { sprintf, __ } from '../../locale'; - export default { - components: { - CiIcon, +export default { + components: { + CiIcon, + }, + props: { + deploymentStatus: { + type: Object, + required: true, }, - props: { - deploymentStatus: { - type: Object, - required: true, - }, - iconStatus: { - type: Object, - required: true, - }, + iconStatus: { + type: Object, + required: true, }, - computed: { - environment() { - let environmentText; - switch (this.deploymentStatus.status) { - case 'last': + }, + computed: { + environment() { + let environmentText; + switch (this.deploymentStatus.status) { + case 'last': + environmentText = sprintf( + __('This job is the most recent deployment to %{link}.'), + { link: this.environmentLink }, + false, + ); + break; + case 'out_of_date': + if (this.hasLastDeployment) { environmentText = sprintf( - __('This job is the most recent deployment to %{link}.'), - { link: this.environmentLink }, + __( + 'This job is an out-of-date deployment to %{environmentLink}. View the most recent deployment %{deploymentLink}.', + ), + { + environmentLink: this.environmentLink, + deploymentLink: this.deploymentLink(`#${this.lastDeployment.iid}`), + }, false, ); - break; - case 'out_of_date': - if (this.hasLastDeployment) { - environmentText = sprintf( - __( - 'This job is an out-of-date deployment to %{environmentLink}. View the most recent deployment %{deploymentLink}.', - ), - { - environmentLink: this.environmentLink, - deploymentLink: this.deploymentLink(`#${this.lastDeployment.iid}`), - }, - false, - ); - } else { - environmentText = sprintf( - __('This job is an out-of-date deployment to %{environmentLink}.'), - { environmentLink: this.environmentLink }, - false, - ); - } - - break; - case 'failed': + } else { environmentText = sprintf( - __('The deployment of this job to %{environmentLink} did not succeed.'), + __('This job is an out-of-date deployment to %{environmentLink}.'), { environmentLink: this.environmentLink }, false, ); - break; - case 'creating': - if (this.hasLastDeployment) { - environmentText = sprintf( - __( - 'This job is creating a deployment to %{environmentLink} and will overwrite the %{deploymentLink}.', - ), - { - environmentLink: this.environmentLink, - deploymentLink: this.deploymentLink(__('latest deployment')), - }, - false, - ); - } else { - environmentText = sprintf( - __('This job is creating a deployment to %{environmentLink}.'), - { environmentLink: this.environmentLink }, - false, - ); - } - break; - default: - break; - } - return environmentText; - }, - environmentLink() { - if (this.hasEnvironment) { - return sprintf( - '%{startLink}%{name}%{endLink}', - { - startLink: `<a href="${ - this.deploymentStatus.environment.environment_path - }" class="js-environment-link">`, - name: _.escape(this.deploymentStatus.environment.name), - endLink: '</a>', - }, + } + + break; + case 'failed': + environmentText = sprintf( + __('The deployment of this job to %{environmentLink} did not succeed.'), + { environmentLink: this.environmentLink }, false, ); - } - return ''; - }, - hasLastDeployment() { - return this.hasEnvironment && this.deploymentStatus.environment.last_deployment; - }, - lastDeployment() { - return this.hasLastDeployment ? this.deploymentStatus.environment.last_deployment : {}; - }, - hasEnvironment() { - return !_.isEmpty(this.deploymentStatus.environment); - }, - lastDeploymentPath() { - return !_.isEmpty(this.lastDeployment.deployable) ? this.lastDeployment.deployable.build_path : ''; - }, + break; + case 'creating': + if (this.hasLastDeployment) { + environmentText = sprintf( + __( + 'This job is creating a deployment to %{environmentLink} and will overwrite the %{deploymentLink}.', + ), + { + environmentLink: this.environmentLink, + deploymentLink: this.deploymentLink(__('latest deployment')), + }, + false, + ); + } else { + environmentText = sprintf( + __('This job is creating a deployment to %{environmentLink}.'), + { environmentLink: this.environmentLink }, + false, + ); + } + break; + default: + break; + } + return environmentText; }, - methods: { - deploymentLink(name) { + environmentLink() { + if (this.hasEnvironment) { return sprintf( '%{startLink}%{name}%{endLink}', { - startLink: `<a href="${this.lastDeploymentPath}" class="js-job-deployment-link">`, - name, + startLink: `<a href="${ + this.deploymentStatus.environment.environment_path + }" class="js-environment-link">`, + name: _.escape(this.deploymentStatus.environment.name), endLink: '</a>', }, false, ); - }, + } + return ''; + }, + hasLastDeployment() { + return this.hasEnvironment && this.deploymentStatus.environment.last_deployment; + }, + lastDeployment() { + return this.hasLastDeployment ? this.deploymentStatus.environment.last_deployment : {}; + }, + hasEnvironment() { + return !_.isEmpty(this.deploymentStatus.environment); + }, + lastDeploymentPath() { + return !_.isEmpty(this.lastDeployment.deployable) + ? this.lastDeployment.deployable.build_path + : ''; + }, + }, + methods: { + deploymentLink(name) { + return sprintf( + '%{startLink}%{name}%{endLink}', + { + startLink: `<a href="${this.lastDeploymentPath}" class="js-job-deployment-link">`, + name, + endLink: '</a>', + }, + false, + ); }, - }; + }, +}; </script> <template> <div class="prepend-top-default js-environment-container"> diff --git a/app/assets/javascripts/jobs/components/erased_block.vue b/app/assets/javascripts/jobs/components/erased_block.vue index 3d6d9ba4387..5ffbfb6e19a 100644 --- a/app/assets/javascripts/jobs/components/erased_block.vue +++ b/app/assets/javascripts/jobs/components/erased_block.vue @@ -1,28 +1,28 @@ <script> - import _ from 'underscore'; - import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import _ from 'underscore'; +import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; - export default { - components: { - TimeagoTooltip, +export default { + components: { + TimeagoTooltip, + }, + props: { + user: { + type: Object, + required: false, + default: () => ({}), }, - props: { - user: { - type: Object, - required: false, - default: () => ({}), - }, - erasedAt: { - type: String, - required: true, - }, + erasedAt: { + type: String, + required: true, }, - computed: { - isErasedByUser() { - return !_.isEmpty(this.user); - }, + }, + computed: { + isErasedByUser() { + return !_.isEmpty(this.user); }, - }; + }, +}; </script> <template> <div class="prepend-top-default js-build-erased"> diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue index 047e55866ce..4e8d3ad24cc 100644 --- a/app/assets/javascripts/jobs/components/job_app.vue +++ b/app/assets/javascripts/jobs/components/job_app.vue @@ -18,7 +18,7 @@ StuckBlock, }, props: { - runnerHelpUrl: { + runnerSettingsUrl: { type: String, required: false, default: null, @@ -30,7 +30,7 @@ 'headerActions', 'headerTime', 'shouldRenderCalloutMessage', - 'jobHasStarted', + 'shouldRenderTriggeredLabel', 'hasEnvironment', 'isJobStuck', 'hasTrace', @@ -58,7 +58,7 @@ :user="job.user" :actions="headerActions" :has-sidebar-button="true" - :should-render-triggered-label="jobHasStarted" + :should-render-triggered-label="shouldRenderTriggeredLabel" :item-name="__('Job')" /> </div> @@ -76,7 +76,7 @@ class="js-job-stuck" :has-no-runners-for-project="job.runners.available" :tags="job.tags" - :runners-path="runnerHelpUrl" + :runners-path="runnerSettingsUrl" /> <environments-block @@ -87,8 +87,8 @@ /> <erased-block - v-if="job.erased" - class="js-job-erased" + v-if="job.erased_at" + class="js-job-erased-block" :user="job.erased_by" :erased-at="job.erased_at" /> diff --git a/app/assets/javascripts/jobs/components/job_log.vue b/app/assets/javascripts/jobs/components/job_log.vue index b12e963b60c..9d78d89239a 100644 --- a/app/assets/javascripts/jobs/components/job_log.vue +++ b/app/assets/javascripts/jobs/components/job_log.vue @@ -1,17 +1,17 @@ <script> - export default { - name: 'JobLog', - props: { - trace: { - type: String, - required: true, - }, - isComplete: { - type: Boolean, - required: true, - }, +export default { + name: 'JobLog', + props: { + trace: { + type: String, + required: true, }, - }; + isComplete: { + type: Boolean, + required: true, + }, + }, +}; </script> <template> <pre class="build-trace"> diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue index 3e62ababea3..cc885ea8e1b 100644 --- a/app/assets/javascripts/jobs/components/job_log_controllers.vue +++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue @@ -1,72 +1,71 @@ <script> - import { polyfillSticky } from '~/lib/utils/sticky'; - import Icon from '~/vue_shared/components/icon.vue'; - import tooltip from '~/vue_shared/directives/tooltip'; - import { numberToHumanSize } from '~/lib/utils/number_utils'; - import { sprintf } from '~/locale'; +import { polyfillSticky } from '~/lib/utils/sticky'; +import Icon from '~/vue_shared/components/icon.vue'; +import tooltip from '~/vue_shared/directives/tooltip'; +import { numberToHumanSize } from '~/lib/utils/number_utils'; +import { sprintf } from '~/locale'; - export default { - components: { - Icon, +export default { + components: { + Icon, + }, + directives: { + tooltip, + }, + props: { + erasePath: { + type: String, + required: false, + default: null, }, - directives: { - tooltip, + size: { + type: Number, + required: true, }, - props: { - erasePath: { - type: String, - required: false, - default: null, - }, - size: { - type: Number, - required: true, - }, - rawPath: { - type: String, - required: false, - default: null, - }, - isScrollTopDisabled: { - type: Boolean, - required: true, - }, - isScrollBottomDisabled: { - type: Boolean, - required: true, - }, - isScrollingDown: { - type: Boolean, - required: true, - }, - isTraceSizeVisible: { - type: Boolean, - required: true, - }, + rawPath: { + type: String, + required: false, + default: null, }, - computed: { - jobLogSize() { - return sprintf('Showing last %{size} of log -', { - size: numberToHumanSize(this.size), - }); - }, + isScrollTopDisabled: { + type: Boolean, + required: true, }, - mounted() { - polyfillSticky(this.$el); + isScrollBottomDisabled: { + type: Boolean, + required: true, }, - methods: { - handleScrollToTop() { - this.$emit('scrollJobLogTop'); - }, - handleScrollToBottom() { - this.$emit('scrollJobLogBottom'); - }, + isScrollingDown: { + type: Boolean, + required: true, }, - - }; + isTraceSizeVisible: { + type: Boolean, + required: true, + }, + }, + computed: { + jobLogSize() { + return sprintf('Showing last %{size} of log -', { + size: numberToHumanSize(this.size), + }); + }, + }, + mounted() { + polyfillSticky(this.$el); + }, + methods: { + handleScrollToTop() { + this.$emit('scrollJobLogTop'); + }, + handleScrollToBottom() { + this.$emit('scrollJobLogBottom'); + }, + }, +}; </script> <template> - <div class="top-bar"> + <div class="top-bar affix js-top-bar"> <!-- truncate information --> <div class="js-truncated-info truncated-info d-none d-sm-block float-left"> <template v-if="isTraceSizeVisible"> diff --git a/app/assets/javascripts/jobs/components/jobs_container.vue b/app/assets/javascripts/jobs/components/jobs_container.vue index 271b7790d75..03f36ec5c8b 100644 --- a/app/assets/javascripts/jobs/components/jobs_container.vue +++ b/app/assets/javascripts/jobs/components/jobs_container.vue @@ -1,36 +1,36 @@ <script> - import _ from 'underscore'; - import CiIcon from '~/vue_shared/components/ci_icon.vue'; - import Icon from '~/vue_shared/components/icon.vue'; - import tooltip from '~/vue_shared/directives/tooltip'; +import _ from 'underscore'; +import CiIcon from '~/vue_shared/components/ci_icon.vue'; +import Icon from '~/vue_shared/components/icon.vue'; +import tooltip from '~/vue_shared/directives/tooltip'; - export default { - components: { - CiIcon, - Icon, +export default { + components: { + CiIcon, + Icon, + }, + directives: { + tooltip, + }, + props: { + jobs: { + type: Array, + required: true, }, - directives: { - tooltip, + jobId: { + type: Number, + required: true, }, - props: { - jobs: { - type: Array, - required: true, - }, - jobId: { - type: Number, - required: true, - }, + }, + methods: { + isJobActive(currentJobId) { + return this.jobId === currentJobId; }, - methods: { - isJobActive(currentJobId) { - return this.jobId === currentJobId; - }, - tooltipText(job) { - return `${_.escape(job.name)} - ${job.status.tooltip}`; - }, + tooltipText(job) { + return `${_.escape(job.name)} - ${job.status.tooltip}`; }, - }; + }, +}; </script> <template> <div class="js-jobs-container builds-container"> diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue index 22bcd402e72..8f3c6aced23 100644 --- a/app/assets/javascripts/jobs/components/sidebar.vue +++ b/app/assets/javascripts/jobs/components/sidebar.vue @@ -1,116 +1,116 @@ <script> - import _ from 'underscore'; - import { mapActions, mapState } from 'vuex'; - import timeagoMixin from '~/vue_shared/mixins/timeago'; - import { timeIntervalInWords } from '~/lib/utils/datetime_utility'; - import Icon from '~/vue_shared/components/icon.vue'; - import DetailRow from './sidebar_detail_row.vue'; - import ArtifactsBlock from './artifacts_block.vue'; - import TriggerBlock from './trigger_block.vue'; - import CommitBlock from './commit_block.vue'; - import StagesDropdown from './stages_dropdown.vue'; - import JobsContainer from './jobs_container.vue'; +import _ from 'underscore'; +import { mapActions, mapState } from 'vuex'; +import timeagoMixin from '~/vue_shared/mixins/timeago'; +import { timeIntervalInWords } from '~/lib/utils/datetime_utility'; +import Icon from '~/vue_shared/components/icon.vue'; +import DetailRow from './sidebar_detail_row.vue'; +import ArtifactsBlock from './artifacts_block.vue'; +import TriggerBlock from './trigger_block.vue'; +import CommitBlock from './commit_block.vue'; +import StagesDropdown from './stages_dropdown.vue'; +import JobsContainer from './jobs_container.vue'; - export default { - name: 'JobSidebar', - components: { - ArtifactsBlock, - CommitBlock, - DetailRow, - Icon, - TriggerBlock, - StagesDropdown, - JobsContainer, +export default { + name: 'JobSidebar', + components: { + ArtifactsBlock, + CommitBlock, + DetailRow, + Icon, + TriggerBlock, + StagesDropdown, + JobsContainer, + }, + mixins: [timeagoMixin], + props: { + runnerHelpUrl: { + type: String, + required: false, + default: '', }, - mixins: [timeagoMixin], - props: { - runnerHelpUrl: { - type: String, - required: false, - default: '', - }, - terminalPath: { - type: String, - required: false, - default: null, - }, + terminalPath: { + type: String, + required: false, + default: null, }, - computed: { - ...mapState(['job', 'isLoading', 'stages', 'jobs']), - coverage() { - return `${this.job.coverage}%`; - }, - duration() { - return timeIntervalInWords(this.job.duration); - }, - queued() { - return timeIntervalInWords(this.job.queued); - }, - runnerId() { - return `${this.job.runner.description} (#${this.job.runner.id})`; - }, - retryButtonClass() { - let className = - 'js-retry-button float-right btn btn-retry d-none d-md-block d-lg-block d-xl-block'; - className += - this.job.status && this.job.recoverable ? ' btn-primary' : ' btn-inverted-secondary'; - return className; - }, - hasTimeout() { - return this.job.metadata != null && this.job.metadata.timeout_human_readable !== null; - }, - timeout() { - if (this.job.metadata == null) { - return ''; - } + }, + computed: { + ...mapState(['job', 'isLoading', 'stages', 'jobs', 'selectedStage']), + coverage() { + return `${this.job.coverage}%`; + }, + duration() { + return timeIntervalInWords(this.job.duration); + }, + queued() { + return timeIntervalInWords(this.job.queued); + }, + runnerId() { + return `${this.job.runner.description} (#${this.job.runner.id})`; + }, + retryButtonClass() { + let className = + 'js-retry-button float-right btn btn-retry d-none d-md-block d-lg-block d-xl-block'; + className += + this.job.status && this.job.recoverable ? ' btn-primary' : ' btn-inverted-secondary'; + return className; + }, + hasTimeout() { + return this.job.metadata != null && this.job.metadata.timeout_human_readable !== null; + }, + timeout() { + if (this.job.metadata == null) { + return ''; + } - let t = this.job.metadata.timeout_human_readable; - if (this.job.metadata.timeout_source !== '') { - t += ` (from ${this.job.metadata.timeout_source})`; - } + let t = this.job.metadata.timeout_human_readable; + if (this.job.metadata.timeout_source !== '') { + t += ` (from ${this.job.metadata.timeout_source})`; + } - return t; - }, - renderBlock() { - return ( - this.job.merge_request || - this.job.duration || - this.job.finished_data || - this.job.erased_at || - this.job.queued || - this.job.runner || - this.job.coverage || - this.job.tags.length || - this.job.cancel_path - ); - }, - hasArtifact() { - return !_.isEmpty(this.job.artifact); - }, - hasTriggers() { - return !_.isEmpty(this.job.trigger); - }, - hasStages() { - return ( - (this.job && - this.job.pipeline && - this.job.pipeline.stages && - this.job.pipeline.stages.length > 0) || - false - ); - }, - commit() { - return this.job.pipeline.commit || {}; - }, + return t; + }, + renderBlock() { + return ( + this.job.merge_request || + this.job.duration || + this.job.finished_data || + this.job.erased_at || + this.job.queued || + this.job.runner || + this.job.coverage || + this.job.tags.length || + this.job.cancel_path + ); + }, + hasArtifact() { + return !_.isEmpty(this.job.artifact); + }, + hasTriggers() { + return !_.isEmpty(this.job.trigger); + }, + hasStages() { + return ( + (this.job && + this.job.pipeline && + this.job.pipeline.stages && + this.job.pipeline.stages.length > 0) || + false + ); }, - methods: { - ...mapActions(['fetchJobsForStage']), + commit() { + return this.job.pipeline.commit || {}; }, - }; + }, + methods: { + ...mapActions(['fetchJobsForStage']), + }, +}; </script> <template> <aside - class="right-sidebar right-sidebar-expanded build-sidebar" + class="js-build-sidebar right-sidebar right-sidebar-expanded build-sidebar" data-offset-top="101" data-spy="affix" > @@ -276,6 +276,7 @@ <stages-dropdown :stages="stages" :pipeline="job.pipeline" + :selected-stage="selectedStage" @requestSidebarStageDropdown="fetchJobsForStage" /> diff --git a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue index 83560a8ff0e..aeafe98a70b 100644 --- a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue +++ b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue @@ -1,31 +1,31 @@ <script> - export default { - name: 'SidebarDetailRow', - props: { - title: { - type: String, - required: false, - default: '', - }, - value: { - type: String, - required: true, - }, - helpUrl: { - type: String, - required: false, - default: '', - }, +export default { + name: 'SidebarDetailRow', + props: { + title: { + type: String, + required: false, + default: '', }, - computed: { - hasTitle() { - return this.title.length > 0; - }, - hasHelpURL() { - return this.helpUrl.length > 0; - }, + value: { + type: String, + required: true, }, - }; + helpUrl: { + type: String, + required: false, + default: '', + }, + }, + computed: { + hasTitle() { + return this.title.length > 0; + }, + hasHelpURL() { + return this.helpUrl.length > 0; + }, + }, +}; </script> <template> <p class="build-detail-row"> diff --git a/app/assets/javascripts/jobs/components/stages_dropdown.vue b/app/assets/javascripts/jobs/components/stages_dropdown.vue index 1c15af55a8b..e5e1d56e287 100644 --- a/app/assets/javascripts/jobs/components/stages_dropdown.vue +++ b/app/assets/javascripts/jobs/components/stages_dropdown.vue @@ -1,50 +1,39 @@ <script> - import _ from 'underscore'; - import CiIcon from '~/vue_shared/components/ci_icon.vue'; - import Icon from '~/vue_shared/components/icon.vue'; - import { __ } from '~/locale'; +import _ from 'underscore'; +import CiIcon from '~/vue_shared/components/ci_icon.vue'; +import Icon from '~/vue_shared/components/icon.vue'; - export default { - components: { - CiIcon, - Icon, +export default { + components: { + CiIcon, + Icon, + }, + props: { + pipeline: { + type: Object, + required: true, }, - props: { - pipeline: { - type: Object, - required: true, - }, - stages: { - type: Array, - required: true, - }, + stages: { + type: Array, + required: true, }, - data() { - return { - selectedStage: this.stages.length > 0 ? this.stages[0].name : __('More'), - }; + selectedStage: { + type: String, + required: true, }, - computed: { - hasRef() { - return !_.isEmpty(this.pipeline.ref); - }, - }, - watch: { - // When the component is initially mounted it may start with an empty stages array. - // Once the prop is updated, we set the first stage as the selected one - stages(newVal) { - if (newVal.length) { - this.selectedStage = newVal[0].name; - } - }, + }, + + computed: { + hasRef() { + return !_.isEmpty(this.pipeline.ref); }, - methods: { - onStageClick(stage) { - this.$emit('requestSidebarStageDropdown', stage); - this.selectedStage = stage.name; - }, + }, + methods: { + onStageClick(stage) { + this.$emit('requestSidebarStageDropdown', stage); }, - }; + }, +}; </script> <template> <div class="block-last dropdown"> diff --git a/app/assets/javascripts/jobs/components/trigger_block.vue b/app/assets/javascripts/jobs/components/trigger_block.vue index d7b3c4fcb5b..41de4a6e85a 100644 --- a/app/assets/javascripts/jobs/components/trigger_block.vue +++ b/app/assets/javascripts/jobs/components/trigger_block.vue @@ -1,27 +1,27 @@ <script> - export default { - props: { - trigger: { - type: Object, - required: true, - }, +export default { + props: { + trigger: { + type: Object, + required: true, }, - data() { - return { - areVariablesVisible: false, - }; + }, + data() { + return { + areVariablesVisible: false, + }; + }, + computed: { + hasVariables() { + return this.trigger.variables && this.trigger.variables.length > 0; }, - computed: { - hasVariables() { - return this.trigger.variables && this.trigger.variables.length > 0; - }, + }, + methods: { + revealVariables() { + this.areVariablesVisible = true; }, - methods: { - revealVariables() { - this.areVariablesVisible = true; - }, - }, - }; + }, +}; </script> <template> diff --git a/app/assets/javascripts/jobs/job_details_bundle.js b/app/assets/javascripts/jobs/job_details_bundle.js index 3eb75e72506..15cd79b1c50 100644 --- a/app/assets/javascripts/jobs/job_details_bundle.js +++ b/app/assets/javascripts/jobs/job_details_bundle.js @@ -9,8 +9,7 @@ import createStore from './store'; export default () => { const { dataset } = document.getElementById('js-job-details-vue'); - // eslint-disable-next-line no-new - new Job(); + const store = createStore(); store.dispatch('setJobEndpoint', dataset.endpoint); @@ -33,7 +32,7 @@ export default () => { props: { isLoading: this.isLoading, job: this.job, - runnerHelpUrl: dataset.runnerHelpUrl, + runnerSettingsUrl: dataset.runnerSettingsUrl, }, }); }, @@ -71,4 +70,7 @@ export default () => { }); }, }); + + // eslint-disable-next-line no-new + new Job(); }; diff --git a/app/assets/javascripts/jobs/store/actions.js b/app/assets/javascripts/jobs/store/actions.js index 298367c9342..d0040161dc3 100644 --- a/app/assets/javascripts/jobs/store/actions.js +++ b/app/assets/javascripts/jobs/store/actions.js @@ -139,10 +139,12 @@ export const fetchStages = ({ state, dispatch }) => { dispatch('requestStages'); axios - .get(state.job.pipeline.path) + .get(`${state.job.pipeline.path}.json`) .then(({ data }) => { + // Set selected stage dispatch('receiveStagesSuccess', data.details.stages); - dispatch('fetchJobsForStage', data.details.stages[0]); + const selectedStage = data.details.stages.find(stage => stage.name === state.selectedStage); + dispatch('fetchJobsForStage', selectedStage); }) .catch(() => dispatch('receiveStagesError')); }; @@ -156,11 +158,12 @@ export const receiveStagesError = ({ commit }) => { /** * Jobs list on sidebar - depend on stages dropdown */ -export const requestJobsForStage = ({ commit }) => commit(types.REQUEST_JOBS_FOR_STAGE); +export const requestJobsForStage = ({ commit }, stage) => + commit(types.REQUEST_JOBS_FOR_STAGE, stage); // On stage click, set selected stage + fetch job export const fetchJobsForStage = ({ dispatch }, stage) => { - dispatch('requestJobsForStage'); + dispatch('requestJobsForStage', stage); axios .get(stage.dropdown_path, { diff --git a/app/assets/javascripts/jobs/store/getters.js b/app/assets/javascripts/jobs/store/getters.js index afe5f88b292..9f4f372e3d2 100644 --- a/app/assets/javascripts/jobs/store/getters.js +++ b/app/assets/javascripts/jobs/store/getters.js @@ -22,10 +22,10 @@ export const shouldRenderCalloutMessage = state => !_.isEmpty(state.job.status) && !_.isEmpty(state.job.callout_message); /** - * When job has not started the key will be `false` + * When job has not started the key will be null * When job started the key will be a string with a date. */ -export const jobHasStarted = state => !(state.job.started === false); +export const shouldRenderTriggeredLabel = state => _.isString(state.job.started); export const hasEnvironment = state => !_.isEmpty(state.job.deployment_status); diff --git a/app/assets/javascripts/jobs/store/index.js b/app/assets/javascripts/jobs/store/index.js index 96e38f9a2fa..bba01426af7 100644 --- a/app/assets/javascripts/jobs/store/index.js +++ b/app/assets/javascripts/jobs/store/index.js @@ -7,9 +7,10 @@ import mutations from './mutations'; Vue.use(Vuex); -export default () => new Vuex.Store({ - actions, - mutations, - getters, - state: state(), -}); +export default () => + new Vuex.Store({ + actions, + mutations, + getters, + state: state(), + }); diff --git a/app/assets/javascripts/jobs/store/mutations.js b/app/assets/javascripts/jobs/store/mutations.js index c3f2359fa4d..f00e06e1a6c 100644 --- a/app/assets/javascripts/jobs/store/mutations.js +++ b/app/assets/javascripts/jobs/store/mutations.js @@ -53,6 +53,16 @@ export default { state.isLoading = false; state.hasError = false; state.job = job; + + /** + * We only update it on the first request + * The dropdown can be changed by the user + * after the first request, + * and we do not want to hijack that + */ + if (state.selectedStage === 'More' && job.stage) { + state.selectedStage = job.stage; + } }, [types.RECEIVE_JOB_ERROR](state) { state.isLoading = false; @@ -81,8 +91,9 @@ export default { state.stages = []; }, - [types.REQUEST_JOBS_FOR_STAGE](state) { + [types.REQUEST_JOBS_FOR_STAGE](state, stage) { state.isLoadingJobs = true; + state.selectedStage = stage.name; }, [types.RECEIVE_JOBS_FOR_STAGE_SUCCESS](state, jobs) { state.isLoadingJobs = false; diff --git a/app/assets/javascripts/jobs/store/state.js b/app/assets/javascripts/jobs/store/state.js index 509cb69a5d3..afbc959bb71 100644 --- a/app/assets/javascripts/jobs/store/state.js +++ b/app/assets/javascripts/jobs/store/state.js @@ -1,3 +1,5 @@ +import { __ } from '~/locale'; + export default () => ({ jobEndpoint: null, traceEndpoint: null, @@ -34,7 +36,7 @@ export default () => ({ // sidebar dropdown isLoadingStages: false, isLoadingJobs: false, - selectedStage: null, + selectedStage: __('More'), stages: [], jobs: [], }); diff --git a/app/assets/javascripts/label_manager.js b/app/assets/javascripts/label_manager.js index c10b1a2b233..2c995c5902f 100644 --- a/app/assets/javascripts/label_manager.js +++ b/app/assets/javascripts/label_manager.js @@ -1,4 +1,4 @@ -/* eslint-disable class-methods-use-this, no-underscore-dangle, no-param-reassign, no-unused-vars, func-names, max-len */ +/* eslint-disable class-methods-use-this, no-underscore-dangle, no-param-reassign, no-unused-vars, func-names */ import $ from 'jquery'; import Sortable from 'sortablejs'; diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js index 1c7bca78df3..3c38d998b6c 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, max-len, one-var, no-unused-vars, one-var-declaration-per-line, prefer-template, no-new, consistent-return, object-shorthand, comma-dangle, no-shadow, no-param-reassign, brace-style, vars-on-top, quotes, 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, no-unused-vars, 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 */ /* global Issuable */ /* global ListLabel */ @@ -11,6 +11,7 @@ import DropdownUtils from './filtered_search/dropdown_utils'; import CreateLabelDropdown from './create_label'; import flash from './flash'; import ModalStore from './boards/stores/modal_store'; +import boardsStore from './boards/stores/boards_store'; export default class LabelsSelect { constructor(els, options = {}) { @@ -378,7 +379,7 @@ export default class LabelsSelect { } else if ($dropdown.hasClass('js-issue-board-sidebar')) { if ($el.hasClass('is-active')) { - gl.issueBoards.BoardsStore.detail.issue.labels.push(new ListLabel({ + boardsStore.detail.issue.labels.push(new ListLabel({ id: label.id, title: label.title, color: label.color[0], @@ -386,16 +387,16 @@ export default class LabelsSelect { })); } else { - var { labels } = gl.issueBoards.BoardsStore.detail.issue; + var { labels } = boardsStore.detail.issue; labels = labels.filter(function (selectedLabel) { return selectedLabel.id !== label.id; }); - gl.issueBoards.BoardsStore.detail.issue.labels = labels; + boardsStore.detail.issue.labels = labels; } $loading.fadeIn(); - gl.issueBoards.BoardsStore.detail.issue.update($dropdown.attr('data-issue-update')) + boardsStore.detail.issue.update($dropdown.attr('data-issue-update')) .then(fadeOutLoader) .catch(fadeOutLoader); } diff --git a/app/assets/javascripts/lib/utils/ajax_cache.js b/app/assets/javascripts/lib/utils/ajax_cache.js index 616d8952ada..2d976dbdbbe 100644 --- a/app/assets/javascripts/lib/utils/ajax_cache.js +++ b/app/assets/javascripts/lib/utils/ajax_cache.js @@ -4,7 +4,7 @@ import Cache from './cache'; class AjaxCache extends Cache { constructor() { super(); - this.pendingRequests = { }; + this.pendingRequests = {}; } override(endpoint, data) { @@ -19,12 +19,13 @@ class AjaxCache extends Cache { let pendingRequest = this.pendingRequests[endpoint]; if (!pendingRequest) { - pendingRequest = axios.get(endpoint) + pendingRequest = axios + .get(endpoint) .then(({ data }) => { this.internalStorage[endpoint] = data; delete this.pendingRequests[endpoint]; }) - .catch((e) => { + .catch(e => { const error = new Error(`${endpoint}: ${e.message}`); error.textStatus = e.message; diff --git a/app/assets/javascripts/lib/utils/axios_utils.js b/app/assets/javascripts/lib/utils/axios_utils.js index 792871e2ecf..69159e2d741 100644 --- a/app/assets/javascripts/lib/utils/axios_utils.js +++ b/app/assets/javascripts/lib/utils/axios_utils.js @@ -7,7 +7,7 @@ axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; // Maintain a global counter for active requests // see: spec/support/wait_for_requests.rb -axios.interceptors.request.use((config) => { +axios.interceptors.request.use(config => { window.activeVueResources = window.activeVueResources || 0; window.activeVueResources += 1; @@ -15,15 +15,18 @@ axios.interceptors.request.use((config) => { }); // Remove the global counter -axios.interceptors.response.use((config) => { - window.activeVueResources -= 1; - - return config; -}, (e) => { - window.activeVueResources -= 1; - - return Promise.reject(e); -}); +axios.interceptors.response.use( + config => { + window.activeVueResources -= 1; + + return config; + }, + e => { + window.activeVueResources -= 1; + + return Promise.reject(e); + }, +); export default axios; diff --git a/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js b/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js index c28ed04f94f..a24c71aeab1 100644 --- a/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js +++ b/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js @@ -93,9 +93,13 @@ export default class LinkedTabs { const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`; - window.history.replaceState({ - url: newState, - }, document.title, newState); + window.history.replaceState( + { + url: newState, + }, + document.title, + newState, + ); return newState; } diff --git a/app/assets/javascripts/lib/utils/cache.js b/app/assets/javascripts/lib/utils/cache.js index 596bd1e388a..45048145139 100644 --- a/app/assets/javascripts/lib/utils/cache.js +++ b/app/assets/javascripts/lib/utils/cache.js @@ -1,6 +1,6 @@ export default class Cache { constructor() { - this.internalStorage = { }; + this.internalStorage = {}; } get(key) { diff --git a/app/assets/javascripts/lib/utils/datefix.js b/app/assets/javascripts/lib/utils/datefix.js index e98c9068367..19e4085dbbb 100644 --- a/app/assets/javascripts/lib/utils/datefix.js +++ b/app/assets/javascripts/lib/utils/datefix.js @@ -1,12 +1,11 @@ - -export const pad = (val, len = 2) => (`0${val}`).slice(-len); +export const pad = (val, len = 2) => `0${val}`.slice(-len); /** * Formats dates in Pickaday * @param {String} dateString Date in yyyy-mm-dd format * @return {Date} UTC format */ -export const parsePikadayDate = (dateString) => { +export const parsePikadayDate = dateString => { const parts = dateString.split('-'); const year = parseInt(parts[0], 10); const month = parseInt(parts[1] - 1, 10); @@ -20,7 +19,7 @@ export const parsePikadayDate = (dateString) => { * @param {Date} date UTC format * @return {String} Date formated in yyyy-mm-dd */ -export const pikadayToString = (date) => { +export const pikadayToString = date => { const day = pad(date.getDate()); const month = pad(date.getMonth() + 1); const year = date.getFullYear(); diff --git a/app/assets/javascripts/lib/utils/notify.js b/app/assets/javascripts/lib/utils/notify.js index 305ad3e5e26..d93873e0214 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, comma-dangle, max-len */ +/* eslint-disable func-names, no-var, consistent-return, prefer-arrow-callback, no-return-assign, object-shorthand */ function notificationGranted(message, opts, onclick) { var notification; @@ -8,7 +8,7 @@ function notificationGranted(message, opts, onclick) { return notification.close(); }, 8000); - return notification.onclick = onclick || notification.close; + return (notification.onclick = onclick || notification.close); } function notifyPermissions() { @@ -21,7 +21,7 @@ function notifyMe(message, body, icon, onclick) { var opts; opts = { body: body, - icon: icon + icon: icon, }; // Let's check if the browser supports notifications if (!('Notification' in window)) { diff --git a/app/assets/javascripts/lib/utils/pretty_time.js b/app/assets/javascripts/lib/utils/pretty_time.js index b1ffd797f7e..d92b8a7179f 100644 --- a/app/assets/javascripts/lib/utils/pretty_time.js +++ b/app/assets/javascripts/lib/utils/pretty_time.js @@ -27,10 +27,10 @@ export function parseSeconds(seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) let unorderedMinutes = Math.abs(seconds / MINUTES_PER_HOUR); - return _.mapObject(timePeriodConstraints, (minutesPerPeriod) => { + return _.mapObject(timePeriodConstraints, minutesPerPeriod => { const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod); - unorderedMinutes -= (periodCount * minutesPerPeriod); + unorderedMinutes -= periodCount * minutesPerPeriod; return periodCount; }); @@ -42,10 +42,14 @@ export function parseSeconds(seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) */ export function stringifyTime(timeObject) { - const reducedTime = _.reduce(timeObject, (memo, unitValue, unitName) => { - const isNonZero = !!unitValue; - return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo; - }, '').trim(); + const reducedTime = _.reduce( + timeObject, + (memo, unitValue, unitName) => { + const isNonZero = !!unitValue; + return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo; + }, + '', + ).trim(); return reducedTime.length ? reducedTime : '0m'; } @@ -55,7 +59,5 @@ export function stringifyTime(timeObject) { */ export function abbreviateTime(timeStr) { - return timeStr.split(' ') - .filter(unitStr => unitStr.charAt(0) !== '0')[0]; + return timeStr.split(' ').filter(unitStr => unitStr.charAt(0) !== '0')[0]; } - diff --git a/app/assets/javascripts/lib/utils/regexp.js b/app/assets/javascripts/lib/utils/regexp.js index baa0b51d59b..25b60dcd14a 100644 --- a/app/assets/javascripts/lib/utils/regexp.js +++ b/app/assets/javascripts/lib/utils/regexp.js @@ -5,6 +5,7 @@ // Inspired by https://github.com/mishoo/UglifyJS/blob/2bc1d02363db3798d5df41fb5059a19edca9b7eb/lib/parse-js.js#L203 // Unicode 6.1 -const unicodeLetters = '\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0\\u08A2-\\u08AC\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F0\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC'; +const unicodeLetters = + '\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0\\u08A2-\\u08AC\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F0\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC'; export default { unicodeLetters }; diff --git a/app/assets/javascripts/lib/utils/simple_poll.js b/app/assets/javascripts/lib/utils/simple_poll.js index 25ca98afbe7..473f179ad86 100644 --- a/app/assets/javascripts/lib/utils/simple_poll.js +++ b/app/assets/javascripts/lib/utils/simple_poll.js @@ -2,7 +2,7 @@ export default (fn, interval = 2000, timeout = 60000) => { const startTime = Date.now(); return new Promise((resolve, reject) => { - const stop = arg => ((arg instanceof Error) ? reject(arg) : resolve(arg)); + const stop = arg => (arg instanceof Error ? reject(arg) : resolve(arg)); const next = () => { if (Date.now() - startTime < timeout) { setTimeout(fn.bind(null, next, stop), interval); diff --git a/app/assets/javascripts/lib/utils/sticky.js b/app/assets/javascripts/lib/utils/sticky.js index 15a4dd62012..f3244301350 100644 --- a/app/assets/javascripts/lib/utils/sticky.js +++ b/app/assets/javascripts/lib/utils/sticky.js @@ -24,7 +24,11 @@ export const isSticky = (el, scrollY, stickyTop, insertPlaceholder) => { } else if (top > stickyTop && el.classList.contains('is-stuck')) { el.classList.remove('is-stuck'); - if (insertPlaceholder && el.nextElementSibling && el.nextElementSibling.classList.contains('sticky-placeholder')) { + if ( + insertPlaceholder && + el.nextElementSibling && + el.nextElementSibling.classList.contains('sticky-placeholder') + ) { el.nextElementSibling.remove(); } } @@ -42,11 +46,19 @@ export const isSticky = (el, scrollY, stickyTop, insertPlaceholder) => { export const stickyMonitor = (el, stickyTop, insertPlaceholder = true) => { if (!el) return; - if (typeof CSS === 'undefined' || !(CSS.supports('(position: -webkit-sticky) or (position: sticky)'))) return; + if ( + typeof CSS === 'undefined' || + !CSS.supports('(position: -webkit-sticky) or (position: sticky)') + ) + return; - document.addEventListener('scroll', () => isSticky(el, window.scrollY, stickyTop, insertPlaceholder), { - passive: true, - }); + document.addEventListener( + 'scroll', + () => isSticky(el, window.scrollY, stickyTop, insertPlaceholder), + { + passive: true, + }, + ); }; /** @@ -55,6 +67,6 @@ export const stickyMonitor = (el, stickyTop, insertPlaceholder = true) => { * - If the current environment supports `position: sticky`, do nothing. * - Can receive an iterable element list (NodeList, jQuery collection, etc.) or single HTMLElement. */ -export const polyfillSticky = (el) => { +export const polyfillSticky = el => { StickyFill.add(el); }; diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js index f7429601afa..e26a6b986be 100644 --- a/app/assets/javascripts/lib/utils/text_markdown.js +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, no-param-reassign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, max-len, consistent-return, no-unused-vars, max-len */ +/* eslint-disable func-names, no-var, no-param-reassign, one-var, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, consistent-return, no-unused-vars */ import $ from 'jquery'; import { insertText } from '~/lib/utils/common_utils'; @@ -8,12 +8,18 @@ function selectedText(text, textarea) { function lineBefore(text, textarea) { var split; - split = text.substring(0, textarea.selectionStart).trim().split('\n'); + split = text + .substring(0, textarea.selectionStart) + .trim() + .split('\n'); return split[split.length - 1]; } function lineAfter(text, textarea) { - return text.substring(textarea.selectionEnd).trim().split('\n')[0]; + return text + .substring(textarea.selectionEnd) + .trim() + .split('\n')[0]; } function blockTagText(text, textArea, blockTag, selected) { @@ -27,7 +33,7 @@ function blockTagText(text, textArea, blockTag, selected) { } return selected; } else { - return blockTag + "\n" + selected + "\n" + blockTag; + return blockTag + '\n' + selected + '\n' + blockTag; } } @@ -58,7 +64,14 @@ function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) { } export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }) { - var textToInsert, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine; + var textToInsert, + inserted, + selectedSplit, + startChar, + removedLastNewLine, + removedFirstNewLine, + currentLineEmpty, + lastNewLine; removedLastNewLine = false; removedFirstNewLine = false; currentLineEmpty = false; @@ -94,21 +107,23 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr if (blockTag != null && blockTag !== '') { textToInsert = blockTagText(text, textArea, blockTag, selected); } else { - textToInsert = selectedSplit.map(function(val) { - if (tag.indexOf(textPlaceholder) > -1) { - return tag.replace(textPlaceholder, val); - } - if (val.indexOf(tag) === 0) { - return "" + (val.replace(tag, '')); - } else { - return "" + tag + val; - } - }).join('\n'); + textToInsert = selectedSplit + .map(function(val) { + if (tag.indexOf(textPlaceholder) > -1) { + return tag.replace(textPlaceholder, val); + } + if (val.indexOf(tag) === 0) { + return '' + val.replace(tag, ''); + } else { + return '' + tag + val; + } + }) + .join('\n'); } } else if (tag.indexOf(textPlaceholder) > -1) { textToInsert = tag.replace(textPlaceholder, selected); } else { - textToInsert = "" + startChar + tag + selected + (wrap ? tag : ' '); + textToInsert = '' + startChar + tag + selected + (wrap ? tag : ' '); } if (removedFirstNewLine) { @@ -120,7 +135,13 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr } insertText(textArea, textToInsert); - return moveCursor({ textArea, tag: tag.replace(textPlaceholder, selected), wrap, removedLastNewLine, select }); + return moveCursor({ + textArea, + tag: tag.replace(textPlaceholder, selected), + wrap, + removedLastNewLine, + select, + }); } function updateText({ textArea, tag, blockTag, wrap, select }) { @@ -138,15 +159,18 @@ function replaceRange(s, start, end, substitute) { } export function addMarkdownListeners(form) { - return $('.js-md', form).off('click').on('click', function() { - const $this = $(this); - return updateText({ - textArea: $this.closest('.md-area').find('textarea'), - tag: $this.data('mdTag'), - blockTag: $this.data('mdBlock'), - wrap: !$this.data('mdPrepend'), - select: $this.data('mdSelect') }); - }); + return $('.js-md', form) + .off('click') + .on('click', function() { + const $this = $(this); + return updateText({ + textArea: $this.closest('.md-area').find('textarea'), + tag: $this.data('mdTag'), + blockTag: $this.data('mdBlock'), + wrap: !$this.data('mdPrepend'), + select: $this.data('mdSelect'), + }); + }); } export function removeMarkdownListeners(form) { diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index 879f94a26ec..250980919dd 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -8,7 +8,7 @@ * @returns {String} */ export const addDelimiter = text => - (text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') : text); + text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') : text; /** * Returns '99+' for numbers bigger than 99. @@ -94,9 +94,7 @@ export function capitalizeFirstCharacter(text) { * @return {String} */ export function getFirstCharacterCapitalized(text) { - return text - ? text.charAt(0).toUpperCase() - : ''; + return text ? text.charAt(0).toUpperCase() : ''; } /** @@ -136,10 +134,9 @@ export const convertToSentenceCase = string => { * e.g. HelloWorld => Hello World * * @param {*} string -*/ -export const splitCamelCase = string => ( + */ +export const splitCamelCase = string => string - .replace(/([A-Z]+)([A-Z][a-z])/g, ' $1 $2') - .replace(/([a-z\d])([A-Z])/g, '$1 $2') - .trim() -); + .replace(/([A-Z]+)([A-Z][a-z])/g, ' $1 $2') + .replace(/([a-z\d])([A-Z])/g, '$1 $2') + .trim(); diff --git a/app/assets/javascripts/lib/utils/tick_formats.js b/app/assets/javascripts/lib/utils/tick_formats.js index 0c10a85e336..af3ca714400 100644 --- a/app/assets/javascripts/lib/utils/tick_formats.js +++ b/app/assets/javascripts/lib/utils/tick_formats.js @@ -26,7 +26,7 @@ initDateFormats(); see also https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#tickFormat */ -export const dateTickFormat = (date) => { +export const dateTickFormat = date => { if (date.getDate() !== 1) { return dateTimeFormats.dayFormat.format(date); } diff --git a/app/assets/javascripts/lib/utils/users_cache.js b/app/assets/javascripts/lib/utils/users_cache.js index b01ec6b81a3..c0d45e017b4 100644 --- a/app/assets/javascripts/lib/utils/users_cache.js +++ b/app/assets/javascripts/lib/utils/users_cache.js @@ -7,21 +7,20 @@ class UsersCache extends Cache { return Promise.resolve(this.get(username)); } - return Api.users('', { username }) - .then(({ data }) => { - if (!data.length) { - throw new Error(`User "${username}" could not be found!`); - } + return Api.users('', { username }).then(({ data }) => { + if (!data.length) { + throw new Error(`User "${username}" could not be found!`); + } - if (data.length > 1) { - throw new Error(`Expected username "${username}" to be unique!`); - } + if (data.length > 1) { + throw new Error(`Expected username "${username}" to be unique!`); + } - const user = data[0]; - this.internalStorage[username] = user; - return user; - }); - // missing catch is intentional, error handling depends on use case + const user = data[0]; + this.internalStorage[username] = user; + return user; + }); + // missing catch is intentional, error handling depends on use case } } diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js index 291655235d5..d58fd63bb33 100644 --- a/app/assets/javascripts/line_highlighter.js +++ b/app/assets/javascripts/line_highlighter.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, no-underscore-dangle, no-param-reassign, prefer-template, quotes, comma-dangle, consistent-return, one-var, one-var-declaration-per-line, no-else-return, max-len */ +/* eslint-disable func-names, no-var, no-underscore-dangle, no-param-reassign, prefer-template, consistent-return, one-var, no-else-return */ import $ from 'jquery'; 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 81950515ab4..425b806e9d6 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 comma-dangle, quote-props, no-useless-computed-key, object-shorthand, no-param-reassign, max-len */ +/* eslint-disable no-useless-computed-key, object-shorthand, no-param-reassign */ /* global ace */ import Vue from 'vue'; @@ -6,7 +6,7 @@ import axios from '~/lib/utils/axios_utils'; import flash from '~/flash'; import { __ } from '~/locale'; -((global) => { +(global => { global.mergeConflicts = global.mergeConflicts || {}; global.mergeConflicts.diffFileEditor = Vue.extend({ @@ -35,10 +35,10 @@ import { __ } from '~/locale'; computed: { classObject() { return { - 'saved': this.saved, - 'is-loading': this.loading + saved: this.saved, + 'is-loading': this.loading, }; - } + }, }, watch: { ['file.showEditor'](val) { @@ -49,7 +49,7 @@ import { __ } from '~/locale'; } this.loadEditor(); - } + }, }, mounted() { if (this.file.loadEditor) { @@ -60,7 +60,8 @@ import { __ } from '~/locale'; loadEditor() { this.loading = true; - axios.get(this.file.content_path) + axios + .get(this.file.content_path) .then(({ data }) => { const content = this.$el.querySelector('pre'); const fileContent = document.createTextNode(data.content); @@ -101,7 +102,7 @@ import { __ } from '~/locale'; }, acceptDiscardConfirmation(file) { this.onAcceptDiscardConfirmation(file); - } - } + }, + }, }); })(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js b/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js index 69208ac2d36..c2de0379d23 100644 --- a/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js +++ b/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js @@ -4,7 +4,7 @@ import Vue from 'vue'; import actionsMixin from '../mixins/line_conflict_actions'; import utilsMixin from '../mixins/line_conflict_utils'; -((global) => { +(global => { global.mergeConflicts = global.mergeConflicts || {}; global.mergeConflicts.parallelConflictLines = Vue.extend({ diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js index 1501296ac4f..0333335de06 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js +++ b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js @@ -1,10 +1,10 @@ -/* eslint-disable comma-dangle, object-shorthand, no-param-reassign, camelcase, no-nested-ternary, no-continue, max-len */ +/* eslint-disable object-shorthand, no-param-reassign, camelcase, no-nested-ternary, no-continue */ import $ from 'jquery'; import Vue from 'vue'; import Cookies from 'js-cookie'; -((global) => { +(global => { global.mergeConflicts = global.mergeConflicts || {}; const diffViewType = Cookies.get('diff_view'); @@ -17,11 +17,11 @@ import Cookies from 'js-cookie'; const DEFAULT_RESOLVE_MODE = INTERACTIVE_RESOLVE_MODE; const VIEW_TYPES = { INLINE: 'inline', - PARALLEL: 'parallel' + PARALLEL: 'parallel', }; const CONFLICT_TYPES = { TEXT: 'text', - TEXT_EDITOR: 'text-editor' + TEXT_EDITOR: 'text-editor', }; global.mergeConflicts.mergeConflictsStore = { @@ -31,7 +31,7 @@ import Cookies from 'js-cookie'; isSubmitting: false, isParallel: diffViewType === VIEW_TYPES.PARALLEL, diffViewType: diffViewType, - conflictsData: {} + conflictsData: {}, }, setConflictsData(data) { @@ -47,7 +47,7 @@ import Cookies from 'js-cookie'; }, decorateFiles(files) { - files.forEach((file) => { + files.forEach(file => { file.content = ''; file.resolutionData = {}; file.promptDiscardConfirmation = false; @@ -72,7 +72,7 @@ import Cookies from 'js-cookie'; setInlineLine(file) { file.inlineLines = []; - file.sections.forEach((section) => { + file.sections.forEach(section => { let currentLineType = 'new'; const { conflict, lines, id } = section; @@ -80,7 +80,7 @@ import Cookies from 'js-cookie'; file.inlineLines.push(this.getHeadHeaderLine(id)); } - lines.forEach((line) => { + lines.forEach(line => { const { type } = line; if ((type === 'new' || type === 'old') && currentLineType !== type) { @@ -102,7 +102,7 @@ import Cookies from 'js-cookie'; file.parallelLines = []; const linesObj = { left: [], right: [] }; - file.sections.forEach((section) => { + file.sections.forEach(section => { const { conflict, lines, id } = section; if (conflict) { @@ -110,7 +110,7 @@ import Cookies from 'js-cookie'; linesObj.right.push(this.getHeadHeaderLine(id)); } - lines.forEach((line) => { + lines.forEach(line => { const { type } = line; if (conflict) { @@ -131,10 +131,7 @@ import Cookies from 'js-cookie'; }); for (let i = 0, len = linesObj.left.length; i < len; i += 1) { - file.parallelLines.push([ - linesObj.right[i], - linesObj.left[i] - ]); + file.parallelLines.push([linesObj.right[i], linesObj.left[i]]); } }, @@ -159,9 +156,9 @@ import Cookies from 'js-cookie'; const { files } = this.state.conflictsData; let count = 0; - files.forEach((file) => { + files.forEach(file => { if (file.type === CONFLICT_TYPES.TEXT) { - file.sections.forEach((section) => { + file.sections.forEach(section => { if (section.conflict) { count += 1; } @@ -198,7 +195,7 @@ import Cookies from 'js-cookie'; isHeader: true, isHead: true, isSelected: false, - isUnselected: false + isUnselected: false, }; }, @@ -229,7 +226,7 @@ import Cookies from 'js-cookie'; section: isHead ? 'head' : 'origin', richText: rich_text, isSelected: false, - isUnselected: false + isUnselected: false, }; }, @@ -243,7 +240,7 @@ import Cookies from 'js-cookie'; isHeader: true, isOrigin: true, isSelected: false, - isUnselected: false + isUnselected: false, }; }, @@ -290,14 +287,14 @@ import Cookies from 'js-cookie'; }, restoreFileLinesState(file) { - file.inlineLines.forEach((line) => { + file.inlineLines.forEach(line => { if (line.hasConflict || line.isHeader) { line.isSelected = false; line.isUnselected = false; } }); - file.parallelLines.forEach((lines) => { + file.parallelLines.forEach(lines => { const left = lines[0]; const right = lines[1]; const isLeftMatch = left.hasConflict || left.isHeader; @@ -354,7 +351,7 @@ import Cookies from 'js-cookie'; const initial = 'Commit to source branch'; const inProgress = 'Committing...'; - return this.state ? this.state.isSubmitting ? inProgress : initial : initial; + return this.state ? (this.state.isSubmitting ? inProgress : initial) : initial; }, getCommitData() { @@ -362,13 +359,13 @@ import Cookies from 'js-cookie'; commitData = { commit_message: this.state.conflictsData.commitMessage, - files: [] + files: [], }; - this.state.conflictsData.files.forEach((file) => { + this.state.conflictsData.files.forEach(file => { const addFile = { old_path: file.old_path, - new_path: file.new_path + new_path: file.new_path, }; if (file.type === CONFLICT_TYPES.TEXT) { @@ -391,13 +388,13 @@ import Cookies from 'js-cookie'; handleSelected(file, sectionId, selection) { Vue.set(file.resolutionData, sectionId, selection); - file.inlineLines.forEach((line) => { + file.inlineLines.forEach(line => { if (line.id === sectionId && (line.hasConflict || line.isHeader)) { this.markLine(line, selection); } }); - file.parallelLines.forEach((lines) => { + file.parallelLines.forEach(lines => { const left = lines[0]; const right = lines[1]; const hasSameId = right.id === sectionId || left.id === sectionId; @@ -430,6 +427,6 @@ import Cookies from 'js-cookie'; fileTextTypePresent() { return this.state.conflictsData.files.some(f => f.type === CONFLICT_TYPES.TEXT); - } + }, }; })(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index 7bf2c56dd5d..9b6d7d1772f 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, wrap-iife, quotes, no-underscore-dangle, one-var, one-var-declaration-per-line, consistent-return, comma-dangle, max-len, prefer-arrow-callback */ +/* eslint-disable func-names, no-var, no-underscore-dangle, one-var, consistent-return, prefer-arrow-callback */ import $ from 'jquery'; import { __ } from '~/locale'; diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 78f56ab57ff..03f3bb42193 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -18,7 +18,6 @@ import syntaxHighlight from './syntax_highlight'; import Notes from './notes'; import { polyfillSticky } from './lib/utils/sticky'; -/* eslint-disable max-len */ // MergeRequestTabs // // Handles persisting and restoring the current tab selection and lazily-loading @@ -62,7 +61,6 @@ import { polyfillSticky } from './lib/utils/sticky'; // </div> // </div> // -/* eslint-enable max-len */ // Store the `location` object, allowing for easier stubbing in tests let { location } = window; diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index 640a4c8260f..42fb5c7177a 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -1,4 +1,4 @@ -/* eslint-disable max-len, one-var, one-var-declaration-per-line, no-unused-vars, object-shorthand, no-else-return, no-self-compare, consistent-return, no-param-reassign, no-shadow */ +/* eslint-disable one-var, no-unused-vars, object-shorthand, no-else-return, no-self-compare, consistent-return, no-param-reassign, no-shadow */ /* global Issuable */ /* global ListMilestone */ @@ -9,6 +9,7 @@ import '~/gl_dropdown'; import axios from './lib/utils/axios_utils'; import { timeFor } from './lib/utils/datetime_utility'; import ModalStore from './boards/stores/modal_store'; +import boardsStore, { boardStoreIssueSet, boardStoreIssueDelete } from './boards/stores/boards_store'; export default class MilestoneSelect { constructor(currentProject, els, options = {}) { @@ -187,7 +188,7 @@ export default class MilestoneSelect { return $dropdown.closest('form').submit(); } else if ($dropdown.hasClass('js-issue-board-sidebar')) { if (selected.id !== -1 && isSelecting) { - gl.issueBoards.boardStoreIssueSet( + boardStoreIssueSet( 'milestone', new ListMilestone({ id: selected.id, @@ -195,13 +196,13 @@ export default class MilestoneSelect { }), ); } else { - gl.issueBoards.boardStoreIssueDelete('milestone'); + boardStoreIssueDelete('milestone'); } $dropdown.trigger('loading.gl.dropdown'); $loading.removeClass('hidden').fadeIn(); - gl.issueBoards.BoardsStore.detail.issue + boardsStore.detail.issue .update($dropdown.attr('data-issue-update')) .then(() => { $dropdown.trigger('loaded.gl.dropdown'); diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue index 3cccaf72ed7..ed5c8b15945 100644 --- a/app/assets/javascripts/monitoring/components/graph.vue +++ b/app/assets/javascripts/monitoring/components/graph.vue @@ -148,7 +148,7 @@ export default { point = point.matrixTransform(this.$refs.graphData.getScreenCTM().inverse()); point.x += 7; - this.seriesUnderMouse = this.timeSeries.filter((series) => { + this.seriesUnderMouse = this.timeSeries.filter(series => { const mouseX = series.timeSeriesScaleX.invert(point.x); let minDistance = Infinity; @@ -221,21 +221,18 @@ export default { .scale(axisYScale) .ticks(measurements.yTicks); - d3 - .select(this.$refs.baseSvg) + d3.select(this.$refs.baseSvg) .select('.x-axis') .call(xAxis); const width = this.graphWidth; - d3 - .select(this.$refs.baseSvg) + d3.select(this.$refs.baseSvg) .select('.y-axis') .call(yAxis) .selectAll('.tick') .each(function createTickLines(d, i) { if (i > 0) { - d3 - .select(this) + d3.select(this) .select('line') .attr('x2', width) .attr('class', 'axis-tick'); diff --git a/app/assets/javascripts/monitoring/components/graph/axis.vue b/app/assets/javascripts/monitoring/components/graph/axis.vue index 8a604a51eb2..616410ec34f 100644 --- a/app/assets/javascripts/monitoring/components/graph/axis.vue +++ b/app/assets/javascripts/monitoring/components/graph/axis.vue @@ -38,38 +38,25 @@ export default { computed: { textTransform() { const yCoordinate = - (this.graphHeight - - this.margin.top + - this.measurements.axisLabelLineOffset) / - 2 || 0; + (this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 || 0; return `translate(15, ${yCoordinate}) rotate(-90)`; }, rectTransform() { const yCoordinate = - (this.graphHeight - - this.margin.top + - this.measurements.axisLabelLineOffset) / - 2 + + (this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 + this.yLabelWidth / 2 || 0; return `translate(0, ${yCoordinate}) rotate(-90)`; }, xPosition() { - return ( - (this.graphWidth + this.measurements.axisLabelLineOffset) / 2 - - this.margin.right || 0 - ); + return (this.graphWidth + this.measurements.axisLabelLineOffset) / 2 - this.margin.right || 0; }, yPosition() { - return ( - this.graphHeight - - this.margin.top + - this.measurements.axisLabelLineOffset || 0 - ); + return this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset || 0; }, yAxisLabelSentenceCase() { diff --git a/app/assets/javascripts/monitoring/components/graph/flag.vue b/app/assets/javascripts/monitoring/components/graph/flag.vue index 5f00d20ca3f..1720476480e 100644 --- a/app/assets/javascripts/monitoring/components/graph/flag.vue +++ b/app/assets/javascripts/monitoring/components/graph/flag.vue @@ -92,7 +92,8 @@ export default { methods: { seriesMetricValue(seriesIndex, series) { const indexFromCoordinates = this.currentCoordinates[series.metricTag] - ? this.currentCoordinates[series.metricTag].currentDataIndex : 0; + ? this.currentCoordinates[series.metricTag].currentDataIndex + : 0; const index = this.deploymentFlagData ? this.deploymentFlagData.seriesIndex : indexFromCoordinates; diff --git a/app/assets/javascripts/monitoring/components/graph/track_info.vue b/app/assets/javascripts/monitoring/components/graph/track_info.vue index ec1c2222af9..3464067834f 100644 --- a/app/assets/javascripts/monitoring/components/graph/track_info.vue +++ b/app/assets/javascripts/monitoring/components/graph/track_info.vue @@ -26,4 +26,3 @@ export default { {{ summaryMetrics }} </span> </template> - diff --git a/app/assets/javascripts/monitoring/components/graph/track_line.vue b/app/assets/javascripts/monitoring/components/graph/track_line.vue index ba3f93b39ff..e04fd9c1f35 100644 --- a/app/assets/javascripts/monitoring/components/graph/track_line.vue +++ b/app/assets/javascripts/monitoring/components/graph/track_line.vue @@ -33,4 +33,3 @@ export default { </svg> </td> </template> - diff --git a/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js b/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js index 007451d5c7a..87c3d969de4 100644 --- a/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js +++ b/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js @@ -6,7 +6,7 @@ const mixins = { if (!this.reducedDeploymentData) return false; let dataFound = false; - this.reducedDeploymentData = this.reducedDeploymentData.map((d) => { + this.reducedDeploymentData = this.reducedDeploymentData.map(d => { const deployment = d; if (d.xPos >= mouseXPos - 10 && d.xPos <= mouseXPos + 10 && !dataFound) { dataFound = d.xPos + 1; @@ -61,7 +61,7 @@ const mixins = { this.currentCoordinates = {}; - this.seriesUnderMouse.forEach((series) => { + this.seriesUnderMouse.forEach(series => { const currentDataIndex = bisectDate(series.values, this.hoverData.hoveredDate); const currentData = series.values[currentDataIndex]; const currentX = Math.floor(series.timeSeriesScaleX(currentData.time)); diff --git a/app/assets/javascripts/monitoring/services/monitoring_service.js b/app/assets/javascripts/monitoring/services/monitoring_service.js index 260d424378e..24b4acaf6da 100644 --- a/app/assets/javascripts/monitoring/services/monitoring_service.js +++ b/app/assets/javascripts/monitoring/services/monitoring_service.js @@ -8,18 +8,20 @@ const MAX_REQUESTS = 3; function backOffRequest(makeRequestCallback) { let requestCounter = 0; return backOff((next, stop) => { - makeRequestCallback().then((resp) => { - if (resp.status === statusCodes.NO_CONTENT) { - requestCounter += 1; - if (requestCounter < MAX_REQUESTS) { - next(); + makeRequestCallback() + .then(resp => { + if (resp.status === statusCodes.NO_CONTENT) { + requestCounter += 1; + if (requestCounter < MAX_REQUESTS) { + next(); + } else { + stop(new Error('Failed to connect to the prometheus server')); + } } else { - stop(new Error('Failed to connect to the prometheus server')); + stop(resp); } - } else { - stop(resp); - } - }).catch(stop); + }) + .catch(stop); }); } @@ -33,7 +35,7 @@ export default class MonitoringService { getGraphsData() { return backOffRequest(() => axios.get(this.metricsEndpoint)) .then(resp => resp.data) - .then((response) => { + .then(response => { if (!response || !response.data) { throw new Error(s__('Metrics|Unexpected metrics data response from prometheus endpoint')); } @@ -47,22 +49,27 @@ export default class MonitoringService { } return backOffRequest(() => axios.get(this.deploymentEndpoint)) .then(resp => resp.data) - .then((response) => { + .then(response => { if (!response || !response.deployments) { - throw new Error(s__('Metrics|Unexpected deployment data response from prometheus endpoint')); + throw new Error( + s__('Metrics|Unexpected deployment data response from prometheus endpoint'), + ); } return response.deployments; }); } getEnvironmentsData() { - return axios.get(this.environmentsEndpoint) - .then(resp => resp.data) - .then((response) => { - if (!response || !response.environments) { - throw new Error(s__('Metrics|There was an error fetching the environments data, please try again')); - } - return response.environments; - }); + return axios + .get(this.environmentsEndpoint) + .then(resp => resp.data) + .then(response => { + if (!response || !response.environments) { + throw new Error( + s__('Metrics|There was an error fetching the environments data, please try again'), + ); + } + return response.environments; + }); } } diff --git a/app/assets/javascripts/monitoring/utils/measurements.js b/app/assets/javascripts/monitoring/utils/measurements.js index ee866850e13..7c771f43eee 100644 --- a/app/assets/javascripts/monitoring/utils/measurements.js +++ b/app/assets/javascripts/monitoring/utils/measurements.js @@ -1,5 +1,6 @@ export default { - small: { // Covers both xs and sm screen sizes + small: { + // Covers both xs and sm screen sizes margin: { top: 40, right: 40, @@ -18,7 +19,8 @@ export default { }, axisLabelLineOffset: -20, }, - large: { // This covers both md and lg screen sizes + large: { + // This covers both md and lg screen sizes margin: { top: 80, right: 80, diff --git a/app/assets/javascripts/monitoring/utils/multiple_time_series.js b/app/assets/javascripts/monitoring/utils/multiple_time_series.js index d5971730e31..bb24a1acdb3 100644 --- a/app/assets/javascripts/monitoring/utils/multiple_time_series.js +++ b/app/assets/javascripts/monitoring/utils/multiple_time_series.js @@ -66,7 +66,8 @@ function queryTimeSeries(query, graphDrawData, lineStyle) { // offset the same amount as the original data const [minX, maxX] = graphDrawData.xDom; const offset = d3.timeMinute(minX) - Number(minX); - const datesWithoutGaps = d3.timeSecond.every(60) + const datesWithoutGaps = d3.timeSecond + .every(60) .range(d3.timeMinute.offset(minX, -1), maxX) .map(d => d - offset); @@ -208,9 +209,7 @@ export default function createTimeSeries(queries, graphWidth, graphHeight, graph const timeSeries = queries.reduce((series, query, index) => { const lineStyle = defaultStyleOrder[index % defaultStyleOrder.length]; - return series.concat( - queryTimeSeries(query, graphDrawData, lineStyle), - ); + return series.concat(queryTimeSeries(query, graphDrawData, lineStyle)); }, []); return { diff --git a/app/assets/javascripts/namespace_select.js b/app/assets/javascripts/namespace_select.js index 17370edeb0c..ec4c0910e92 100644 --- a/app/assets/javascripts/namespace_select.js +++ b/app/assets/javascripts/namespace_select.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, comma-dangle, object-shorthand, no-else-return, prefer-template, quotes, prefer-arrow-callback, max-len */ +/* eslint-disable func-names, object-shorthand, no-else-return, prefer-template, prefer-arrow-callback */ import $ from 'jquery'; import Api from './api'; diff --git a/app/assets/javascripts/network/branch_graph.js b/app/assets/javascripts/network/branch_graph.js index 94da1be4066..ad7136adb8c 100644 --- a/app/assets/javascripts/network/branch_graph.js +++ b/app/assets/javascripts/network/branch_graph.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, wrap-iife, quotes, comma-dangle, one-var, one-var-declaration-per-line, no-loop-func, no-floating-decimal, consistent-return, no-unused-vars, prefer-template, prefer-arrow-callback, camelcase, max-len */ +/* eslint-disable func-names, no-var, one-var, no-loop-func, consistent-return, no-unused-vars, prefer-template, prefer-arrow-callback, camelcase */ import $ from 'jquery'; import { __ } from '../locale'; diff --git a/app/assets/javascripts/new_branch_form.js b/app/assets/javascripts/new_branch_form.js index 205d9766656..8f6ea9e61c1 100644 --- a/app/assets/javascripts/new_branch_form.js +++ b/app/assets/javascripts/new_branch_form.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, one-var, max-len, wrap-iife, consistent-return, comma-dangle, one-var-declaration-per-line, quotes, no-return-assign, prefer-arrow-callback, prefer-template, no-shadow, no-else-return, max-len */ +/* eslint-disable func-names, no-var, one-var, consistent-return, no-return-assign, prefer-arrow-callback, prefer-template, no-shadow, no-else-return */ import $ from 'jquery'; import RefSelectDropdown from './ref_select_dropdown'; diff --git a/app/assets/javascripts/notebook/cells/code/index.vue b/app/assets/javascripts/notebook/cells/code/index.vue index 7d2a1a33b98..0691ba64f8e 100644 --- a/app/assets/javascripts/notebook/cells/code/index.vue +++ b/app/assets/javascripts/notebook/cells/code/index.vue @@ -1,45 +1,45 @@ <script> - import Prism from '../../lib/highlight'; - import Prompt from '../prompt.vue'; +import Prism from '../../lib/highlight'; +import Prompt from '../prompt.vue'; - export default { - components: { - prompt: Prompt, +export default { + components: { + prompt: Prompt, + }, + props: { + count: { + type: Number, + required: false, + default: 0, }, - props: { - count: { - type: Number, - required: false, - default: 0, - }, - codeCssClass: { - type: String, - required: false, - default: '', - }, - type: { - type: String, - required: true, - }, - rawCode: { - type: String, - required: true, - }, + codeCssClass: { + type: String, + required: false, + default: '', }, - computed: { - code() { - return this.rawCode; - }, - promptType() { - const type = this.type.split('put')[0]; - - return type.charAt(0).toUpperCase() + type.slice(1); - }, + type: { + type: String, + required: true, + }, + rawCode: { + type: String, + required: true, }, - mounted() { - Prism.highlightElement(this.$refs.code); + }, + computed: { + code() { + return this.rawCode; + }, + promptType() { + const type = this.type.split('put')[0]; + + return type.charAt(0).toUpperCase() + type.slice(1); }, - }; + }, + mounted() { + Prism.highlightElement(this.$refs.code); + }, +}; </script> <template> diff --git a/app/assets/javascripts/notebook/cells/markdown.vue b/app/assets/javascripts/notebook/cells/markdown.vue index 3d09d24b6ab..5aa83db0986 100644 --- a/app/assets/javascripts/notebook/cells/markdown.vue +++ b/app/assets/javascripts/notebook/cells/markdown.vue @@ -1,12 +1,12 @@ <script> - /* global katex */ - import marked from 'marked'; - import sanitize from 'sanitize-html'; - import Prompt from './prompt.vue'; +/* global katex */ +import marked from 'marked'; +import sanitize from 'sanitize-html'; +import Prompt from './prompt.vue'; - const renderer = new marked.Renderer(); +const renderer = new marked.Renderer(); - /* +/* Regex to match KaTex blocks. Supports the following: @@ -17,7 +17,7 @@ The matched text then goes through the KaTex renderer & then outputs the HTML */ - const katexRegexString = `( +const katexRegexString = `( ^\\\\begin{[a-zA-Z]+}\\s | ^\\$\\$ @@ -32,66 +32,69 @@ | \\$ ) - `.replace(/\s/g, '').trim(); + ` + .replace(/\s/g, '') + .trim(); - renderer.paragraph = (t) => { - let text = t; - let inline = false; +renderer.paragraph = t => { + let text = t; + let inline = false; - if (typeof katex !== 'undefined') { - const katexString = text.replace(/&/g, '&') - .replace(/&=&/g, '\\space=\\space') - .replace(/<(\/?)em>/g, '_'); - const regex = new RegExp(katexRegexString, 'gi'); - const matchLocation = katexString.search(regex); - const numberOfMatches = katexString.match(regex); + if (typeof katex !== 'undefined') { + const katexString = text + .replace(/&/g, '&') + .replace(/&=&/g, '\\space=\\space') + .replace(/<(\/?)em>/g, '_'); + const regex = new RegExp(katexRegexString, 'gi'); + const matchLocation = katexString.search(regex); + const numberOfMatches = katexString.match(regex); - if (numberOfMatches && numberOfMatches.length !== 0) { - if (matchLocation > 0) { - let matches = regex.exec(katexString); - inline = true; + if (numberOfMatches && numberOfMatches.length !== 0) { + if (matchLocation > 0) { + let matches = regex.exec(katexString); + inline = true; - while (matches !== null) { - const renderedKatex = katex.renderToString(matches[0].replace(/\$/g, '')); - text = `${text.replace(matches[0], ` ${renderedKatex}`)}`; - matches = regex.exec(katexString); - } - } else { - const matches = regex.exec(katexString); - text = katex.renderToString(matches[2]); + while (matches !== null) { + const renderedKatex = katex.renderToString(matches[0].replace(/\$/g, '')); + text = `${text.replace(matches[0], ` ${renderedKatex}`)}`; + matches = regex.exec(katexString); } + } else { + const matches = regex.exec(katexString); + text = katex.renderToString(matches[2]); } } + } - return `<p class="${inline ? 'inline-katex' : ''}">${text}</p>`; - }; + return `<p class="${inline ? 'inline-katex' : ''}">${text}</p>`; +}; - marked.setOptions({ - sanitize: true, - renderer, - }); +marked.setOptions({ + sanitize: true, + renderer, +}); - export default { - components: { - prompt: Prompt, - }, - props: { - cell: { - type: Object, - required: true, - }, +export default { + components: { + prompt: Prompt, + }, + props: { + cell: { + type: Object, + required: true, }, - computed: { - markdown() { - return sanitize(marked(this.cell.source.join('').replace(/\\/g, '\\\\')), { - allowedTags: false, - allowedAttributes: { - '*': ['class'], - }, - }); - }, + }, + computed: { + markdown() { + return sanitize(marked(this.cell.source.join('').replace(/\\/g, '\\\\')), { + allowedTags: false, + allowedAttributes: { + '*': ['class'], + }, + }); }, - }; + }, +}; </script> <template> @@ -105,13 +108,13 @@ </template> <style> - .markdown .katex { - display: block; - text-align: center; - } +.markdown .katex { + display: block; + text-align: center; +} - .markdown .inline-katex .katex { - display: inline; - text-align: initial; - } +.markdown .inline-katex .katex { + display: inline; + text-align: initial; +} </style> diff --git a/app/assets/javascripts/notebook/cells/output/html.vue b/app/assets/javascripts/notebook/cells/output/html.vue index 0535ee7afa8..c6fc786fa76 100644 --- a/app/assets/javascripts/notebook/cells/output/html.vue +++ b/app/assets/javascripts/notebook/cells/output/html.vue @@ -1,30 +1,28 @@ <script> - import sanitize from 'sanitize-html'; - import Prompt from '../prompt.vue'; +import sanitize from 'sanitize-html'; +import Prompt from '../prompt.vue'; - export default { - components: { - prompt: Prompt, +export default { + components: { + prompt: Prompt, + }, + props: { + rawCode: { + type: String, + required: true, }, - props: { - rawCode: { - type: String, - required: true, - }, + }, + computed: { + sanitizedOutput() { + return sanitize(this.rawCode, { + allowedTags: sanitize.defaults.allowedTags.concat(['img', 'svg']), + allowedAttributes: { + img: ['src'], + }, + }); }, - computed: { - sanitizedOutput() { - return sanitize(this.rawCode, { - allowedTags: sanitize.defaults.allowedTags.concat([ - 'img', 'svg', - ]), - allowedAttributes: { - img: ['src'], - }, - }); - }, - }, - }; + }, +}; </script> <template> diff --git a/app/assets/javascripts/notebook/cells/output/image.vue b/app/assets/javascripts/notebook/cells/output/image.vue index 67d6c5ad12b..a17868963ce 100644 --- a/app/assets/javascripts/notebook/cells/output/image.vue +++ b/app/assets/javascripts/notebook/cells/output/image.vue @@ -1,21 +1,21 @@ <script> - import Prompt from '../prompt.vue'; +import Prompt from '../prompt.vue'; - export default { - components: { - prompt: Prompt, +export default { + components: { + prompt: Prompt, + }, + props: { + outputType: { + type: String, + required: true, }, - props: { - outputType: { - type: String, - required: true, - }, - rawCode: { - type: String, - required: true, - }, + rawCode: { + type: String, + required: true, }, - }; + }, +}; </script> <template> diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue index 4183b976814..d9f8604ed10 100644 --- a/app/assets/javascripts/notebook/cells/output/index.vue +++ b/app/assets/javascripts/notebook/cells/output/index.vue @@ -1,78 +1,78 @@ <script> - import CodeCell from '../code/index.vue'; - import Html from './html.vue'; - import Image from './image.vue'; +import CodeCell from '../code/index.vue'; +import Html from './html.vue'; +import Image from './image.vue'; - export default { - components: { - 'code-cell': CodeCell, - 'html-output': Html, - 'image-output': Image, +export default { + components: { + 'code-cell': CodeCell, + 'html-output': Html, + 'image-output': Image, + }, + props: { + codeCssClass: { + type: String, + required: false, + default: '', }, - props: { - codeCssClass: { - type: String, - required: false, - default: '', - }, - count: { - type: Number, - required: false, - default: 0, - }, - output: { - type: Object, - requred: true, - default: () => ({}), - }, + count: { + type: Number, + required: false, + default: 0, }, - computed: { - componentName() { - if (this.output.text) { - return 'code-cell'; - } else if (this.output.data['image/png']) { - return 'image-output'; - } else if (this.output.data['text/html']) { - return 'html-output'; - } else if (this.output.data['image/svg+xml']) { - return 'html-output'; - } - + output: { + type: Object, + requred: true, + default: () => ({}), + }, + }, + computed: { + componentName() { + if (this.output.text) { return 'code-cell'; - }, - rawCode() { - if (this.output.text) { - return this.output.text.join(''); - } + } else if (this.output.data['image/png']) { + return 'image-output'; + } else if (this.output.data['text/html']) { + return 'html-output'; + } else if (this.output.data['image/svg+xml']) { + return 'html-output'; + } - return this.dataForType(this.outputType); - }, - outputType() { - if (this.output.text) { - return ''; - } else if (this.output.data['image/png']) { - return 'image/png'; - } else if (this.output.data['text/html']) { - return 'text/html'; - } else if (this.output.data['image/svg+xml']) { - return 'image/svg+xml'; - } + return 'code-cell'; + }, + rawCode() { + if (this.output.text) { + return this.output.text.join(''); + } + + return this.dataForType(this.outputType); + }, + outputType() { + if (this.output.text) { + return ''; + } else if (this.output.data['image/png']) { + return 'image/png'; + } else if (this.output.data['text/html']) { + return 'text/html'; + } else if (this.output.data['image/svg+xml']) { + return 'image/svg+xml'; + } - return 'text/plain'; - }, + return 'text/plain'; }, - methods: { - dataForType(type) { - let data = this.output.data[type]; + }, + methods: { + dataForType(type) { + let data = this.output.data[type]; - if (typeof data === 'object') { - data = data.join(''); - } + if (typeof data === 'object') { + data = data.join(''); + } - return data; - }, + return data; }, - }; + }, +}; </script> <template> diff --git a/app/assets/javascripts/notebook/cells/prompt.vue b/app/assets/javascripts/notebook/cells/prompt.vue index fe1fc37e1dc..d96f701ee3e 100644 --- a/app/assets/javascripts/notebook/cells/prompt.vue +++ b/app/assets/javascripts/notebook/cells/prompt.vue @@ -1,23 +1,23 @@ <script> - export default { - props: { - type: { - type: String, - required: false, - default: '', - }, - count: { - type: Number, - required: false, - default: 0, - }, +export default { + props: { + type: { + type: String, + required: false, + default: '', }, - computed: { - hasKeys() { - return this.type !== '' && this.count; - }, + count: { + type: Number, + required: false, + default: 0, }, - }; + }, + computed: { + hasKeys() { + return this.type !== '' && this.count; + }, + }, +}; </script> <template> @@ -29,9 +29,9 @@ </template> <style scoped> - .prompt { - padding: 0 10px; - min-width: 7em; - font-family: monospace; - } +.prompt { + padding: 0 10px; + min-width: 7em; + font-family: monospace; +} </style> diff --git a/app/assets/javascripts/notebook/index.vue b/app/assets/javascripts/notebook/index.vue index f241df9620d..c5cc8c97dda 100644 --- a/app/assets/javascripts/notebook/index.vue +++ b/app/assets/javascripts/notebook/index.vue @@ -1,51 +1,48 @@ <script> - import { - MarkdownCell, - CodeCell, - } from './cells'; +import { MarkdownCell, CodeCell } from './cells'; - export default { - components: { - 'code-cell': CodeCell, - 'markdown-cell': MarkdownCell, +export default { + components: { + 'code-cell': CodeCell, + 'markdown-cell': MarkdownCell, + }, + props: { + notebook: { + type: Object, + required: true, }, - props: { - notebook: { - type: Object, - required: true, - }, - codeCssClass: { - type: String, - required: false, - default: '', - }, + codeCssClass: { + type: String, + required: false, + default: '', }, - computed: { - cells() { - if (this.notebook.worksheets) { - const data = { - cells: [], - }; + }, + computed: { + cells() { + if (this.notebook.worksheets) { + const data = { + cells: [], + }; - return this.notebook.worksheets.reduce((cellData, sheet) => { - const cellDataCopy = cellData; - cellDataCopy.cells = cellDataCopy.cells.concat(sheet.cells); - return cellDataCopy; - }, data).cells; - } + return this.notebook.worksheets.reduce((cellData, sheet) => { + const cellDataCopy = cellData; + cellDataCopy.cells = cellDataCopy.cells.concat(sheet.cells); + return cellDataCopy; + }, data).cells; + } - return this.notebook.cells; - }, - hasNotebook() { - return Object.keys(this.notebook).length; - }, + return this.notebook.cells; }, - methods: { - cellType(type) { - return `${type}-cell`; - }, + hasNotebook() { + return Object.keys(this.notebook).length; }, - }; + }, + methods: { + cellType(type) { + return `${type}-cell`; + }, + }, +}; </script> <template> diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index f301f093ef4..1369b5820d5 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -1,5 +1,5 @@ -/* eslint-disable no-restricted-properties, func-names, no-var, wrap-iife, camelcase, -no-unused-expressions, max-len, one-var, one-var-declaration-per-line, default-case, +/* eslint-disable no-restricted-properties, func-names, no-var, camelcase, +no-unused-expressions, one-var, default-case, prefer-template, consistent-return, no-alert, no-return-assign, no-param-reassign, prefer-arrow-callback, no-else-return, vars-on-top, no-unused-vars, no-shadow, no-useless-escape, class-methods-use-this */ diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue index 353aa790743..d9e99603238 100644 --- a/app/assets/javascripts/notes/components/diff_with_note.vue +++ b/app/assets/javascripts/notes/components/diff_with_note.vue @@ -94,6 +94,7 @@ export default { class="diff-file file-holder" > <diff-file-header + :discussion-path="discussion.discussionPath" :diff-file="diffFile" :can-current-user-fork="false" :discussions-expanded="isDiscussionsExpanded" diff --git a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors.js b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors.js index 6c1788dc160..58bb8c5b0c8 100644 --- a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors.js +++ b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign */ +/* eslint-disable func-names, no-var, one-var, camelcase, no-param-reassign, prefer-template, no-return-assign */ import $ from 'jquery'; import _ from 'underscore'; diff --git a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js index a02ec9e5f00..5f91686347a 100644 --- a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js +++ b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, max-len, no-restricted-syntax, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return, no-shadow */ +/* eslint-disable func-names, no-restricted-syntax, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, no-return-assign, prefer-arrow-callback, prefer-template, no-else-return, no-shadow */ import $ from 'jquery'; import _ from 'underscore'; 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 d12249bf612..cd0e2bc023c 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,4 +1,4 @@ -/* eslint-disable func-names, object-shorthand, no-var, one-var, camelcase, one-var-declaration-per-line, comma-dangle, no-param-reassign, no-return-assign, quotes, prefer-arrow-callback, wrap-iife, consistent-return, no-unused-vars, max-len, no-cond-assign, no-else-return, max-len */ +/* eslint-disable func-names, object-shorthand, no-var, one-var, camelcase, no-param-reassign, no-return-assign, prefer-arrow-callback, consistent-return, no-unused-vars, no-cond-assign, no-else-return */ import _ from 'underscore'; export default { diff --git a/app/assets/javascripts/pages/projects/network/network.js b/app/assets/javascripts/pages/projects/network/network.js index 77368c47451..70fbb3f301c 100644 --- a/app/assets/javascripts/pages/projects/network/network.js +++ b/app/assets/javascripts/pages/projects/network/network.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, wrap-iife, no-var, quotes, quote-props, prefer-template, comma-dangle, max-len */ +/* eslint-disable func-names, no-var, prefer-template */ import $ from 'jquery'; import BranchGraph from '../../../network/branch_graph'; diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js index 34a13eb3251..52d66beefc9 100644 --- a/app/assets/javascripts/pages/projects/project.js +++ b/app/assets/javascripts/pages/projects/project.js @@ -1,5 +1,4 @@ -/* eslint-disable func-names, no-var, no-return-assign, one-var, - one-var-declaration-per-line, object-shorthand, vars-on-top */ +/* eslint-disable func-names, no-var, no-return-assign, one-var, object-shorthand, vars-on-top */ import $ from 'jquery'; import Cookies from 'js-cookie'; diff --git a/app/assets/javascripts/pages/sessions/new/username_validator.js b/app/assets/javascripts/pages/sessions/new/username_validator.js index 97cf1aeaadc..d621f988d86 100644 --- a/app/assets/javascripts/pages/sessions/new/username_validator.js +++ b/app/assets/javascripts/pages/sessions/new/username_validator.js @@ -1,4 +1,4 @@ -/* eslint-disable comma-dangle, consistent-return, class-methods-use-this */ +/* eslint-disable consistent-return, class-methods-use-this */ import $ from 'jquery'; import _ from 'underscore'; diff --git a/app/assets/javascripts/pipelines/components/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_table.vue index 0d7324f3fb5..cb14d4400d1 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_table.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_table.vue @@ -35,7 +35,7 @@ export default { }, data() { return { - pipelineId: '', + pipelineId: 0, endpoint: '', cancelingPipeline: null, }; diff --git a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue index 09ee190b8ca..b03438ddba1 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue @@ -47,7 +47,7 @@ export default { required: true, }, cancelingPipeline: { - type: String, + type: Number, required: false, default: null, }, diff --git a/app/assets/javascripts/profile/gl_crop.js b/app/assets/javascripts/profile/gl_crop.js index f641b23e519..af134881f31 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, max-len, no-var, no-underscore-dangle, func-names, no-unused-vars, no-return-assign, object-shorthand, one-var, one-var-declaration-per-line, comma-dangle, consistent-return, class-methods-use-this, new-parens */ +/* eslint-disable no-useless-escape, no-var, no-underscore-dangle, func-names, no-unused-vars, no-return-assign, object-shorthand, one-var, consistent-return, class-methods-use-this */ import $ from 'jquery'; import 'cropper'; diff --git a/app/assets/javascripts/project_find_file.js b/app/assets/javascripts/project_find_file.js index 05485e352dc..12cfa7de316 100644 --- a/app/assets/javascripts/project_find_file.js +++ b/app/assets/javascripts/project_find_file.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, wrap-iife, quotes, consistent-return, one-var, one-var-declaration-per-line, no-cond-assign, max-len, prefer-template, no-unused-vars, no-return-assign */ +/* eslint-disable func-names, no-var, consistent-return, one-var, no-cond-assign, prefer-template, no-unused-vars, no-return-assign */ import $ from 'jquery'; import fuzzaldrinPlus from 'fuzzaldrin-plus'; diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js index 6f3b32f8eea..eaaeda8b339 100644 --- a/app/assets/javascripts/project_select.js +++ b/app/assets/javascripts/project_select.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, wrap-iife, no-var, comma-dangle, object-shorthand, one-var, one-var-declaration-per-line, no-else-return, quotes, max-len */ +/* eslint-disable func-names, no-var, object-shorthand, one-var, no-else-return */ import $ from 'jquery'; import Api from './api'; diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js index b27d635c6ac..64f3dde5be7 100644 --- a/app/assets/javascripts/right_sidebar.js +++ b/app/assets/javascripts/right_sidebar.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, no-var, no-unused-vars, consistent-return, one-var, one-var-declaration-per-line, quotes, prefer-template, no-else-return, no-param-reassign, max-len */ +/* eslint-disable func-names, no-var, no-unused-vars, consistent-return, one-var, prefer-template, no-else-return, no-param-reassign */ import $ from 'jquery'; import _ from 'underscore'; diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js index 50dd3c12382..7bde4860973 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, one-var-declaration-per-line, no-unused-vars, consistent-return, object-shorthand, prefer-template, class-methods-use-this, no-lonely-if, vars-on-top, max-len */ +/* eslint-disable no-return-assign, one-var, no-var, no-unused-vars, consistent-return, object-shorthand, prefer-template, class-methods-use-this, no-lonely-if, vars-on-top */ import $ from 'jquery'; import { escape, throttle } from 'underscore'; diff --git a/app/assets/javascripts/templates/issuable_template_selector.js b/app/assets/javascripts/templates/issuable_template_selector.js index 6fea03af46a..74166313940 100644 --- a/app/assets/javascripts/templates/issuable_template_selector.js +++ b/app/assets/javascripts/templates/issuable_template_selector.js @@ -1,4 +1,4 @@ -/* eslint-disable no-useless-return, max-len */ +/* eslint-disable no-useless-return */ import $ from 'jquery'; import Api from '../api'; diff --git a/app/assets/javascripts/tree.js b/app/assets/javascripts/tree.js index 85123a63a45..066fd6278a7 100644 --- a/app/assets/javascripts/tree.js +++ b/app/assets/javascripts/tree.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, max-len, quotes, consistent-return, no-var, one-var, one-var-declaration-per-line, no-else-return, prefer-arrow-callback, class-methods-use-this */ +/* eslint-disable func-names, consistent-return, no-var, one-var, no-else-return, prefer-arrow-callback, class-methods-use-this */ import $ from 'jquery'; import { visitUrl } from './lib/utils/url_utility'; diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index b9dfa22dd49..e2259a8d07b 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, quotes, max-len, one-var-declaration-per-line, vars-on-top, prefer-arrow-callback, consistent-return, comma-dangle, object-shorthand, no-shadow, no-unused-vars, no-else-return, no-self-compare, prefer-template, no-unused-expressions, yoda, prefer-spread, no-void, camelcase, no-param-reassign */ +/* eslint-disable func-names, one-var, no-var, prefer-rest-params, vars-on-top, prefer-arrow-callback, consistent-return, object-shorthand, no-shadow, no-unused-vars, no-else-return, no-self-compare, prefer-template, no-unused-expressions, yoda, prefer-spread, no-void, camelcase, no-param-reassign */ /* global Issuable */ /* global emitSidebarEvent */ diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue index 8184ef33022..c19b67f00fa 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue @@ -162,18 +162,20 @@ <span class="label-branch"> <a :href="mr.targetBranchPath">{{ mr.targetBranch }}</a> </span> - with - <a - :href="mr.mergeCommitPath" - class="commit-sha js-mr-merged-commit-sha" - v-text="mr.shortMergeCommitSha" - > - </a> - <clipboard-button - :title="__('Copy commit SHA to clipboard')" - :text="mr.mergeCommitSha" - css-class="btn-default btn-transparent btn-clipboard js-mr-merged-copy-sha" - /> + <template v-if="mr.mergeCommitSha"> + with + <a + :href="mr.mergeCommitPath" + class="commit-sha js-mr-merged-commit-sha" + v-text="mr.shortMergeCommitSha" + > + </a> + <clipboard-button + :title="__('Copy commit SHA to clipboard')" + :text="mr.mergeCommitSha" + css-class="btn-default btn-transparent btn-clipboard js-mr-merged-copy-sha" + /> + </template> </p> <p v-if="mr.sourceBranchRemoved"> {{ s__("mrWidget|The source branch has been removed") }} diff --git a/app/assets/javascripts/vue_shared/components/gl_modal.vue b/app/assets/javascripts/vue_shared/components/gl_modal.vue index b023c5cfeb1..b5444d43ded 100644 --- a/app/assets/javascripts/vue_shared/components/gl_modal.vue +++ b/app/assets/javascripts/vue_shared/components/gl_modal.vue @@ -41,10 +41,14 @@ export default { }, }, mounted() { - $(this.$el).on('shown.bs.modal', this.opened).on('hidden.bs.modal', this.closed); + $(this.$el) + .on('shown.bs.modal', this.opened) + .on('hidden.bs.modal', this.closed); }, beforeDestroy() { - $(this.$el).off('shown.bs.modal', this.opened).off('hidden.bs.modal', this.closed); + $(this.$el) + .off('shown.bs.modal', this.opened) + .off('hidden.bs.modal', this.closed); }, methods: { emitCancel(event) { @@ -103,7 +107,7 @@ export default { <slot name="footer"> <button type="button" - class="btn js-modal-cancel-action" + class="btn js-modal-cancel-action qa-modal-cancel-button" data-dismiss="modal" @click="emitCancel($event)" > @@ -112,7 +116,7 @@ export default { <button :class="`btn-${footerPrimaryButtonVariant}`" type="button" - class="btn js-modal-primary-action" + class="btn js-modal-primary-action qa-modal-primary-button" data-dismiss="modal" @click="emitSubmit($event)" > diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js index 0138c9be803..bdb2351c344 100644 --- a/app/assets/javascripts/zen_mode.js +++ b/app/assets/javascripts/zen_mode.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, wrap-iife, prefer-arrow-callback, no-unused-vars, consistent-return, camelcase, comma-dangle, max-len, class-methods-use-this */ +/* eslint-disable func-names, prefer-arrow-callback, no-unused-vars, consistent-return, camelcase, class-methods-use-this */ // Zen Mode (full screen) textarea // diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index ffe65ce780e..bd1cca69c03 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -17,7 +17,7 @@ */ @import "../../../node_modules/pikaday/scss/pikaday"; -@import "../../../node_modules/dropzone/dist/basic.css"; +@import "../../../node_modules/dropzone/dist/basic"; /* * GitLab UI framework diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index be41dbfc61f..1c84baf68ed 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -12,6 +12,15 @@ max-width: $max-width; } +/** + * Mixin for fixed width container + */ +@mixin fixed-width-container { + max-width: $limited-layout-width - ($gl-padding * 2); + margin-left: auto; + margin-right: auto; +} + /* * Mixin for markdown tables */ diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index 17b02c6e31e..cba5324ce53 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -1046,3 +1046,19 @@ left: auto; line-height: 0; } + +@media (max-width: map-get($grid-breakpoints, md)-1) { + .diffs .files { + @include fixed-width-container; + flex-direction: column; + + .diff-tree-list { + width: 100%; + } + + .tree-list-holder { + max-height: calc(50px + 50vh); + padding-right: 0; + } + } +} diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 62a9f97caa9..00b06aea898 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -1,8 +1,6 @@ // Limit MR description for side-by-side diff view .fixed-width-container { - max-width: $limited-layout-width - ($gl-padding * 2); - margin-left: auto; - margin-right: auto; + @include fixed-width-container; } .issuable-warning-icon { diff --git a/app/controllers/admin/health_check_controller.rb b/app/controllers/admin/health_check_controller.rb index 44864f9c7d0..25cc241e5b0 100644 --- a/app/controllers/admin/health_check_controller.rb +++ b/app/controllers/admin/health_check_controller.rb @@ -3,12 +3,5 @@ class Admin::HealthCheckController < Admin::ApplicationController def show @errors = HealthCheck::Utils.process_checks(['standard']) - @failing_storage_statuses = Gitlab::Git::Storage::Health.for_failing_storages - end - - def reset_storage_health - Gitlab::Git::Storage::FailureInfo.reset_all! - redirect_to admin_health_check_path, - notice: _('Git storage health information has been reset') end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ec45e2813c5..bbeaeb7694e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -66,7 +66,7 @@ class ApplicationController < ActionController::Base head :forbidden, retry_after: Gitlab::Auth::UniqueIpsLimiter.config.unique_ips_limit_time_window end - rescue_from Gitlab::Git::Storage::Inaccessible, GRPC::Unavailable, Gitlab::Git::CommandError do |exception| + rescue_from GRPC::Unavailable, Gitlab::Git::CommandError do |exception| log_exception(exception) headers['Retry-After'] = exception.retry_after if exception.respond_to?(:retry_after) diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb index ab4bc911e17..dc9a52f8da5 100644 --- a/app/controllers/health_controller.rb +++ b/app/controllers/health_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class HealthController < ActionController::Base - protect_from_forgery with: :exception, except: :storage_check, prepend: true + protect_from_forgery with: :exception, prepend: true include RequiresWhitelistedMonitoringClient CHECKS = [ @@ -25,15 +25,6 @@ class HealthController < ActionController::Base render_check_results(results) end - def storage_check - results = Gitlab::Git::Storage::Checker.check_all - - render json: { - check_interval: Gitlab::CurrentSettings.current_application_settings.circuitbreaker_check_interval, - results: results - } - end - private def render_check_results(results) diff --git a/app/finders/branches_finder.rb b/app/finders/branches_finder.rb index 970efa79dfb..45d5591e81b 100644 --- a/app/finders/branches_finder.rb +++ b/app/finders/branches_finder.rb @@ -7,8 +7,9 @@ class BranchesFinder end def execute - branches = @repository.branches_sorted_by(sort) - filter_by_name(branches) + branches = repository.branches_sorted_by(sort) + branches = by_search(branches) + branches end private @@ -23,11 +24,39 @@ class BranchesFinder @params[:sort].presence || 'name' end - def filter_by_name(branches) - if search - branches.select { |branch| branch.name.upcase.include?(search.upcase) } + def by_search(branches) + return branches unless search + + case search + when ->(v) { v.starts_with?('^') } + filter_branches_with_prefix(branches, search.slice(1..-1).upcase) + when ->(v) { v.ends_with?('$') } + filter_branches_with_suffix(branches, search.chop.upcase) else - branches + matches = filter_branches_by_name(branches, search.upcase) + set_exact_match_as_first_result(matches, search) end end + + def filter_branches_with_prefix(branches, prefix) + branches.select { |branch| branch.name.upcase.starts_with?(prefix) } + end + + def filter_branches_with_suffix(branches, suffix) + branches.select { |branch| branch.name.upcase.ends_with?(suffix) } + end + + def filter_branches_by_name(branches, term) + branches.select { |branch| branch.name.upcase.include?(term) } + end + + def set_exact_match_as_first_result(matches, term) + exact_match_index = find_exact_match_index(matches, term) + matches.insert(0, matches.delete_at(exact_match_index)) if exact_match_index + matches + end + + def find_exact_match_index(matches, term) + matches.index { |branch| branch.name.casecmp(term) == 0 } + end end diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb index c2404412006..6ececcd4152 100644 --- a/app/finders/projects_finder.rb +++ b/app/finders/projects_finder.rb @@ -42,17 +42,7 @@ class ProjectsFinder < UnionFinder init_collection end - collection = by_ids(collection) - collection = by_personal(collection) - collection = by_starred(collection) - collection = by_trending(collection) - collection = by_visibilty_level(collection) - collection = by_tags(collection) - collection = by_search(collection) - collection = by_archived(collection) - collection = by_custom_attributes(collection) - collection = by_deleted_status(collection) - + collection = filter_projects(collection) sort(collection) end @@ -66,6 +56,21 @@ class ProjectsFinder < UnionFinder end end + # EE would override this to add more filters + def filter_projects(collection) + collection = by_ids(collection) + collection = by_personal(collection) + collection = by_starred(collection) + collection = by_trending(collection) + collection = by_visibilty_level(collection) + collection = by_tags(collection) + collection = by_search(collection) + collection = by_archived(collection) + collection = by_custom_attributes(collection) + collection = by_deleted_status(collection) + collection + end + # rubocop: disable CodeReuse/ActiveRecord def collection_with_user if owned_projects? diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 15cbfeea609..d6753e46165 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -108,37 +108,6 @@ module ApplicationSettingsHelper options_for_select(options, selected) end - def circuitbreaker_failure_count_help_text - health_link = link_to(s_('AdminHealthPageLink|health page'), admin_health_check_path) - api_link = link_to(s_('CircuitBreakerApiLink|circuitbreaker api'), help_page_path("api/repository_storage_health")) - message = _("The number of failures of after which GitLab will completely "\ - "prevent access to the storage. The number of failures can be "\ - "reset in the admin interface: %{link_to_health_page} or using "\ - "the %{api_documentation_link}.") - message = message % { link_to_health_page: health_link, api_documentation_link: api_link } - - message.html_safe - end - - def circuitbreaker_access_retries_help_text - _('The number of attempts GitLab will make to access a storage.') - end - - def circuitbreaker_failure_reset_time_help_text - _("The time in seconds GitLab will keep failure information. When no "\ - "failures occur during this time, information about the mount is reset.") - end - - def circuitbreaker_storage_timeout_help_text - _("The time in seconds GitLab will try to access storage. After this time a "\ - "timeout error will be raised.") - end - - def circuitbreaker_check_interval_help_text - _("The time in seconds between storage checks. When a previous check did "\ - "complete yet, GitLab will skip a check.") - end - def visible_attributes [ :admin_notification_email, @@ -150,11 +119,6 @@ module ApplicationSettingsHelper :authorized_keys_enabled, :auto_devops_enabled, :auto_devops_domain, - :circuitbreaker_access_retries, - :circuitbreaker_check_interval, - :circuitbreaker_failure_count_threshold, - :circuitbreaker_failure_reset_time, - :circuitbreaker_storage_timeout, :clientside_sentry_dsn, :clientside_sentry_enabled, :container_registry_token_expire_delay, diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb index ff9842d4cd9..f4f46b0fe96 100644 --- a/app/helpers/preferences_helper.rb +++ b/app/helpers/preferences_helper.rb @@ -18,22 +18,20 @@ module PreferencesHelper groups: _("Your Groups"), todos: _("Your Todos"), issues: _("Assigned Issues"), - merge_requests: _("Assigned Merge Requests") + merge_requests: _("Assigned Merge Requests"), + operations: _("Operations Dashboard") }.with_indifferent_access.freeze # Returns an Array usable by a select field for more user-friendly option text def dashboard_choices - defined = User.dashboards + dashboards = User.dashboards.keys - if defined.size != DASHBOARD_CHOICES.size - # Ensure that anyone adding new options updates this method too - raise "`User` defines #{defined.size} dashboard choices," \ - " but `DASHBOARD_CHOICES` defined #{DASHBOARD_CHOICES.size}." - else - defined.map do |key, _| - # Use `fetch` so `KeyError` gets raised when a key is missing - [DASHBOARD_CHOICES.fetch(key), key] - end + validate_dashboard_choices!(dashboards) + dashboards -= excluded_dashboard_choices + + dashboards.map do |key| + # Use `fetch` so `KeyError` gets raised when a key is missing + [DASHBOARD_CHOICES.fetch(key), key] end end @@ -52,4 +50,20 @@ module PreferencesHelper def user_color_scheme Gitlab::ColorSchemes.for_user(current_user).css_class end + + private + + # Ensure that anyone adding new options updates `DASHBOARD_CHOICES` too + def validate_dashboard_choices!(user_dashboards) + if user_dashboards.size != DASHBOARD_CHOICES.size + raise "`User` defines #{user_dashboards.size} dashboard choices," \ + " but `DASHBOARD_CHOICES` defined #{DASHBOARD_CHOICES.size}." + end + end + + # List of dashboard choice to be excluded from CE. + # EE would override this. + def excluded_dashboard_choices + ['operations'] + end end diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb index 53bd43d4861..8ed2a2ec9f4 100644 --- a/app/helpers/sorting_helper.rb +++ b/app/helpers/sorting_helper.rb @@ -48,15 +48,21 @@ module SortingHelper def groups_sort_options_hash { - sort_value_name => sort_title_name, - sort_value_name_desc => sort_title_name_desc, + sort_value_name => sort_title_name, + sort_value_name_desc => sort_title_name_desc, sort_value_recently_created => sort_title_recently_created, - sort_value_oldest_created => sort_title_oldest_created, + sort_value_oldest_created => sort_title_oldest_created, sort_value_recently_updated => sort_title_recently_updated, - sort_value_oldest_updated => sort_title_oldest_updated + sort_value_oldest_updated => sort_title_oldest_updated } end + def subgroups_sort_options_hash + groups_sort_options_hash.merge( + sort_value_most_stars => sort_title_most_stars + ) + end + def admin_groups_sort_options_hash groups_sort_options_hash.merge( sort_value_largest_group => sort_title_largest_group diff --git a/app/helpers/storage_health_helper.rb b/app/helpers/storage_health_helper.rb deleted file mode 100644 index 182e8e6641b..00000000000 --- a/app/helpers/storage_health_helper.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -module StorageHealthHelper - def failing_storage_health_message(storage_health) - storage_name = content_tag(:strong, h(storage_health.storage_name)) - host_names = h(storage_health.failing_on_hosts.to_sentence) - translation_params = { storage_name: storage_name, - host_names: host_names, - failed_attempts: storage_health.total_failures } - - translation = n_('%{storage_name}: failed storage access attempt on host:', - '%{storage_name}: %{failed_attempts} failed storage access attempts:', - storage_health.total_failures) % translation_params - - translation.html_safe - end - - def message_for_circuit_breaker(circuit_breaker) - maximum_failures = circuit_breaker.failure_count_threshold - current_failures = circuit_breaker.failure_count - - translation_params = { number_of_failures: current_failures, - maximum_failures: maximum_failures } - - if circuit_breaker.circuit_broken? - s_("%{number_of_failures} of %{maximum_failures} failures. GitLab will not "\ - "retry automatically. Reset storage information when the problem is "\ - "resolved.") % translation_params - else - _("%{number_of_failures} of %{maximum_failures} failures. GitLab will "\ - "allow access on the next attempt.") % translation_params - end - end -end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 65a2f760f93..23131af1b7d 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -4,6 +4,7 @@ class ApplicationSetting < ActiveRecord::Base include CacheableAttributes include CacheMarkdownField include TokenAuthenticatable + include IgnorableColumn add_authentication_token_field :runners_registration_token add_authentication_token_field :health_check_access_token @@ -27,6 +28,12 @@ class ApplicationSetting < ActiveRecord::Base serialize :domain_blacklist, Array # rubocop:disable Cop/ActiveRecordSerialize serialize :repository_storages # rubocop:disable Cop/ActiveRecordSerialize + ignore_column :circuitbreaker_failure_count_threshold + ignore_column :circuitbreaker_failure_reset_time + ignore_column :circuitbreaker_storage_timeout + ignore_column :circuitbreaker_access_retries + ignore_column :circuitbreaker_check_interval + cache_markdown_field :sign_in_text cache_markdown_field :help_page_text cache_markdown_field :shared_runners_text, pipeline: :plain_markdown @@ -150,17 +157,6 @@ class ApplicationSetting < ActiveRecord::Base presence: true, numericality: { greater_than_or_equal_to: 0 } - validates :circuitbreaker_failure_count_threshold, - :circuitbreaker_failure_reset_time, - :circuitbreaker_storage_timeout, - :circuitbreaker_check_interval, - presence: true, - numericality: { only_integer: true, greater_than_or_equal_to: 0 } - - validates :circuitbreaker_access_retries, - presence: true, - numericality: { only_integer: true, greater_than_or_equal_to: 1 } - validates :gitaly_timeout_default, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 } diff --git a/app/models/deployment.rb b/app/models/deployment.rb index 6962b54441b..62dc0f2cbeb 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -19,6 +19,17 @@ class Deployment < ActiveRecord::Base after_create :create_ref after_create :invalidate_cache + scope :for_environment, -> (environment) { where(environment_id: environment) } + + def self.last_for_environment(environment) + ids = self + .for_environment(environment) + .select('MAX(id) AS id') + .group(:environment_id) + .map(&:id) + find(ids) + end + def commit project.commit(sha) end diff --git a/app/models/environment.rb b/app/models/environment.rb index 309bd4f37c9..0816c395185 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -48,6 +48,8 @@ class Environment < ActiveRecord::Base order(Gitlab::Database.nulls_first_order("(#{max_deployment_id_sql})", 'ASC')) end scope :in_review_folder, -> { where(environment_type: "review") } + scope :for_name, -> (name) { where(name: name) } + scope :for_project, -> (project) { where(project_id: project) } state_machine :state, initial: :available do event :start do diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index 68ba4b213b2..b2fb79bc7ed 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -37,38 +37,4 @@ class WebHook < ActiveRecord::Base def allow_local_requests? false end - - # In 11.4, the web_hooks table has both `token` and `encrypted_token` fields. - # Ensure that the encrypted version always takes precedence if present. - alias_method :attr_encrypted_token, :token - def token - attr_encrypted_token.presence || read_attribute(:token) - end - - # In 11.4, the web_hooks table has both `token` and `encrypted_token` fields. - # Pending a background migration to encrypt all fields, we should just clear - # the unencrypted value whenever the new value is set. - alias_method :'attr_encrypted_token=', :'token=' - def token=(value) - self.attr_encrypted_token = value - - write_attribute(:token, nil) - end - - # In 11.4, the web_hooks table has both `url` and `encrypted_url` fields. - # Ensure that the encrypted version always takes precedence if present. - alias_method :attr_encrypted_url, :url - def url - attr_encrypted_url.presence || read_attribute(:url) - end - - # In 11.4, the web_hooks table has both `url` and `encrypted_url` fields. - # Pending a background migration to encrypt all fields, we should just clear - # the unencrypted value whenever the new value is set. - alias_method :'attr_encrypted_url=', :'url=' - def url=(value) - self.attr_encrypted_url = value - - write_attribute(:url, nil) - end end diff --git a/app/models/project.rb b/app/models/project.rb index 05e14c578b5..c7ca322853f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1789,7 +1789,7 @@ class Project < ActiveRecord::Base return unless export_file_exists? import_export_upload.remove_export_file! - import_export_upload.save + import_export_upload.save unless import_export_upload.destroyed? end def export_file_exists? diff --git a/app/models/user.rb b/app/models/user.rb index 8a7acfb73b1..a0665518cf5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -217,7 +217,7 @@ class User < ActiveRecord::Base # User's Dashboard preference # Note: When adding an option, it MUST go on the end of the array. - enum dashboard: [:projects, :stars, :project_activity, :starred_project_activity, :groups, :todos, :issues, :merge_requests] + enum dashboard: [:projects, :stars, :project_activity, :starred_project_activity, :groups, :todos, :issues, :merge_requests, :operations] # User's Project preference # Note: When adding an option, it MUST go on the end of the array. diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb index 3d508a9a407..7bdcfcc38f7 100644 --- a/app/serializers/build_details_entity.rb +++ b/app/serializers/build_details_entity.rb @@ -4,6 +4,7 @@ class BuildDetailsEntity < JobEntity expose :coverage, :erased_at, :duration expose :tag_list, as: :tags expose :has_trace?, as: :has_trace + expose :stage expose :user, using: UserEntity expose :runner, using: RunnerEntity expose :pipeline, using: PipelineEntity diff --git a/app/views/admin/application_settings/_repository_storage.html.haml b/app/views/admin/application_settings/_repository_storage.html.haml index 908b30cc3ce..c6c29ed1f21 100644 --- a/app/views/admin/application_settings/_repository_storage.html.haml +++ b/app/views/admin/application_settings/_repository_storage.html.haml @@ -20,32 +20,5 @@ Manage repository storage paths. Learn more in the = succeed "." do = link_to "repository storages documentation", help_page_path("administration/repository_storage_paths") - .sub-section - %h4 Circuit breaker - .form-group - = f.label :circuitbreaker_check_interval, _('Check interval'), class: 'label-bold' - = f.number_field :circuitbreaker_check_interval, class: 'form-control' - .form-text.text-muted - = circuitbreaker_check_interval_help_text - .form-group - = f.label :circuitbreaker_access_retries, _('Number of access attempts'), class: 'label-bold' - = f.number_field :circuitbreaker_access_retries, class: 'form-control' - .form-text.text-muted - = circuitbreaker_access_retries_help_text - .form-group - = f.label :circuitbreaker_storage_timeout, _('Seconds to wait for a storage access attempt'), class: 'label-bold' - = f.number_field :circuitbreaker_storage_timeout, class: 'form-control' - .form-text.text-muted - = circuitbreaker_storage_timeout_help_text - .form-group - = f.label :circuitbreaker_failure_count_threshold, _('Maximum git storage failures'), class: 'label-bold' - = f.number_field :circuitbreaker_failure_count_threshold, class: 'form-control' - .form-text.text-muted - = circuitbreaker_failure_count_help_text - .form-group - = f.label :circuitbreaker_failure_reset_time, _('Seconds before reseting failure information'), class: 'label-bold' - = f.number_field :circuitbreaker_failure_reset_time, class: 'form-control' - .form-text.text-muted - = circuitbreaker_failure_reset_time_help_text = f.submit 'Save changes', class: "btn btn-success qa-save-changes-button" diff --git a/app/views/admin/application_settings/repository.html.haml b/app/views/admin/application_settings/repository.html.haml index be13138a764..b50a0dd5a18 100644 --- a/app/views/admin/application_settings/repository.html.haml +++ b/app/views/admin/application_settings/repository.html.haml @@ -20,7 +20,7 @@ %button.btn.btn-default.js-settings-toggle{ type: 'button' } = expanded_by_default? ? _('Collapse') : _('Expand') %p - = _('Configure storage path and circuit breaker settings.') + = _('Configure storage path settings.') .settings-content = render 'repository_storage' diff --git a/app/views/admin/applications/show.html.haml b/app/views/admin/applications/show.html.haml index e69143abe45..df3eeba907c 100644 --- a/app/views/admin/applications/show.html.haml +++ b/app/views/admin/applications/show.html.haml @@ -22,7 +22,7 @@ .input-group %input.label.label-monospace{ id: "secret", type: "text", autocomplete: 'off', value: @application.secret, readonly: true } .input-group-append - = clipboard_button(target: '#application_id', title: _("Copy secret to clipboard"), class: "btn btn btn-default") + = clipboard_button(target: '#secret', title: _("Copy secret to clipboard"), class: "btn btn btn-default") %tr %td = _('Callback URL') diff --git a/app/views/admin/health_check/_failing_storages.html.haml b/app/views/admin/health_check/_failing_storages.html.haml deleted file mode 100644 index 6830201538d..00000000000 --- a/app/views/admin/health_check/_failing_storages.html.haml +++ /dev/null @@ -1,15 +0,0 @@ -- if failing_storages.any? - = _('There are problems accessing Git storage: ') - %ul - - failing_storages.each do |storage_health| - %li - = failing_storage_health_message(storage_health) - %ul - - storage_health.failing_circuit_breakers.each do |circuit_breaker| - %li - #{circuit_breaker.hostname}: #{message_for_circuit_breaker(circuit_breaker)} - - = _("Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again.") - .prepend-top-10 - = button_to _("Reset git storage health information"), reset_storage_health_admin_health_check_path, - method: :post, class: 'btn btn-default' diff --git a/app/views/admin/health_check/show.html.haml b/app/views/admin/health_check/show.html.haml index d51ac854b04..0f5e97e288a 100644 --- a/app/views/admin/health_check/show.html.haml +++ b/app/views/admin/health_check/show.html.haml @@ -1,6 +1,6 @@ - @no_container = true - page_title _('Health Check') -- no_errors = @errors.blank? && @failing_storage_statuses.blank? +- no_errors = @errors.blank? %div{ class: container_class } %h3.page-title= page_title @@ -39,4 +39,3 @@ #{ s_('HealthCheck|No Health Problems Detected') } - else = @errors - = render partial: 'failing_storages', object: @failing_storage_statuses diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml index 269a3721e06..12271ee5adb 100644 --- a/app/views/devise/shared/_omniauth_box.html.haml +++ b/app/views/devise/shared/_omniauth_box.html.haml @@ -5,7 +5,7 @@ .d-flex.justify-content-between.flex-wrap - providers.each do |provider| - has_icon = provider_has_icon?(provider) - = link_to omniauth_authorize_path(:user, provider), method: :post, class: 'btn d-flex align-items-center omniauth-btn text-left oauth-login', id: "oauth-login-#{provider}" do + = link_to omniauth_authorize_path(:user, provider), method: :post, class: 'btn d-flex align-items-center omniauth-btn text-left oauth-login qa-saml-login-button', id: "oauth-login-#{provider}" do - if has_icon = provider_image_tag(provider) %span diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index 90ed20404c5..9a827523ed4 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -5,22 +5,22 @@ = devise_error_messages! .form-group = f.label :name, 'Full name', class: 'label-bold' - = f.text_field :name, class: "form-control top", required: true, title: "This field is required." + = f.text_field :name, class: "form-control top qa-new-user-name", required: true, title: "This field is required." .username.form-group = f.label :username, class: 'label-bold' - = f.text_field :username, class: "form-control middle", pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: 'Please create a username with only alphanumeric characters.' + = f.text_field :username, class: "form-control middle qa-new-user-username", pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: 'Please create a username with only alphanumeric characters.' %p.validation-error.hide Username is already taken. %p.validation-success.hide Username is available. %p.validation-pending.hide Checking username availability... .form-group = f.label :email, class: 'label-bold' - = f.email_field :email, class: "form-control middle", required: true, title: "Please provide a valid email address." + = f.email_field :email, class: "form-control middle qa-new-user-email", required: true, title: "Please provide a valid email address." .form-group = f.label :email_confirmation, class: 'label-bold' - = f.email_field :email_confirmation, class: "form-control middle", required: true, title: "Please retype the email address." + = f.email_field :email_confirmation, class: "form-control middle qa-new-user-email-confirmation", required: true, title: "Please retype the email address." .form-group.append-bottom-20#password-strength = f.label :password, class: 'label-bold' - = f.password_field :password, class: "form-control bottom", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters." + = f.password_field :password, class: "form-control bottom qa-new-user-password", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters." %p.gl-field-hint.text-secondary Minimum length is #{@minimum_password_length} characters - if Gitlab::CurrentSettings.current_application_settings.enforce_terms? .form-group @@ -33,4 +33,4 @@ - if Gitlab::Recaptcha.enabled? = recaptcha_tags .submit-container - = f.submit "Register", class: "btn-register btn" + = f.submit "Register", class: "btn-register btn qa-new-user-register-button" diff --git a/app/views/doorkeeper/applications/show.html.haml b/app/views/doorkeeper/applications/show.html.haml index 776bbc36ec2..cac00f9c854 100644 --- a/app/views/doorkeeper/applications/show.html.haml +++ b/app/views/doorkeeper/applications/show.html.haml @@ -25,7 +25,7 @@ .input-group %input.label.label-monospace{ id: "secret", type: "text", autocomplete: 'off', value: @application.secret, readonly: true } .input-group-append - = clipboard_button(target: '#application_id', title: _("Copy secret to clipboard"), class: "btn btn btn-default") + = clipboard_button(target: '#secret', title: _("Copy secret to clipboard"), class: "btn btn btn-default") %tr %td = _('Callback URL') diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 6a293daaf95..cc294f6a931 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -53,7 +53,7 @@ = _("Archived projects") .nav-controls - = render "shared/groups/dropdown" + = render "shared/groups/dropdown", options_hash: subgroups_sort_options_hash .tab-content #subgroups_and_projects.tab-pane diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 5e467c862ab..8f8b6b454d9 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -66,6 +66,7 @@ - if Gitlab::Sherlock.enabled? || can?(current_user, :read_instance_statistics) %li.line-separator.d-none.d-sm-block + = render_if_exists 'dashboard/operations/nav_link' - if can?(current_user, :read_instance_statistics) = nav_link(controller: [:conversational_development_index, :cohorts]) do = link_to instance_statistics_root_path, title: _('Instance Statistics'), aria: { label: _('Instance Statistics') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml index 25cd53b378a..3625224fbcd 100644 --- a/app/views/layouts/nav/sidebar/_project.html.haml +++ b/app/views/layouts/nav/sidebar/_project.html.haml @@ -216,7 +216,7 @@ = _('Metrics') = nav_link(controller: :environments, action: [:index, :folder, :show, :new, :edit, :create, :update, :stop, :terminal]) do - = link_to project_environments_path(@project), title: _('Environments'), class: 'shortcuts-environments' do + = link_to project_environments_path(@project), title: _('Environments'), class: 'shortcuts-environments qa-operations-environments-link' do %span = _('Environments') @@ -309,7 +309,7 @@ %span = _('General') = nav_link(controller: :project_members) do - = link_to project_project_members_path(@project), title: _('Members') do + = link_to project_project_members_path(@project), title: _('Members'), class: 'qa-link-members-settings' do %span = _('Members') - if can_edit diff --git a/app/views/projects/blob/_template_selectors.html.haml b/app/views/projects/blob/_template_selectors.html.haml index 5b092427496..2c8dd45670f 100644 --- a/app/views/projects/blob/_template_selectors.html.haml +++ b/app/views/projects/blob/_template_selectors.html.haml @@ -3,15 +3,15 @@ Template .template-selector-dropdowns-wrap .template-type-selector.js-template-type-selector-wrap.hidden - = dropdown_tag("Choose type", options: { toggle_class: 'js-template-type-selector', title: "Choose a template type" } ) + = dropdown_tag("Choose type", options: { toggle_class: 'js-template-type-selector qa-template-type-dropdown', title: "Choose a template type" } ) .license-selector.js-license-selector-wrap.js-template-selector-wrap.hidden - = dropdown_tag("Apply a license template", options: { toggle_class: 'js-license-selector', title: "Apply a license", filter: true, placeholder: "Filter", data: { data: licenses_for_select, project: @project.name, fullname: @project.namespace.human_name } } ) + = dropdown_tag("Apply a license template", options: { toggle_class: 'js-license-selector qa-license-dropdown', title: "Apply a license", filter: true, placeholder: "Filter", data: { data: licenses_for_select, project: @project.name, fullname: @project.namespace.human_name } } ) .gitignore-selector.js-gitignore-selector-wrap.js-template-selector-wrap.hidden - = dropdown_tag("Apply a .gitignore template", options: { toggle_class: 'js-gitignore-selector', title: "Apply a template", filter: true, placeholder: "Filter", data: { data: gitignore_names } } ) + = dropdown_tag("Apply a .gitignore template", options: { toggle_class: 'js-gitignore-selector qa-gitignore-dropdown', title: "Apply a template", filter: true, placeholder: "Filter", data: { data: gitignore_names } } ) .gitlab-ci-yml-selector.js-gitlab-ci-yml-selector-wrap.js-template-selector-wrap.hidden - = dropdown_tag("Apply a GitLab CI Yaml template", options: { toggle_class: 'js-gitlab-ci-yml-selector', title: "Apply a template", filter: true, placeholder: "Filter", data: { data: gitlab_ci_ymls } } ) + = dropdown_tag("Apply a GitLab CI Yaml template", options: { toggle_class: 'js-gitlab-ci-yml-selector qa-gitlab-ci-yml-dropdown', title: "Apply a template", filter: true, placeholder: "Filter", data: { data: gitlab_ci_ymls } } ) .dockerfile-selector.js-dockerfile-selector-wrap.js-template-selector-wrap.hidden - = dropdown_tag("Apply a Dockerfile template", options: { toggle_class: 'js-dockerfile-selector', title: "Apply a template", filter: true, placeholder: "Filter", data: { data: dockerfile_names } } ) + = dropdown_tag("Apply a Dockerfile template", options: { toggle_class: 'js-dockerfile-selector qa-dockerfile-dropdown', title: "Apply a template", filter: true, placeholder: "Filter", data: { data: dockerfile_names } } ) .template-selectors-undo-menu.hidden %span.text-info Template applied %button.btn.btn-sm.btn-info Undo diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml index 8b9c52f0802..45515fb492f 100644 --- a/app/views/projects/buttons/_dropdown.html.haml +++ b/app/views/projects/buttons/_dropdown.html.haml @@ -8,7 +8,7 @@ - if show_menu .project-action-button.dropdown.inline - %a.btn.dropdown-toggle.has-tooltip{ href: '#', title: _('Create new...'), 'data-toggle' => 'dropdown', 'data-container' => 'body', 'aria-label' => _('Create new...'), 'data-display' => 'static' } + %a.btn.dropdown-toggle.has-tooltip.qa-create-new-dropdown{ href: '#', title: _('Create new...'), 'data-toggle' => 'dropdown', 'data-container' => 'body', 'aria-label' => _('Create new...'), 'data-display' => 'static' } = icon('plus') = icon("caret-down") %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown @@ -28,7 +28,7 @@ %li.dropdown-header= _('This repository') - if can_push_code - %li= link_to _('New file'), project_new_blob_path(@project, @project.default_branch || 'master') + %li.qa-new-file-option= link_to _('New file'), project_new_blob_path(@project, @project.default_branch || 'master') - unless @project.empty_repo? %li= link_to _('New branch'), new_project_branch_path(@project) %li= link_to _('New tag'), new_project_tag_path(@project) diff --git a/app/views/projects/clusters/gcp/_form.html.haml b/app/views/projects/clusters/gcp/_form.html.haml index eaf3a93bd15..171ceeceb68 100644 --- a/app/views/projects/clusters/gcp/_form.html.haml +++ b/app/views/projects/clusters/gcp/_form.html.haml @@ -68,7 +68,7 @@ .form-text.text-muted = s_('ClusterIntegration|Enable this setting if using role-based access control (RBAC).') = s_('ClusterIntegration|This option will allow you to install applications on RBAC clusters.') - = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'role-based-access-control-rbac-experimental-support'), target: '_blank' + = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'role-based-access-control-rbac-core-only'), target: '_blank' .form-group = field.submit s_('ClusterIntegration|Create Kubernetes cluster'), class: 'js-gke-cluster-creation-submit btn btn-success', disabled: true diff --git a/app/views/projects/clusters/user/_form.html.haml b/app/views/projects/clusters/user/_form.html.haml index 56551ed4d65..54a6e685bb0 100644 --- a/app/views/projects/clusters/user/_form.html.haml +++ b/app/views/projects/clusters/user/_form.html.haml @@ -32,7 +32,7 @@ .form-text.text-muted = s_('ClusterIntegration|Enable this setting if using role-based access control (RBAC).') = s_('ClusterIntegration|This option will allow you to install applications on RBAC clusters.') - = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'role-based-access-control-rbac-experimental-support'), target: '_blank' + = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'role-based-access-control-rbac-core-only'), target: '_blank' .form-group = field.submit s_('ClusterIntegration|Add Kubernetes cluster'), class: 'btn btn-success' diff --git a/app/views/projects/environments/_external_url.html.haml b/app/views/projects/environments/_external_url.html.haml index 4694bc39d54..b3a82d1ef41 100644 --- a/app/views/projects/environments/_external_url.html.haml +++ b/app/views/projects/environments/_external_url.html.haml @@ -1,4 +1,4 @@ - if environment.external_url && can?(current_user, :read_environment, environment) - = link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url has-tooltip', title: s_('Environments|Open live environment') do + = link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url has-tooltip qa-view-deployment', title: s_('Environments|Open live environment') do = sprite_icon('external-link') View deployment diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml index a5f814b722d..02a088d338b 100644 --- a/app/views/projects/jobs/show.html.haml +++ b/app/views/projects/jobs/show.html.haml @@ -47,4 +47,6 @@ .js-build-options{ data: javascript_build_options } -#js-job-details-vue{ data: { endpoint: project_job_path(@project, @build, format: :json), runner_help_url: help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner') } } +#js-job-details-vue{ data: { endpoint: project_job_path(@project, @build, format: :json), + runner_help_url: help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner'), + runner_settings_url: project_runners_path(@build.project, anchor: 'js-runners-settings') } } diff --git a/app/views/projects/pipelines/_info.html.haml b/app/views/projects/pipelines/_info.html.haml index ccb83148ded..dbb563f51ea 100644 --- a/app/views/projects/pipelines/_info.html.haml +++ b/app/views/projects/pipelines/_info.html.haml @@ -30,5 +30,3 @@ %span.js-details-content.hide = link_to @pipeline.sha, project_commit_path(@project, @pipeline.sha), class: "commit-sha commit-hash-full" = clipboard_button(text: @pipeline.sha, title: "Copy commit SHA to clipboard") - - = render_if_exists "projects/pipelines/info_extension", pipeline: @pipeline diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index 517fd249f6e..5e21442bb60 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -3,7 +3,7 @@ = form_for @project_member, as: :project_member, url: project_project_members_path(@project), html: { class: 'users-project-form' } do |f| .form-group = label_tag :user_ids, "Select members to invite", class: "label-bold" - = users_select_tag(:user_ids, multiple: true, class: "input-clamp", scope: :all, email_user: true, placeholder: "Search for members to update or invite") + = users_select_tag(:user_ids, multiple: true, class: "input-clamp qa-member-select-input", scope: :all, email_user: true, placeholder: "Search for members to update or invite") .form-group = label_tag :access_level, "Choose a role permission", class: "label-bold" .select-wrapper @@ -17,5 +17,5 @@ = label_tag :expires_at, 'Access expiration date', class: 'label-bold' = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date' %i.clear-icon.js-clear-input - = f.submit "Add to project", class: "btn btn-success" + = f.submit "Add to project", class: "btn btn-success qa-add-member-button" = link_to "Import", import_project_project_members_path(@project), class: "btn btn-default", title: "Import members from another project" diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index 0c5a187f208..9682f8ac922 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -14,5 +14,5 @@ %button.member-search-btn{ type: "submit", "aria-label" => "Submit search" } = icon("search") = render 'shared/members/sort_dropdown' - %ul.content-list.members-list + %ul.content-list.members-list.qa-members-list = render partial: 'shared/members/member', collection: members, as: :member diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml index 9d196075bf1..601e3f25852 100644 --- a/app/views/projects/tree/_tree_header.html.haml +++ b/app/views/projects/tree/_tree_header.html.haml @@ -82,7 +82,7 @@ - if can_collaborate = succeed " " do - = link_to ide_edit_path(@project, @ref, @path), class: 'btn btn-default' do + = link_to ide_edit_path(@project, @ref, @path), class: 'btn btn-default qa-web-ide-button' do = _('Web IDE') = render 'projects/buttons/download', project: @project, ref: @ref diff --git a/app/views/shared/empty_states/_wikis.html.haml b/app/views/shared/empty_states/_wikis.html.haml index 5351c9ce6a4..df3308abe0d 100644 --- a/app/views/shared/empty_states/_wikis.html.haml +++ b/app/views/shared/empty_states/_wikis.html.haml @@ -5,7 +5,7 @@ - create_link = link_to s_('WikiEmpty|Create your first page'), create_path, class: 'btn btn-success', title: s_('WikiEmpty|Create your first page') = render layout: layout_path, locals: { image_path: 'illustrations/wiki_login_empty.svg' } do - %h4 + %h4.text-left = s_('WikiEmpty|The wiki lets you write documentation for your project') %p.text-left = s_("WikiEmpty|A wiki is where you can store all the details about your project. This can include why you've created it, its principles, how to use it, and so on.") |