diff options
411 files changed, 1909 insertions, 459 deletions
diff --git a/.eslintrc b/.eslintrc index 8f9cdfb14ac..a86f8a841c3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,6 +1,5 @@ { "env": { - "jquery": true, "browser": true, "es6": true }, diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index fe6d01c1a45..5aee1345c52 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -0.88.0 +0.89.0 diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION index faef31a4357..39e898a4f95 100644 --- a/GITLAB_PAGES_VERSION +++ b/GITLAB_PAGES_VERSION @@ -1 +1 @@ -0.7.0 +0.7.1 diff --git a/Gemfile.lock b/Gemfile.lock index fa99ec3febe..b85c7085d07 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -63,7 +63,7 @@ GEM fog-core mime-types (>= 2.99) unf - ast (2.3.0) + ast (2.4.0) atomic (1.1.99) attr_encrypted (3.0.3) encryptor (~> 3.0.0) @@ -586,8 +586,8 @@ GEM orm_adapter (0.5.0) os (0.9.6) parallel (1.12.1) - parser (2.4.0.2) - ast (~> 2.3) + parser (2.5.0.3) + ast (~> 2.4.0) parslet (1.5.0) blankslate (~> 2.0) path_expander (1.0.2) @@ -951,13 +951,13 @@ GEM get_process_mem (~> 0) unicorn (>= 4, < 6) uniform_notifier (1.10.0) - unparser (0.2.6) + unparser (0.2.7) abstract_type (~> 0.0.7) adamantium (~> 0.2.0) concord (~> 0.1.5) diff-lcs (~> 1.3) equalizer (~> 0.0.9) - parser (>= 2.3.1.2, < 2.5) + parser (>= 2.3.1.2, < 2.6) procto (~> 0.0.2) url_safe_base64 (0.2.2) validates_hostname (1.0.6) diff --git a/app/assets/javascripts/activities.js b/app/assets/javascripts/activities.js index 6a0662ba903..c117d080bda 100644 --- a/app/assets/javascripts/activities.js +++ b/app/assets/javascripts/activities.js @@ -1,5 +1,6 @@ /* eslint-disable no-param-reassign, class-methods-use-this */ +import $ from 'jquery'; import Cookies from 'js-cookie'; import Pager from './pager'; import { localTimeAgo } from './lib/utils/datetime_utility'; diff --git a/app/assets/javascripts/ajax_loading_spinner.js b/app/assets/javascripts/ajax_loading_spinner.js index 2bc77859c26..bd08308904c 100644 --- a/app/assets/javascripts/ajax_loading_spinner.js +++ b/app/assets/javascripts/ajax_loading_spinner.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default class AjaxLoadingSpinner { static init() { const $elements = $('.js-ajax-loading-spinner'); diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 464611f66f0..cbcefb2c18f 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import axios from './lib/utils/axios_utils'; diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js index 26e62732b33..6da33a26e58 100644 --- a/app/assets/javascripts/awards_handler.js +++ b/app/assets/javascripts/awards_handler.js @@ -1,4 +1,6 @@ /* eslint-disable class-methods-use-this */ + +import $ from 'jquery'; import _ from 'underscore'; import Cookies from 'js-cookie'; import { __ } from './locale'; diff --git a/app/assets/javascripts/behaviors/copy_as_gfm.js b/app/assets/javascripts/behaviors/copy_as_gfm.js index ffe90595b5d..f5f4f00d587 100644 --- a/app/assets/javascripts/behaviors/copy_as_gfm.js +++ b/app/assets/javascripts/behaviors/copy_as_gfm.js @@ -1,5 +1,6 @@ /* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */ +import $ from 'jquery'; import _ from 'underscore'; import { insertText, getSelectedFragment, nodeMatchesSelector } from '../lib/utils/common_utils'; import { placeholderImage } from '../lazy_loader'; diff --git a/app/assets/javascripts/behaviors/copy_to_clipboard.js b/app/assets/javascripts/behaviors/copy_to_clipboard.js index b669b63d23c..e2a73a1797c 100644 --- a/app/assets/javascripts/behaviors/copy_to_clipboard.js +++ b/app/assets/javascripts/behaviors/copy_to_clipboard.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Clipboard from 'clipboard'; function showTooltip(target, title) { diff --git a/app/assets/javascripts/behaviors/details_behavior.js b/app/assets/javascripts/behaviors/details_behavior.js index 7c9dbcc8d6e..1d63f5baeee 100644 --- a/app/assets/javascripts/behaviors/details_behavior.js +++ b/app/assets/javascripts/behaviors/details_behavior.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; $(() => { $('body').on('click', '.js-details-target', function target() { diff --git a/app/assets/javascripts/behaviors/quick_submit.js b/app/assets/javascripts/behaviors/quick_submit.js index 51bd5b8ebe5..3ec932bdb73 100644 --- a/app/assets/javascripts/behaviors/quick_submit.js +++ b/app/assets/javascripts/behaviors/quick_submit.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import '../commons/bootstrap'; import { isInIssuePage } from '../lib/utils/common_utils'; diff --git a/app/assets/javascripts/behaviors/requires_input.js b/app/assets/javascripts/behaviors/requires_input.js index e10cb2e3dc4..ffff4ddb71a 100644 --- a/app/assets/javascripts/behaviors/requires_input.js +++ b/app/assets/javascripts/behaviors/requires_input.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import '../commons/bootstrap'; diff --git a/app/assets/javascripts/behaviors/toggler_behavior.js b/app/assets/javascripts/behaviors/toggler_behavior.js index 81c89441424..4446be0e52f 100644 --- a/app/assets/javascripts/behaviors/toggler_behavior.js +++ b/app/assets/javascripts/behaviors/toggler_behavior.js @@ -1,3 +1,6 @@ +import $ from 'jquery'; +import { getLocationHash } from '../lib/utils/url_utility'; + // Toggle button. Show/hide content inside parent container. // Button does not change visibility. If button has icon - it changes chevron style. // @@ -5,7 +8,6 @@ // %button.js-toggle-button // %div.js-toggle-content // -import { getLocationHash } from '../lib/utils/url_utility'; $(() => { function toggleContainer(container, toggleState) { diff --git a/app/assets/javascripts/blob/blob_file_dropzone.js b/app/assets/javascripts/blob/blob_file_dropzone.js index 83cac896f86..ff1739b1679 100644 --- a/app/assets/javascripts/blob/blob_file_dropzone.js +++ b/app/assets/javascripts/blob/blob_file_dropzone.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, object-shorthand, prefer-arrow-callback */ + +import $ from 'jquery'; import Dropzone from 'dropzone'; import { visitUrl } from '../lib/utils/url_utility'; import { HIDDEN_CLASS } from '../lib/utils/constants'; diff --git a/app/assets/javascripts/blob/blob_fork_suggestion.js b/app/assets/javascripts/blob/blob_fork_suggestion.js index 47c431fb809..476b9405a9e 100644 --- a/app/assets/javascripts/blob/blob_fork_suggestion.js +++ b/app/assets/javascripts/blob/blob_fork_suggestion.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + const defaults = { // Buttons that will show the `suggestionSections` // has `data-fork-path`, and `data-action` diff --git a/app/assets/javascripts/blob/file_template_mediator.js b/app/assets/javascripts/blob/file_template_mediator.js index 37074301b51..030ca1907e5 100644 --- a/app/assets/javascripts/blob/file_template_mediator.js +++ b/app/assets/javascripts/blob/file_template_mediator.js @@ -1,4 +1,6 @@ /* eslint-disable class-methods-use-this */ + +import $ from 'jquery'; import Flash from '../flash'; import FileTemplateTypeSelector from './template_selectors/type_selector'; import BlobCiYamlSelector from './template_selectors/ci_yaml_selector'; diff --git a/app/assets/javascripts/blob/file_template_selector.js b/app/assets/javascripts/blob/file_template_selector.js index 5ae30990aea..e52cf249f3a 100644 --- a/app/assets/javascripts/blob/file_template_selector.js +++ b/app/assets/javascripts/blob/file_template_selector.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default class FileTemplateSelector { constructor(mediator) { this.mediator = mediator; diff --git a/app/assets/javascripts/blob/template_selector.js b/app/assets/javascripts/blob/template_selector.js index 888883163c5..9dfdb06007d 100644 --- a/app/assets/javascripts/blob/template_selector.js +++ b/app/assets/javascripts/blob/template_selector.js @@ -1,5 +1,7 @@ /* eslint-disable class-methods-use-this, no-unused-vars */ +import $ from 'jquery'; + export default class TemplateSelector { constructor({ dropdown, data, pattern, wrapper, editor, $input } = {}) { this.pattern = pattern; @@ -76,7 +78,7 @@ export default class TemplateSelector { if (!skipFocus) this.editor.focus(); - if (this.editor instanceof jQuery) { + if (this.editor instanceof $) { this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent); } } diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js index 92ea91c45a8..137e1f5a099 100644 --- a/app/assets/javascripts/blob/viewer/index.js +++ b/app/assets/javascripts/blob/viewer/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Flash from '../../flash'; import { handleLocationHash } from '../../lib/utils/common_utils'; import axios from '../../lib/utils/axios_utils'; diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js index 931ed042dfd..4424232f642 100644 --- a/app/assets/javascripts/blob_edit/blob_bundle.js +++ b/app/assets/javascripts/blob_edit/blob_bundle.js @@ -1,5 +1,7 @@ /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-new, max-len */ /* global EditBlob */ + +import $ from 'jquery'; import NewCommitForm from '../new_commit_form'; import EditBlob from './edit_blob'; import BlobFileDropzone from '../blob/blob_file_dropzone'; diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js index d4f6adaccbc..82a3d494b67 100644 --- a/app/assets/javascripts/blob_edit/edit_blob.js +++ b/app/assets/javascripts/blob_edit/edit_blob.js @@ -1,5 +1,6 @@ /* global ace */ +import $ from 'jquery'; import axios from '~/lib/utils/axios_utils'; import createFlash from '~/flash'; import { __ } from '~/locale'; diff --git a/app/assets/javascripts/boards/components/board.js b/app/assets/javascripts/boards/components/board.js index 9c4cc2338c8..3cffd91716a 100644 --- a/app/assets/javascripts/boards/components/board.js +++ b/app/assets/javascripts/boards/components/board.js @@ -1,4 +1,6 @@ /* eslint-disable comma-dangle, space-before-function-paren, one-var */ + +import $ from 'jquery'; import Sortable from 'vendor/Sortable'; import Vue from 'vue'; import AccessorUtilities from '../../lib/utils/accessor'; diff --git a/app/assets/javascripts/boards/components/board_delete.js b/app/assets/javascripts/boards/components/board_delete.js index 8a1b177bba8..7be98825fda 100644 --- a/app/assets/javascripts/boards/components/board_delete.js +++ b/app/assets/javascripts/boards/components/board_delete.js @@ -1,5 +1,6 @@ /* eslint-disable comma-dangle, space-before-function-paren, no-alert */ +import $ from 'jquery'; import Vue from 'vue'; window.gl = window.gl || {}; diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue index 870d242e774..8d84c1735b8 100644 --- a/app/assets/javascripts/boards/components/board_new_issue.vue +++ b/app/assets/javascripts/boards/components/board_new_issue.vue @@ -1,4 +1,5 @@ <script> +import $ from 'jquery'; import eventHub from '../eventhub'; import ProjectSelect from './project_select.vue'; import ListIssue from '../models/issue'; diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js index d1a5a3a2253..a44969272a1 100644 --- a/app/assets/javascripts/boards/components/board_sidebar.js +++ b/app/assets/javascripts/boards/components/board_sidebar.js @@ -1,5 +1,6 @@ /* eslint-disable comma-dangle, space-before-function-paren, no-new */ +import $ from 'jquery'; import Vue from 'vue'; import Flash from '../../flash'; import { __ } from '../../locale'; diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js b/app/assets/javascripts/boards/components/issue_card_inner.js index fc2bad2415f..7e882a57202 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.js +++ b/app/assets/javascripts/boards/components/issue_card_inner.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; import eventHub from '../eventhub'; diff --git a/app/assets/javascripts/boards/components/new_list_dropdown.js b/app/assets/javascripts/boards/components/new_list_dropdown.js index 362ef43e6f7..71f49319c36 100644 --- a/app/assets/javascripts/boards/components/new_list_dropdown.js +++ b/app/assets/javascripts/boards/components/new_list_dropdown.js @@ -1,5 +1,6 @@ -/* eslint-disable func-names, no-new, space-before-function-paren, one-var, - promise/catch-or-return */ +/* eslint-disable func-names, no-new, space-before-function-paren, one-var, promise/catch-or-return, max-len */ + +import $ from 'jquery'; import axios from '~/lib/utils/axios_utils'; import _ from 'underscore'; import CreateLabelDropdown from '../../create_label'; diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue index d99b222c305..371774098b9 100644 --- a/app/assets/javascripts/boards/components/project_select.vue +++ b/app/assets/javascripts/boards/components/project_select.vue @@ -1,5 +1,7 @@ <script> /* global ListIssue */ + + import $ from 'jquery'; import _ from 'underscore'; import eventHub from '../eventhub'; import loadingIcon from '../../vue_shared/components/loading_icon.vue'; diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index efc0da2e7a2..8b1c14c04ff 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -1,5 +1,6 @@ /* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren */ +import $ from 'jquery'; import _ from 'underscore'; import Vue from 'vue'; diff --git a/app/assets/javascripts/boards/mixins/sortable_default_options.js b/app/assets/javascripts/boards/mixins/sortable_default_options.js index 5e31c6314b2..ac316c31deb 100644 --- a/app/assets/javascripts/boards/mixins/sortable_default_options.js +++ b/app/assets/javascripts/boards/mixins/sortable_default_options.js @@ -1,6 +1,7 @@ /* eslint-disable no-unused-vars, no-mixed-operators, comma-dangle */ /* global DocumentTouch */ +import $ from 'jquery'; import sortableConfig from '../../sortable/sortable_config'; window.gl = window.gl || {}; diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index 348cdeec737..20e78edf2a2 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -1,5 +1,7 @@ /* eslint-disable comma-dangle, space-before-function-paren, one-var, no-shadow, dot-notation, max-len */ /* global List */ + +import $ from 'jquery'; import _ from 'underscore'; import Cookies from 'js-cookie'; import { getUrlParamsArray } from '~/lib/utils/common_utils'; diff --git a/app/assets/javascripts/branches/branches_delete_modal.js b/app/assets/javascripts/branches/branches_delete_modal.js index cbc28374b80..839e369eaf6 100644 --- a/app/assets/javascripts/branches/branches_delete_modal.js +++ b/app/assets/javascripts/branches/branches_delete_modal.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + const MODAL_SELECTOR = '#modal-delete-branch'; class DeleteModal { diff --git a/app/assets/javascripts/breadcrumb.js b/app/assets/javascripts/breadcrumb.js index 10fbcfe96cf..1474d93dde6 100644 --- a/app/assets/javascripts/breadcrumb.js +++ b/app/assets/javascripts/breadcrumb.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export const addTooltipToEl = (el) => { const textEl = el.querySelector('.js-breadcrumb-item-text'); diff --git a/app/assets/javascripts/build_artifacts.js b/app/assets/javascripts/build_artifacts.js index ace89398943..3fa16517388 100644 --- a/app/assets/javascripts/build_artifacts.js +++ b/app/assets/javascripts/build_artifacts.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, prefer-arrow-callback, no-return-assign */ + +import $ from 'jquery'; import { visitUrl } from './lib/utils/url_utility'; import { convertPermissionToBoolean } from './lib/utils/common_utils'; diff --git a/app/assets/javascripts/build_variables.js b/app/assets/javascripts/build_variables.js index 35edf3e0017..d398e4a4c83 100644 --- a/app/assets/javascripts/build_variables.js +++ b/app/assets/javascripts/build_variables.js @@ -1,9 +1,9 @@ -/* eslint-disable func-names*/ +import $ from 'jquery'; export default function handleRevealVariables() { $('.js-reveal-variables') .off('click') - .on('click', function () { + .on('click', function click() { $('.js-build-variables').toggle(); $(this).hide(); }); diff --git a/app/assets/javascripts/ci_variable_list/native_form_variable_list.js b/app/assets/javascripts/ci_variable_list/native_form_variable_list.js index d54ea7df1c3..7cd5916ac9c 100644 --- a/app/assets/javascripts/ci_variable_list/native_form_variable_list.js +++ b/app/assets/javascripts/ci_variable_list/native_form_variable_list.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import VariableList from './ci_variable_list'; // Used for the variable list on scheduled pipeline edit page diff --git a/app/assets/javascripts/commit/image_file.js b/app/assets/javascripts/commit/image_file.js index 6504a0bbbfc..7f3d04655a7 100644 --- a/app/assets/javascripts/commit/image_file.js +++ b/app/assets/javascripts/commit/image_file.js @@ -1,5 +1,7 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-use-before-define, 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, object-shorthand, max-len */ +import $ from 'jquery'; + // Width where images must fits in, for 2-up this gets divided by 2 const availWidth = 900; const viewModes = ['two-up', 'swipe']; diff --git a/app/assets/javascripts/commit_merge_requests.js b/app/assets/javascripts/commit_merge_requests.js index f76c9b7e690..102b4ee8463 100644 --- a/app/assets/javascripts/commit_merge_requests.js +++ b/app/assets/javascripts/commit_merge_requests.js @@ -1,5 +1,6 @@ /* global Flash */ +import $ from 'jquery'; import axios from './lib/utils/axios_utils'; import { n__, s__ } from './locale'; diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js index 2be63bd8c76..7e2a3573f81 100644 --- a/app/assets/javascripts/commits.js +++ b/app/assets/javascripts/commits.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { pluralize } from './lib/utils/text_utility'; import { localTimeAgo } from './lib/utils/datetime_utility'; import Pager from './pager'; diff --git a/app/assets/javascripts/compare.js b/app/assets/javascripts/compare.js index d5a35ed81a6..303a5bf4a53 100644 --- a/app/assets/javascripts/compare.js +++ b/app/assets/javascripts/compare.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, no-var, object-shorthand, consistent-return, no-unused-vars, comma-dangle, vars-on-top, prefer-template, max-len */ + +import $ from 'jquery'; import { localTimeAgo } from './lib/utils/datetime_utility'; import axios from './lib/utils/axios_utils'; diff --git a/app/assets/javascripts/compare_autocomplete.js b/app/assets/javascripts/compare_autocomplete.js index fa341918fc1..260c91cac24 100644 --- a/app/assets/javascripts/compare_autocomplete.js +++ b/app/assets/javascripts/compare_autocomplete.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, object-shorthand, comma-dangle, prefer-arrow-callback, no-else-return, newline-per-chained-call, wrap-iife, max-len */ + +import $ from 'jquery'; import { __ } from './locale'; import axios from './lib/utils/axios_utils'; import flash from './flash'; diff --git a/app/assets/javascripts/confirm_danger_modal.js b/app/assets/javascripts/confirm_danger_modal.js index eae4a7eab55..0932d836589 100644 --- a/app/assets/javascripts/confirm_danger_modal.js +++ b/app/assets/javascripts/confirm_danger_modal.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, camelcase, one-var-declaration-per-line, no-else-return, max-len */ + +import $ from 'jquery'; import { rstrip } from './lib/utils/common_utils'; window.ConfirmDangerModal = (function() { diff --git a/app/assets/javascripts/contextual_sidebar.js b/app/assets/javascripts/contextual_sidebar.js index 74520675a7c..3a50e73ad85 100644 --- a/app/assets/javascripts/contextual_sidebar.js +++ b/app/assets/javascripts/contextual_sidebar.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Cookies from 'js-cookie'; import _ from 'underscore'; import bp from './breakpoints'; diff --git a/app/assets/javascripts/create_label.js b/app/assets/javascripts/create_label.js index 9a4c9bfcc80..a999c21b2e9 100644 --- a/app/assets/javascripts/create_label.js +++ b/app/assets/javascripts/create_label.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, prefer-arrow-callback */ + +import $ from 'jquery'; import Api from './api'; import { humanize } from './lib/utils/text_utility'; diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js index 46d89c825f9..87f8854f940 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import Cookies from 'js-cookie'; import Flash from '../flash'; diff --git a/app/assets/javascripts/diff.js b/app/assets/javascripts/diff.js index 3df082e8c0c..a044fc1ab42 100644 --- a/app/assets/javascripts/diff.js +++ b/app/assets/javascripts/diff.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import axios from '~/lib/utils/axios_utils'; import flash from '~/flash'; 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 aed7cac4e62..d1260ff5373 100644 --- a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js +++ b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js @@ -1,6 +1,7 @@ /* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, quotes, no-lonely-if, max-len */ /* global CommentsStore */ +import $ from 'jquery'; import Vue from 'vue'; const CommentAndResolveBtn = Vue.extend({ diff --git a/app/assets/javascripts/diff_notes/components/diff_note_avatars.js b/app/assets/javascripts/diff_notes/components/diff_note_avatars.js index 300b02da663..180a6bd67e7 100644 --- a/app/assets/javascripts/diff_notes/components/diff_note_avatars.js +++ b/app/assets/javascripts/diff_notes/components/diff_note_avatars.js @@ -1,5 +1,6 @@ /* global CommentsStore */ +import $ from 'jquery'; import Vue from 'vue'; import collapseIcon from '../icons/collapse_icon.svg'; import Notes from '../../notes'; 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 fadc34959e1..8f9186dfb9a 100644 --- a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js +++ b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js @@ -2,6 +2,7 @@ /* global DiscussionMixins */ /* global CommentsStore */ +import $ from 'jquery'; import Vue from 'vue'; import '../mixins/discussion'; diff --git a/app/assets/javascripts/diff_notes/components/resolve_btn.js b/app/assets/javascripts/diff_notes/components/resolve_btn.js index cc9192deae3..df4c72ba0ed 100644 --- a/app/assets/javascripts/diff_notes/components/resolve_btn.js +++ b/app/assets/javascripts/diff_notes/components/resolve_btn.js @@ -2,6 +2,7 @@ /* global CommentsStore */ /* global ResolveService */ +import $ from 'jquery'; import Vue from 'vue'; import Flash from '../../flash'; diff --git a/app/assets/javascripts/diff_notes/diff_notes_bundle.js b/app/assets/javascripts/diff_notes/diff_notes_bundle.js index 5f49609fe88..e17daec6a92 100644 --- a/app/assets/javascripts/diff_notes/diff_notes_bundle.js +++ b/app/assets/javascripts/diff_notes/diff_notes_bundle.js @@ -1,6 +1,7 @@ /* eslint-disable func-names, comma-dangle, new-cap, no-new, max-len */ /* global ResolveCount */ +import $ from 'jquery'; import Vue from 'vue'; import './models/discussion'; import './models/note'; diff --git a/app/assets/javascripts/diff_notes/models/discussion.js b/app/assets/javascripts/diff_notes/models/discussion.js index 1b8a9af9390..c97c559dd14 100644 --- a/app/assets/javascripts/diff_notes/models/discussion.js +++ b/app/assets/javascripts/diff_notes/models/discussion.js @@ -1,6 +1,7 @@ /* eslint-disable space-before-function-paren, camelcase, guard-for-in, no-restricted-syntax, no-unused-vars, max-len */ /* global NoteModel */ +import $ from 'jquery'; import Vue from 'vue'; import { localTimeAgo } from '../../lib/utils/datetime_utility'; diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 1ccf96a75dc..42ecc415173 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */ + +import $ from 'jquery'; import Flash from './flash'; import GfmAutoComplete from './gfm_auto_complete'; import { convertPermissionToBoolean } from './lib/utils/common_utils'; diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js index ba89e5726fa..5528ad9f38d 100644 --- a/app/assets/javascripts/dropzone_input.js +++ b/app/assets/javascripts/dropzone_input.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Dropzone from 'dropzone'; import _ from 'underscore'; import './preview_markdown'; diff --git a/app/assets/javascripts/due_date_select.js b/app/assets/javascripts/due_date_select.js index 417258e0092..842a4255f08 100644 --- a/app/assets/javascripts/due_date_select.js +++ b/app/assets/javascripts/due_date_select.js @@ -1,5 +1,6 @@ /* global dateFormat */ +import $ from 'jquery'; import Pikaday from 'pikaday'; import axios from './lib/utils/axios_utils'; import { parsePikadayDate, pikadayToString } from './lib/utils/datefix'; diff --git a/app/assets/javascripts/environments/components/environment_stop.vue b/app/assets/javascripts/environments/components/environment_stop.vue index 1eef17bf1fe..dda7429a726 100644 --- a/app/assets/javascripts/environments/components/environment_stop.vue +++ b/app/assets/javascripts/environments/components/environment_stop.vue @@ -3,6 +3,8 @@ * Renders the stop "button" that allows stop an environment. * Used in environments table. */ + + import $ from 'jquery'; import eventHub from '../event_hub'; import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import tooltip from '../../vue_shared/directives/tooltip'; diff --git a/app/assets/javascripts/experimental_flags.js b/app/assets/javascripts/experimental_flags.js index 6ee65ca72f9..1d60847147b 100644 --- a/app/assets/javascripts/experimental_flags.js +++ b/app/assets/javascripts/experimental_flags.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Cookies from 'js-cookie'; export default () => { diff --git a/app/assets/javascripts/feature_highlight/feature_highlight.js b/app/assets/javascripts/feature_highlight/feature_highlight.js index d65cc6d5d7d..c50ac667c20 100644 --- a/app/assets/javascripts/feature_highlight/feature_highlight.js +++ b/app/assets/javascripts/feature_highlight/feature_highlight.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import { getSelector, diff --git a/app/assets/javascripts/feature_highlight/feature_highlight_helper.js b/app/assets/javascripts/feature_highlight/feature_highlight_helper.js index 939d12237f3..f480e72961c 100644 --- a/app/assets/javascripts/feature_highlight/feature_highlight_helper.js +++ b/app/assets/javascripts/feature_highlight/feature_highlight_helper.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import axios from '../lib/utils/axios_utils'; import { __ } from '../locale'; import Flash from '../flash'; diff --git a/app/assets/javascripts/filterable_list.js b/app/assets/javascripts/filterable_list.js index a10f027de53..b17ba3c21db 100644 --- a/app/assets/javascripts/filterable_list.js +++ b/app/assets/javascripts/filterable_list.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import axios from './lib/utils/axios_utils'; diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js index 57a1fa107e5..8259133c95b 100644 --- a/app/assets/javascripts/gfm_auto_complete.js +++ b/app/assets/javascripts/gfm_auto_complete.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import glRegexp from './lib/utils/regexp'; import AjaxCache from './lib/utils/ajax_cache'; @@ -131,9 +132,8 @@ class GfmAutoComplete { callbacks: { ...this.getDefaultCallbacks(), matcher(flag, subtext) { - const relevantText = subtext.trim().split(/\s/).pop(); const regexp = new RegExp(`(?:[^${glRegexp.unicodeLetters}0-9:]|\n|^):([^:]*)$`, 'gi'); - const match = regexp.exec(relevantText); + const match = regexp.exec(subtext); return match && match.length ? match[1] : null; }, diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index 6cf78bab6ad..86b34a6e360 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -1,5 +1,7 @@ /* eslint-disable func-names, no-underscore-dangle, space-before-function-paren, no-var, one-var, one-var-declaration-per-line, prefer-rest-params, max-len, vars-on-top, wrap-iife, no-unused-vars, quotes, no-shadow, no-cond-assign, prefer-arrow-callback, no-return-assign, no-else-return, camelcase, comma-dangle, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, prefer-template, no-param-reassign, no-loop-func, no-mixed-operators */ /* global fuzzaldrinPlus */ + +import $ from 'jquery'; import _ from 'underscore'; import fuzzaldrinPlus from 'fuzzaldrin-plus'; import axios from './lib/utils/axios_utils'; @@ -576,7 +578,7 @@ GitLabDropdown = (function() { for (var i = 0; i < html.length; i += 1) { var el = html[i]; - if (el instanceof jQuery) { + if (el instanceof $) { el = el.get(0); } diff --git a/app/assets/javascripts/gl_field_error.js b/app/assets/javascripts/gl_field_error.js index bd63f6f16f0..972b2252acb 100644 --- a/app/assets/javascripts/gl_field_error.js +++ b/app/assets/javascripts/gl_field_error.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + /** * This class overrides the browser's validation error bubbles, displaying custom * error messages for invalid fields instead. To begin validating any form, add the diff --git a/app/assets/javascripts/gl_field_errors.js b/app/assets/javascripts/gl_field_errors.js index 73bcbd93565..b9c51045b1d 100644 --- a/app/assets/javascripts/gl_field_errors.js +++ b/app/assets/javascripts/gl_field_errors.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import GlFieldError from './gl_field_error'; const customValidationFlag = 'gl-field-error-ignore'; diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js index 2d40856e038..184c98813f1 100644 --- a/app/assets/javascripts/gl_form.js +++ b/app/assets/javascripts/gl_form.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import autosize from 'autosize'; import GfmAutoComplete from './gfm_auto_complete'; import dropzoneInput from './dropzone_input'; diff --git a/app/assets/javascripts/gpg_badges.js b/app/assets/javascripts/gpg_badges.js index 6bf21f4f27d..502e3569321 100644 --- a/app/assets/javascripts/gpg_badges.js +++ b/app/assets/javascripts/gpg_badges.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { parseQueryStringIntoObject } from '~/lib/utils/common_utils'; import axios from '~/lib/utils/axios_utils'; import flash from '~/flash'; diff --git a/app/assets/javascripts/group.js b/app/assets/javascripts/group.js index 7732edde1e7..4365305c168 100644 --- a/app/assets/javascripts/group.js +++ b/app/assets/javascripts/group.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default class Group { constructor() { this.groupPath = $('#group_path'); diff --git a/app/assets/javascripts/group_avatar.js b/app/assets/javascripts/group_avatar.js index 2168ff3a8ba..beaac61e887 100644 --- a/app/assets/javascripts/group_avatar.js +++ b/app/assets/javascripts/group_avatar.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default function groupAvatar() { $('.js-choose-group-avatar-button').on('click', function onClickGroupAvatar() { const form = $(this).closest('form'); diff --git a/app/assets/javascripts/group_label_subscription.js b/app/assets/javascripts/group_label_subscription.js index df9429b1e02..5648cb9a888 100644 --- a/app/assets/javascripts/group_label_subscription.js +++ b/app/assets/javascripts/group_label_subscription.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import axios from './lib/utils/axios_utils'; import flash from './flash'; import { __ } from './locale'; diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue index 0578f43d5af..63bb5832bd0 100644 --- a/app/assets/javascripts/groups/components/app.vue +++ b/app/assets/javascripts/groups/components/app.vue @@ -1,6 +1,7 @@ <script> /* global Flash */ +import $ from 'jquery'; import { s__ } from '~/locale'; import loadingIcon from '~/vue_shared/components/loading_icon.vue'; import modal from '~/vue_shared/components/modal.vue'; diff --git a/app/assets/javascripts/groups/groups_filterable_list.js b/app/assets/javascripts/groups/groups_filterable_list.js index 31d56d15c23..e6db1746487 100644 --- a/app/assets/javascripts/groups/groups_filterable_list.js +++ b/app/assets/javascripts/groups/groups_filterable_list.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import FilterableList from '~/filterable_list'; import eventHub from './event_hub'; import { normalizeHeaders, getParameterByName } from '../lib/utils/common_utils'; diff --git a/app/assets/javascripts/groups/transfer_dropdown.js b/app/assets/javascripts/groups/transfer_dropdown.js index 85b7b08db4d..e0eb118ddf7 100644 --- a/app/assets/javascripts/groups/transfer_dropdown.js +++ b/app/assets/javascripts/groups/transfer_dropdown.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default class TransferDropdown { constructor() { this.groupDropdown = $('.js-groups-dropdown'); diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js index 12fc5f9b5c9..310f6fe06cf 100644 --- a/app/assets/javascripts/groups_select.js +++ b/app/assets/javascripts/groups_select.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import axios from './lib/utils/axios_utils'; import Api from './api'; import { normalizeHeaders } from './lib/utils/common_utils'; diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js index 33a352e158a..4ae3a714bee 100644 --- a/app/assets/javascripts/header.js +++ b/app/assets/javascripts/header.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { highCountTrim } from '~/lib/utils/text_utility'; /** diff --git a/app/assets/javascripts/help/help.js b/app/assets/javascripts/help/help.js index d02477b19a2..f5333042bb8 100644 --- a/app/assets/javascripts/help/help.js +++ b/app/assets/javascripts/help/help.js @@ -1,4 +1,7 @@ // We will render the icons list here + +import $ from 'jquery'; + export default () => { if ($('#user-content-gitlab-icons').length > 0) { const $iconsHeader = $('#user-content-gitlab-icons'); diff --git a/app/assets/javascripts/how_to_merge.js b/app/assets/javascripts/how_to_merge.js index 12e6f24595a..bb734246584 100644 --- a/app/assets/javascripts/how_to_merge.js +++ b/app/assets/javascripts/how_to_merge.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default () => { const modal = $('#modal_merge_info'); diff --git a/app/assets/javascripts/image_diff/image_diff.js b/app/assets/javascripts/image_diff/image_diff.js index f3af92cf2b0..fab0255c378 100644 --- a/app/assets/javascripts/image_diff/image_diff.js +++ b/app/assets/javascripts/image_diff/image_diff.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import imageDiffHelper from './helpers/index'; import ImageBadge from './image_badge'; import { isImageLoaded } from '../lib/utils/image_utility'; diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js index 523bd2adb93..b469e1e2adc 100644 --- a/app/assets/javascripts/importer_status.js +++ b/app/assets/javascripts/importer_status.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import { __, sprintf } from './locale'; import axios from './lib/utils/axios_utils'; diff --git a/app/assets/javascripts/init_changes_dropdown.js b/app/assets/javascripts/init_changes_dropdown.js index 1bab7965c19..09cca1dc7d9 100644 --- a/app/assets/javascripts/init_changes_dropdown.js +++ b/app/assets/javascripts/init_changes_dropdown.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import stickyMonitor from './lib/utils/sticky'; export default (stickyTop) => { diff --git a/app/assets/javascripts/init_labels.js b/app/assets/javascripts/init_labels.js index 5f20055510f..15da5d5cceb 100644 --- a/app/assets/javascripts/init_labels.js +++ b/app/assets/javascripts/init_labels.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import LabelManager from './label_manager'; import GroupLabelSubscription from './group_label_subscription'; import ProjectLabelSubscription from './project_label_subscription'; diff --git a/app/assets/javascripts/integrations/integration_settings_form.js b/app/assets/javascripts/integrations/integration_settings_form.js index 2848fe003cb..741894b5e6c 100644 --- a/app/assets/javascripts/integrations/integration_settings_form.js +++ b/app/assets/javascripts/integrations/integration_settings_form.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import axios from '../lib/utils/axios_utils'; import flash from '../flash'; diff --git a/app/assets/javascripts/issuable/auto_width_dropdown_select.js b/app/assets/javascripts/issuable/auto_width_dropdown_select.js index 14a2bfbe4e0..b2c2de9e5de 100644 --- a/app/assets/javascripts/issuable/auto_width_dropdown_select.js +++ b/app/assets/javascripts/issuable/auto_width_dropdown_select.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + let instanceCount = 0; class AutoWidthDropdownSelect { diff --git a/app/assets/javascripts/issuable_bulk_update_actions.js b/app/assets/javascripts/issuable_bulk_update_actions.js index 8c1b2e78ca4..e003fb1d127 100644 --- a/app/assets/javascripts/issuable_bulk_update_actions.js +++ b/app/assets/javascripts/issuable_bulk_update_actions.js @@ -1,4 +1,6 @@ /* eslint-disable comma-dangle, quotes, consistent-return, func-names, array-callback-return, space-before-function-paren, prefer-arrow-callback, max-len, no-unused-expressions, no-sequences, no-underscore-dangle, no-unused-vars, no-param-reassign */ + +import $ from 'jquery'; import _ from 'underscore'; import axios from './lib/utils/axios_utils'; import Flash from './flash'; diff --git a/app/assets/javascripts/issuable_bulk_update_sidebar.js b/app/assets/javascripts/issuable_bulk_update_sidebar.js index 2056efe701b..2307c8e0d85 100644 --- a/app/assets/javascripts/issuable_bulk_update_sidebar.js +++ b/app/assets/javascripts/issuable_bulk_update_sidebar.js @@ -1,5 +1,6 @@ /* eslint-disable class-methods-use-this, no-new */ +import $ from 'jquery'; import IssuableBulkUpdateActions from './issuable_bulk_update_actions'; import MilestoneSelect from './milestone_select'; import issueStatusSelect from './issue_status_select'; diff --git a/app/assets/javascripts/issuable_context.js b/app/assets/javascripts/issuable_context.js index da99394ff90..7470d634b99 100644 --- a/app/assets/javascripts/issuable_context.js +++ b/app/assets/javascripts/issuable_context.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Cookies from 'js-cookie'; import bp from './breakpoints'; import UsersSelect from './users_select'; diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js index fdfad0b6a4f..bb8b3d91e40 100644 --- a/app/assets/javascripts/issuable_form.js +++ b/app/assets/javascripts/issuable_form.js @@ -1,6 +1,7 @@ /* eslint-disable func-names, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-new, object-shorthand, no-unused-vars, comma-dangle, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, max-len */ /* global GitLab */ +import $ from 'jquery'; import Pikaday from 'pikaday'; import Autosave from './autosave'; import UsersSelect from './users_select'; diff --git a/app/assets/javascripts/issuable_index.js b/app/assets/javascripts/issuable_index.js index 0683ca82a38..06ec4546164 100644 --- a/app/assets/javascripts/issuable_index.js +++ b/app/assets/javascripts/issuable_index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import axios from './lib/utils/axios_utils'; import flash from './flash'; import { __ } from './locale'; diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js index 333bbd9e0ba..5113ac6775d 100644 --- a/app/assets/javascripts/issue.js +++ b/app/assets/javascripts/issue.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, max-len */ + +import $ from 'jquery'; import axios from './lib/utils/axios_utils'; import { addDelimiter } from './lib/utils/text_utility'; import flash from './flash'; diff --git a/app/assets/javascripts/issue_show/components/description.vue b/app/assets/javascripts/issue_show/components/description.vue index 1338be0ec4b..ae577e04a56 100644 --- a/app/assets/javascripts/issue_show/components/description.vue +++ b/app/assets/javascripts/issue_show/components/description.vue @@ -1,4 +1,5 @@ <script> + import $ from 'jquery'; import animateMixin from '../mixins/animate'; import TaskList from '../../task_list'; import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor'; 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 1ad0e59287e..7db0488e306 100644 --- a/app/assets/javascripts/issue_show/components/fields/description_template.vue +++ b/app/assets/javascripts/issue_show/components/fields/description_template.vue @@ -1,4 +1,5 @@ <script> + import $ from 'jquery'; import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors'; export default { diff --git a/app/assets/javascripts/issue_status_select.js b/app/assets/javascripts/issue_status_select.js index 71c0f894389..c14803c80e7 100644 --- a/app/assets/javascripts/issue_status_select.js +++ b/app/assets/javascripts/issue_status_select.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default function issueStatusSelect() { $('.js-issue-status').each((i, el) => { const fieldName = $(el).data('fieldName'); diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js index f39ae764d3c..ace45e9dd29 100644 --- a/app/assets/javascripts/job.js +++ b/app/assets/javascripts/job.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import axios from './lib/utils/axios_utils'; import { visitUrl } from './lib/utils/url_utility'; diff --git a/app/assets/javascripts/label_manager.js b/app/assets/javascripts/label_manager.js index 61b40f79db1..e230dbbd4ac 100644 --- a/app/assets/javascripts/label_manager.js +++ b/app/assets/javascripts/label_manager.js @@ -1,4 +1,6 @@ /* eslint-disable comma-dangle, class-methods-use-this, no-underscore-dangle, no-param-reassign, no-unused-vars, consistent-return, func-names, space-before-function-paren, max-len */ + +import $ from 'jquery'; import Sortable from 'vendor/Sortable'; import flash from './flash'; diff --git a/app/assets/javascripts/labels.js b/app/assets/javascripts/labels.js index 7aab13ed9c6..d85ae851706 100644 --- a/app/assets/javascripts/labels.js +++ b/app/assets/javascripts/labels.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default class Labels { constructor() { this.setSuggestedColor = this.setSuggestedColor.bind(this); diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js index 9b46bbf83da..824d3f7ca09 100644 --- a/app/assets/javascripts/labels_select.js +++ b/app/assets/javascripts/labels_select.js @@ -1,6 +1,8 @@ /* eslint-disable no-useless-return, func-names, space-before-function-paren, wrap-iife, 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, no-return-assign, camelcase, prefer-spread */ /* global Issuable */ /* global ListLabel */ + +import $ from 'jquery'; import _ from 'underscore'; import { __ } from './locale'; import axios from './lib/utils/axios_utils'; diff --git a/app/assets/javascripts/layout_nav.js b/app/assets/javascripts/layout_nav.js index 1b4900827b8..e3177188772 100644 --- a/app/assets/javascripts/layout_nav.js +++ b/app/assets/javascripts/layout_nav.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import ContextualSidebar from './contextual_sidebar'; import initFlyOutNav from './fly_out_nav'; diff --git a/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js b/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js index 0bf2ba6acc2..3873f4528ce 100644 --- a/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js +++ b/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + /** * Linked Tabs * diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index ed90db317df..0830ebe9e4e 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -1,4 +1,4 @@ -import jQuery from 'jquery'; +import $ from 'jquery'; import Cookies from 'js-cookie'; import axios from './axios_utils'; import { getLocationHash } from './url_utility'; @@ -142,7 +142,7 @@ export const isMetaClick = e => e.metaKey || e.ctrlKey || e.which === 2; export const scrollToElement = (element) => { let $el = element; - if (!(element instanceof jQuery)) { + if (!(element instanceof $)) { $el = $(element); } const top = $el.offset().top; diff --git a/app/assets/javascripts/lib/utils/csrf.js b/app/assets/javascripts/lib/utils/csrf.js index 0bdb547d31a..ca9828c4682 100644 --- a/app/assets/javascripts/lib/utils/csrf.js +++ b/app/assets/javascripts/lib/utils/csrf.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + /* This module provides easy access to the CSRF token and caches it for re-use. It also exposes some values commonly used in relation diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index d6cccbef42b..c3d94d63c13 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import timeago from 'timeago.js'; import dateFormat from 'vendor/date.format'; import { pluralize } from './text_utility'; diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js index 5dc98b4a920..470e3e5c52e 100644 --- a/app/assets/javascripts/lib/utils/text_markdown.js +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -1,5 +1,7 @@ /* eslint-disable import/prefer-default-export, func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, max-len, vars-on-top */ +import $ from 'jquery'; + const textUtils = {}; textUtils.selectedText = function(text, textarea) { diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index c0ce0786518..94d03621bff 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -65,20 +65,6 @@ export function capitalizeFirstCharacter(text) { return `${text[0].toUpperCase()}${text.slice(1)}`; } -export function camelCase(str) { - return str.replace(/_+([a-z])/gi, ($1, $2) => $2.toUpperCase()); -} - -export function camelCaseKeys(obj = {}) { - return Object.keys(obj).reduce((acc, key) => { - const camelKey = camelCase(key); - return { - ...acc, - [camelKey]: obj[key], - }; - }, {}); -} - /** * Replaces all html tags from a string with the given replacement. * diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js index e5c1fce3db9..f2323f57455 100644 --- a/app/assets/javascripts/line_highlighter.js +++ b/app/assets/javascripts/line_highlighter.js @@ -1,5 +1,7 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-underscore-dangle, no-param-reassign, prefer-template, quotes, comma-dangle, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-else-return, max-len */ +import $ from 'jquery'; + // LineHighlighter // // Handles single- and multi-line selection and highlight for blob views. diff --git a/app/assets/javascripts/logo.js b/app/assets/javascripts/logo.js index 3688a57937e..403e216e70f 100644 --- a/app/assets/javascripts/logo.js +++ b/app/assets/javascripts/logo.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default function initLogoAnimation() { window.addEventListener('beforeunload', () => { $('.tanuki-logo').addClass('animate'); diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 53b01cca1d3..870285f7940 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -1,5 +1,6 @@ /* eslint-disable import/first */ /* global ConfirmDangerModal */ +/* global $ */ import jQuery from 'jquery'; import Cookies from 'js-cookie'; diff --git a/app/assets/javascripts/member_expiration_date.js b/app/assets/javascripts/member_expiration_date.js index 84e70e35bad..d27922a2099 100644 --- a/app/assets/javascripts/member_expiration_date.js +++ b/app/assets/javascripts/member_expiration_date.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Pikaday from 'pikaday'; import { parsePikadayDate, pikadayToString } from './lib/utils/datefix'; diff --git a/app/assets/javascripts/members.js b/app/assets/javascripts/members.js index 330ebed5f73..7d0c701fd70 100644 --- a/app/assets/javascripts/members.js +++ b/app/assets/javascripts/members.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default class Members { constructor() { this.addListeners(); diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js index 8be7314ded8..db1d09eb2f2 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js +++ b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js @@ -1,5 +1,6 @@ /* eslint-disable comma-dangle, object-shorthand, no-param-reassign, camelcase, no-nested-ternary, no-continue, max-len */ +import $ from 'jquery'; import Vue from 'vue'; import Cookies from 'js-cookie'; diff --git a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js index 66b258839ae..4abd5433bb5 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js +++ b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js @@ -1,5 +1,6 @@ /* eslint-disable new-cap, comma-dangle, no-new */ +import $ from 'jquery'; import Vue from 'vue'; import Flash from '../flash'; import initIssuableSidebar from '../init_issuable_sidebar'; diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index a64093afcf4..d8222ebec63 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, no-underscore-dangle, one-var, one-var-declaration-per-line, consistent-return, dot-notation, quote-props, comma-dangle, object-shorthand, max-len, prefer-arrow-callback */ + +import $ from 'jquery'; import { __ } from '~/locale'; import TaskList from './task_list'; import MergeRequestTabs from './merge_request_tabs'; diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 46789e324c2..f01aef45500 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -1,5 +1,6 @@ /* eslint-disable no-new, class-methods-use-this */ +import $ from 'jquery'; import Cookies from 'js-cookie'; import axios from './lib/utils/axios_utils'; import flash from './flash'; diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js index b1d74250dfd..e6e3a66aa20 100644 --- a/app/assets/javascripts/milestone.js +++ b/app/assets/javascripts/milestone.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import axios from './lib/utils/axios_utils'; import flash from './flash'; diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index c259d5405bd..add07c156a4 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -1,6 +1,8 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-underscore-dangle, prefer-arrow-callback, max-len, one-var, one-var-declaration-per-line, no-unused-vars, object-shorthand, comma-dangle, no-else-return, no-self-compare, consistent-return, no-param-reassign, no-shadow */ /* global Issuable */ /* global ListMilestone */ + +import $ from 'jquery'; import _ from 'underscore'; import axios from './lib/utils/axios_utils'; import { timeFor } from './lib/utils/datetime_utility'; diff --git a/app/assets/javascripts/mini_pipeline_graph_dropdown.js b/app/assets/javascripts/mini_pipeline_graph_dropdown.js index c7bccd483ac..01399de4c62 100644 --- a/app/assets/javascripts/mini_pipeline_graph_dropdown.js +++ b/app/assets/javascripts/mini_pipeline_graph_dropdown.js @@ -1,4 +1,6 @@ /* eslint-disable no-new */ + +import $ from 'jquery'; import flash from './flash'; import axios from './lib/utils/axios_utils'; diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue index 9e67a6f2146..42615d2bb8e 100644 --- a/app/assets/javascripts/monitoring/components/graph.vue +++ b/app/assets/javascripts/monitoring/components/graph.vue @@ -209,6 +209,7 @@ const xAxis = d3.axisBottom() .scale(axisXScale) + .ticks(this.graphWidth / 120) .tickFormat(timeScaleFormat); const yAxis = d3.axisLeft() diff --git a/app/assets/javascripts/namespace_select.js b/app/assets/javascripts/namespace_select.js index aa377327107..c7a8aac79df 100644 --- a/app/assets/javascripts/namespace_select.js +++ b/app/assets/javascripts/namespace_select.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, comma-dangle, object-shorthand, no-else-return, prefer-template, quotes, prefer-arrow-callback, max-len */ + +import $ from 'jquery'; import Api from './api'; import { mergeUrlParams } from './lib/utils/url_utility'; diff --git a/app/assets/javascripts/network/branch_graph.js b/app/assets/javascripts/network/branch_graph.js index d3edcb724f1..bd007c707f2 100644 --- a/app/assets/javascripts/network/branch_graph.js +++ b/app/assets/javascripts/network/branch_graph.js @@ -1,5 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, quotes, comma-dangle, one-var, one-var-declaration-per-line, no-mixed-operators, no-loop-func, no-floating-decimal, consistent-return, no-unused-vars, prefer-template, prefer-arrow-callback, camelcase, max-len */ +import $ from 'jquery'; import { __ } from '../locale'; import axios from '../lib/utils/axios_utils'; import flash from '../flash'; diff --git a/app/assets/javascripts/new_branch_form.js b/app/assets/javascripts/new_branch_form.js index 77733b67c4d..40c08ee0ace 100644 --- a/app/assets/javascripts/new_branch_form.js +++ b/app/assets/javascripts/new_branch_form.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, one-var, prefer-rest-params, max-len, vars-on-top, 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, object-shorthand */ + +import $ from 'jquery'; import RefSelectDropdown from './ref_select_dropdown'; export default class NewBranchForm { diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index c640003d958..6d1b2f452c0 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -16,6 +16,10 @@ import Autosize from 'autosize'; import 'vendor/jquery.caret'; // required by jquery.atwho import 'vendor/jquery.atwho'; import AjaxCache from '~/lib/utils/ajax_cache'; +import Vue from 'vue'; +import syntaxHighlight from '~/syntax_highlight'; +import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue'; +import { __ } from '~/locale'; import axios from './lib/utils/axios_utils'; import { getLocationHash } from './lib/utils/url_utility'; import Flash from './flash'; @@ -99,6 +103,13 @@ export default class Notes { $('.note-edit-form').clone() .addClass('mr-note-edit-form').insertAfter('.note-edit-form'); } + + const hash = getLocationHash(); + const $anchor = hash && document.getElementById(hash); + + if ($anchor) { + this.loadLazyDiff({ currentTarget: $anchor }); + } } setViewType(view) { @@ -135,6 +146,8 @@ export default class Notes { this.$wrapperEl.on('click', '.js-close-discussion-note-form', this.cancelDiscussionForm); // toggle commit list this.$wrapperEl.on('click', '.system-note-commit-list-toggler', this.toggleCommitList); + + this.$wrapperEl.on('click', '.js-toggle-lazy-diff', this.loadLazyDiff); // fetch notes when tab becomes visible this.$wrapperEl.on('visibilitychange', this.visibilityChange); // when issue status changes, we need to refresh data @@ -173,6 +186,7 @@ export default class Notes { this.$wrapperEl.off('keydown', '.js-note-text'); this.$wrapperEl.off('click', '.js-comment-resolve-button'); this.$wrapperEl.off('click', '.system-note-commit-list-toggler'); + this.$wrapperEl.off('click', '.js-toggle-lazy-diff'); this.$wrapperEl.off('ajax:success', '.js-main-target-form'); this.$wrapperEl.off('ajax:success', '.js-discussion-note-form'); this.$wrapperEl.off('ajax:complete', '.js-main-target-form'); @@ -1207,6 +1221,60 @@ export default class Notes { return this.notesCountBadge.text(parseInt(this.notesCountBadge.text(), 10) + updateCount); } + static renderPlaceholderComponent($container) { + const el = $container.find('.js-code-placeholder').get(0); + new Vue({ // eslint-disable-line no-new + el, + components: { + SkeletonLoadingContainer, + }, + render(createElement) { + return createElement('skeleton-loading-container'); + }, + }); + } + + static renderDiffContent($container, data) { + const { discussion_html } = data; + const lines = $(discussion_html).find('.line_holder'); + lines.addClass('fade-in'); + $container.find('tbody').prepend(lines); + const fileHolder = $container.find('.file-holder'); + $container.find('.line-holder-placeholder').remove(); + syntaxHighlight(fileHolder); + } + + static renderDiffError($container) { + $container.find('.line_content').html( + $(` + <div class="nothing-here-block"> + ${__('Unable to load the diff.')} <a class="js-toggle-lazy-diff" href="javascript:void(0)">Try again</a>? + </div> + `), + ); + } + + loadLazyDiff(e) { + const $container = $(e.currentTarget).closest('.js-toggle-container'); + Notes.renderPlaceholderComponent($container); + + $container.find('.js-toggle-lazy-diff').removeClass('js-toggle-lazy-diff'); + + const tableEl = $container.find('tbody'); + if (tableEl.length === 0) return; + + const fileHolder = $container.find('.file-holder'); + const url = fileHolder.data('linesPath'); + + axios.get(url) + .then(({ data }) => { + Notes.renderDiffContent($container, data); + }) + .catch(() => { + Notes.renderDiffError($container); + }); + } + toggleCommitList(e) { const $element = $(e.currentTarget); const $closestSystemCommitList = $element.siblings('.system-note-commit-list'); diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue index b85c1a6ad72..42bc383f4d2 100644 --- a/app/assets/javascripts/notes/components/comment_form.vue +++ b/app/assets/javascripts/notes/components/comment_form.vue @@ -1,5 +1,6 @@ <script> - import { mapActions, mapGetters } from 'vuex'; + import $ from 'jquery'; + import { mapActions, mapGetters, mapState } from 'vuex'; import _ from 'underscore'; import Autosize from 'autosize'; import { __, sprintf } from '~/locale'; @@ -52,6 +53,9 @@ 'getNotesData', 'openState', ]), + ...mapState([ + 'isToggleStateButtonLoading', + ]), noteableDisplayName() { return this.noteableType.replace(/_/g, ' '); }, @@ -142,6 +146,7 @@ 'closeIssue', 'reopenIssue', 'toggleIssueLocalState', + 'toggleStateButtonLoading', ]), setIsSubmitButtonDisabled(note, isSubmitting) { if (!_.isEmpty(note) && !isSubmitting) { @@ -169,13 +174,14 @@ if (this.noteType === constants.DISCUSSION) { noteData.data.note.type = constants.DISCUSSION_NOTE; } + this.note = ''; // Empty textarea while being requested. Repopulate in catch this.resizeTextarea(); this.stopPolling(); this.saveNote(noteData) .then((res) => { - this.isSubmitting = false; + this.enableButton(); this.restartPolling(); if (res.errors) { @@ -197,7 +203,7 @@ } }) .catch(() => { - this.isSubmitting = false; + this.enableButton(); this.discard(false); const msg = `Your comment could not be submitted! @@ -219,6 +225,7 @@ Please check your network connection and try again.`; .then(() => this.enableButton()) .catch(() => { this.enableButton(); + this.toggleStateButtonLoading(false); Flash( sprintf( __('Something went wrong while closing the %{issuable}. Please try again later'), @@ -231,6 +238,7 @@ Please check your network connection and try again.`; .then(() => this.enableButton()) .catch(() => { this.enableButton(); + this.toggleStateButtonLoading(false); Flash( sprintf( __('Something went wrong while reopening the %{issuable}. Please try again later'), @@ -418,13 +426,13 @@ append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown" <loading-button v-if="canUpdateIssue" - :loading="isSubmitting" + :loading="isToggleStateButtonLoading" @click="handleSave(true)" :container-class="[ actionButtonClassNames, 'btn btn-comment btn-comment-and-close js-action-button' ]" - :disabled="isSubmitting" + :disabled="isToggleStateButtonLoading || isSubmitting" :label="issueActionButtonTitle" /> diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue index 75a32709ad5..1dba84fac18 100644 --- a/app/assets/javascripts/notes/components/diff_with_note.vue +++ b/app/assets/javascripts/notes/components/diff_with_note.vue @@ -1,4 +1,5 @@ <script> + import $ from 'jquery'; import syntaxHighlight from '~/syntax_highlight'; import imageDiffHelper from '~/image_diff/helpers/index'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; diff --git a/app/assets/javascripts/notes/components/note_body.vue b/app/assets/javascripts/notes/components/note_body.vue index ca12df9db64..a94f1a28a4c 100644 --- a/app/assets/javascripts/notes/components/note_body.vue +++ b/app/assets/javascripts/notes/components/note_body.vue @@ -1,4 +1,5 @@ <script> + import $ from 'jquery'; import noteEditedText from './note_edited_text.vue'; import noteAwardsList from './note_awards_list.vue'; import noteAttachment from './note_attachment.vue'; diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue index 4d17bd5acc2..6d5501d7d98 100644 --- a/app/assets/javascripts/notes/components/noteable_note.vue +++ b/app/assets/javascripts/notes/components/noteable_note.vue @@ -1,4 +1,5 @@ <script> + import $ from 'jquery'; import { mapGetters, mapActions } from 'vuex'; import { escape } from 'underscore'; import Flash from '../../flash'; diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue index 74afed5560b..c97472c879c 100644 --- a/app/assets/javascripts/notes/components/notes_app.vue +++ b/app/assets/javascripts/notes/components/notes_app.vue @@ -1,4 +1,5 @@ <script> + import $ from 'jquery'; import { mapGetters, mapActions } from 'vuex'; import { getLocationHash } from '../../lib/utils/url_utility'; import Flash from '../../flash'; diff --git a/app/assets/javascripts/notes/mixins/autosave.js b/app/assets/javascripts/notes/mixins/autosave.js index a3d897f2f12..837a4029346 100644 --- a/app/assets/javascripts/notes/mixins/autosave.js +++ b/app/assets/javascripts/notes/mixins/autosave.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Autosave from '../../autosave'; import { capitalizeFirstCharacter } from '../../lib/utils/text_utility'; diff --git a/app/assets/javascripts/notes/services/notes_service.js b/app/assets/javascripts/notes/services/notes_service.js index 4766351dfc5..b4c19a9ec22 100644 --- a/app/assets/javascripts/notes/services/notes_service.js +++ b/app/assets/javascripts/notes/services/notes_service.js @@ -27,10 +27,11 @@ export default { return Vue.http[method](endpoint); }, poll(data = {}) { - const { endpoint, lastFetchedAt } = data; + const endpoint = data.notesData.notesPath; + const lastFetchedAt = data.lastFetchedAt; const options = { headers: { - 'X-Last-Fetched-At': lastFetchedAt, + 'X-Last-Fetched-At': lastFetchedAt ? `${lastFetchedAt}` : undefined, }, }; diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index 42fc2a131b8..ebbacb576d6 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Visibility from 'visibilityjs'; import Flash from '../../flash'; import Poll from '../../lib/utils/poll'; @@ -70,21 +71,32 @@ export const toggleResolveNote = ({ commit }, { endpoint, isResolved, discussion commit(mutationType, res); }); -export const closeIssue = ({ commit, dispatch, state }) => service +export const closeIssue = ({ commit, dispatch, state }) => { + dispatch('toggleStateButtonLoading', true); + return service .toggleIssueState(state.notesData.closePath) .then(res => res.json()) .then((data) => { commit(types.CLOSE_ISSUE); dispatch('emitStateChangedEvent', data); + dispatch('toggleStateButtonLoading', false); }); +}; -export const reopenIssue = ({ commit, dispatch, state }) => service +export const reopenIssue = ({ commit, dispatch, state }) => { + dispatch('toggleStateButtonLoading', true); + return service .toggleIssueState(state.notesData.reopenPath) .then(res => res.json()) .then((data) => { commit(types.REOPEN_ISSUE); dispatch('emitStateChangedEvent', data); + dispatch('toggleStateButtonLoading', false); }); +}; + +export const toggleStateButtonLoading = ({ commit }, value) => + commit(types.TOGGLE_STATE_BUTTON_LOADING, value); export const emitStateChangedEvent = ({ commit, getters }, data) => { const event = new CustomEvent('issuable_vue_app:change', { detail: { @@ -197,18 +209,16 @@ const pollSuccessCallBack = (resp, commit, state, getters) => { }); } - commit(types.SET_LAST_FETCHED_AT, resp.lastFetchedAt); + commit(types.SET_LAST_FETCHED_AT, resp.last_fetched_at); return resp; }; export const poll = ({ commit, state, getters }) => { - const requestData = { endpoint: state.notesData.notesPath, lastFetchedAt: state.lastFetchedAt }; - eTagPoll = new Poll({ resource: service, method: 'poll', - data: requestData, + data: state, successCallback: resp => resp.json() .then(data => pollSuccessCallBack(data, commit, state, getters)), errorCallback: () => Flash('Something went wrong while fetching latest comments.'), @@ -217,7 +227,7 @@ export const poll = ({ commit, state, getters }) => { if (!Visibility.hidden()) { eTagPoll.makeRequest(); } else { - service.poll(requestData); + service.poll(state); } Visibility.change(() => { diff --git a/app/assets/javascripts/notes/stores/index.js b/app/assets/javascripts/notes/stores/index.js index 488a9ca38d3..9ed19bf171e 100644 --- a/app/assets/javascripts/notes/stores/index.js +++ b/app/assets/javascripts/notes/stores/index.js @@ -12,6 +12,9 @@ export default new Vuex.Store({ targetNoteHash: null, lastFetchedAt: null, + // View layer + isToggleStateButtonLoading: false, + // holds endpoints and permissions provided through haml notesData: {}, userData: {}, diff --git a/app/assets/javascripts/notes/stores/mutation_types.js b/app/assets/javascripts/notes/stores/mutation_types.js index da1b5a9e51a..b455e23ecde 100644 --- a/app/assets/javascripts/notes/stores/mutation_types.js +++ b/app/assets/javascripts/notes/stores/mutation_types.js @@ -17,3 +17,4 @@ export const UPDATE_DISCUSSION = 'UPDATE_DISCUSSION'; // Issue export const CLOSE_ISSUE = 'CLOSE_ISSUE'; export const REOPEN_ISSUE = 'REOPEN_ISSUE'; +export const TOGGLE_STATE_BUTTON_LOADING = 'TOGGLE_STATE_BUTTON_LOADING'; diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js index 963b40be3fd..9308daa36f1 100644 --- a/app/assets/javascripts/notes/stores/mutations.js +++ b/app/assets/javascripts/notes/stores/mutations.js @@ -90,19 +90,21 @@ export default { const notes = []; notesData.forEach((note) => { - const nn = Object.assign({}, note); - // To support legacy notes, should be very rare case. if (note.individual_note && note.notes.length > 1) { note.notes.forEach((n) => { - nn.notes = [n]; // override notes array to only have one item to mimick individual_note - notes.push(nn); + notes.push({ + ...note, + notes: [n], // override notes array to only have one item to mimick individual_note + }); }); } else { const oldNote = utils.findNoteObjectById(state.notes, note.id); - nn.expanded = oldNote ? oldNote.expanded : note.expanded; - notes.push(nn); + notes.push({ + ...note, + expanded: (oldNote ? oldNote.expanded : note.expanded), + }); } }); @@ -197,4 +199,8 @@ export default { [types.REOPEN_ISSUE](state) { Object.assign(state.noteableData, { state: constants.REOPENED }); }, + + [types.TOGGLE_STATE_BUTTON_LOADING](state, value) { + Object.assign(state, { isToggleStateButtonLoading: value }); + }, }; diff --git a/app/assets/javascripts/notifications_dropdown.js b/app/assets/javascripts/notifications_dropdown.js index 479a512ed65..8ff8bb446ad 100644 --- a/app/assets/javascripts/notifications_dropdown.js +++ b/app/assets/javascripts/notifications_dropdown.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Flash from './flash'; export default function notificationsDropdown() { diff --git a/app/assets/javascripts/notifications_form.js b/app/assets/javascripts/notifications_form.js index 4e0afe13590..9e6cf67dff0 100644 --- a/app/assets/javascripts/notifications_form.js +++ b/app/assets/javascripts/notifications_form.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { __ } from './locale'; import axios from './lib/utils/axios_utils'; import flash from './flash'; diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js index 7e85bce0d73..86a43b66cc8 100644 --- a/app/assets/javascripts/pager.js +++ b/app/assets/javascripts/pager.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { getParameterByName } from '~/lib/utils/common_utils'; import axios from './lib/utils/axios_utils'; import { removeParams } from './lib/utils/url_utility'; diff --git a/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js b/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js index 66702ec4ca0..15e737fff05 100644 --- a/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js +++ b/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { truncate } from '../../../lib/utils/text_utility'; const MAX_MESSAGE_LENGTH = 500; diff --git a/app/assets/javascripts/pages/admin/admin.js b/app/assets/javascripts/pages/admin/admin.js index 45e05f111a7..91f154b7ecd 100644 --- a/app/assets/javascripts/pages/admin/admin.js +++ b/app/assets/javascripts/pages/admin/admin.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { refreshCurrentPage } from '../../lib/utils/url_utility'; function showBlacklistType() { diff --git a/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js b/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js index f92450cbaa7..e7ceccb6f47 100644 --- a/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js +++ b/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import axios from '~/lib/utils/axios_utils'; import flash from '~/flash'; diff --git a/app/assets/javascripts/pages/admin/projects/index/index.js b/app/assets/javascripts/pages/admin/projects/index/index.js index 3c597a1093e..ddbefec87b6 100644 --- a/app/assets/javascripts/pages/admin/projects/index/index.js +++ b/app/assets/javascripts/pages/admin/projects/index/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import Translate from '~/vue_shared/translate'; diff --git a/app/assets/javascripts/pages/admin/users/index.js b/app/assets/javascripts/pages/admin/users/index.js index 4f5d6b55031..06599c3fd5f 100644 --- a/app/assets/javascripts/pages/admin/users/index.js +++ b/app/assets/javascripts/pages/admin/users/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import Translate from '~/vue_shared/translate'; diff --git a/app/assets/javascripts/pages/dashboard/todos/index/todos.js b/app/assets/javascripts/pages/dashboard/todos/index/todos.js index 42f7460ad55..c334eaa90f8 100644 --- a/app/assets/javascripts/pages/dashboard/todos/index/todos.js +++ b/app/assets/javascripts/pages/dashboard/todos/index/todos.js @@ -1,4 +1,6 @@ /* eslint-disable class-methods-use-this, no-unneeded-ternary, quote-props */ + +import $ from 'jquery'; import { visitUrl } from '~/lib/utils/url_utility'; import UsersSelect from '~/users_select'; import { isMetaClick } from '~/lib/utils/common_utils'; diff --git a/app/assets/javascripts/pages/help/index/index.js b/app/assets/javascripts/pages/help/index/index.js index 05c81fc618b..1bafe564a37 100644 --- a/app/assets/javascripts/pages/help/index/index.js +++ b/app/assets/javascripts/pages/help/index/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import VersionCheckImage from '~/version_check_image'; import docs from '~/docs/docs_bundle'; diff --git a/app/assets/javascripts/pages/profiles/index.js b/app/assets/javascripts/pages/profiles/index.js index c52ad7bc335..04e50963699 100644 --- a/app/assets/javascripts/pages/profiles/index.js +++ b/app/assets/javascripts/pages/profiles/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import '~/profile/gl_crop'; import Profile from '~/profile/profile'; diff --git a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js index 5b2473e0989..fbdef329ab2 100644 --- a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js +++ b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import U2FRegister from '~/u2f/register'; document.addEventListener('DOMContentLoaded', () => { diff --git a/app/assets/javascripts/pages/projects/branches/new/index.js b/app/assets/javascripts/pages/projects/branches/new/index.js index d32d5c6cb29..a9658fd1eb4 100644 --- a/app/assets/javascripts/pages/projects/branches/new/index.js +++ b/app/assets/javascripts/pages/projects/branches/new/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import NewBranchForm from '~/new_branch_form'; document.addEventListener('DOMContentLoaded', () => ( diff --git a/app/assets/javascripts/pages/projects/commit/pipelines/index.js b/app/assets/javascripts/pages/projects/commit/pipelines/index.js index cd923f13ce8..8cc3cb0a57c 100644 --- a/app/assets/javascripts/pages/projects/commit/pipelines/index.js +++ b/app/assets/javascripts/pages/projects/commit/pipelines/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown'; import initPipelines from '~/commit/pipelines/pipelines_bundle'; diff --git a/app/assets/javascripts/pages/projects/commit/show/index.js b/app/assets/javascripts/pages/projects/commit/show/index.js index 1aeed197385..2e23cce11ce 100644 --- a/app/assets/javascripts/pages/projects/commit/show/index.js +++ b/app/assets/javascripts/pages/projects/commit/show/index.js @@ -1,4 +1,6 @@ /* eslint-disable no-new */ + +import $ from 'jquery'; import Diff from '~/diff'; import ZenMode from '~/zen_mode'; import ShortcutsNavigation from '~/shortcuts_navigation'; diff --git a/app/assets/javascripts/pages/projects/find_file/show/index.js b/app/assets/javascripts/pages/projects/find_file/show/index.js index 23d857d69ec..24630c2aa05 100644 --- a/app/assets/javascripts/pages/projects/find_file/show/index.js +++ b/app/assets/javascripts/pages/projects/find_file/show/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import ProjectFindFile from '~/project_find_file'; import ShortcutsFindFile from '~/shortcuts_find_file'; diff --git a/app/assets/javascripts/pages/projects/graphs/charts/index.js b/app/assets/javascripts/pages/projects/graphs/charts/index.js index 42df19c2968..80159a82bd4 100644 --- a/app/assets/javascripts/pages/projects/graphs/charts/index.js +++ b/app/assets/javascripts/pages/projects/graphs/charts/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Chart from 'chart.js'; import _ from 'underscore'; diff --git a/app/assets/javascripts/pages/projects/graphs/show/index.js b/app/assets/javascripts/pages/projects/graphs/show/index.js index f516ff20995..71f629fbc13 100644 --- a/app/assets/javascripts/pages/projects/graphs/show/index.js +++ b/app/assets/javascripts/pages/projects/graphs/show/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import flash from '~/flash'; import { __ } from '~/locale'; import axios from '~/lib/utils/axios_utils'; 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 9ac0b4c07e5..653e2502d01 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,5 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, 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, no-shadow */ +import $ from 'jquery'; import _ from 'underscore'; import { n__, s__, createDateTimeFormat, sprintf } from '~/locale'; import { ContributorsGraph, ContributorsAuthorGraph, ContributorsMasterGraph } from './stat_graph_contributors_graph'; 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 6ffaa277a0a..a99ce0f1c36 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,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, 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 */ + +import $ from 'jquery'; import _ from 'underscore'; import { extent, max } from 'd3-array'; import { select, event as d3Event } from 'd3-selection'; diff --git a/app/assets/javascripts/pages/projects/issues/form.js b/app/assets/javascripts/pages/projects/issues/form.js index 5c7daf84738..14fddbc9a05 100644 --- a/app/assets/javascripts/pages/projects/issues/form.js +++ b/app/assets/javascripts/pages/projects/issues/form.js @@ -1,4 +1,6 @@ /* eslint-disable no-new */ + +import $ from 'jquery'; import GLForm from '~/gl_form'; import IssuableForm from '~/issuable_form'; import LabelsSelect from '~/labels_select'; diff --git a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js index 8bfac606aab..406fc32f9a2 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js +++ b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js @@ -1,5 +1,6 @@ /* eslint-disable no-new */ +import $ from 'jquery'; import Diff from '~/diff'; import ShortcutsNavigation from '~/shortcuts_navigation'; import GLForm from '~/gl_form'; diff --git a/app/assets/javascripts/pages/projects/network/network.js b/app/assets/javascripts/pages/projects/network/network.js index 7354243e4c8..aa50dd4bb25 100644 --- a/app/assets/javascripts/pages/projects/network/network.js +++ b/app/assets/javascripts/pages/projects/network/network.js @@ -1,5 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, quote-props, prefer-template, comma-dangle, max-len */ +import $ from 'jquery'; import BranchGraph from '../../../network/branch_graph'; export default (function() { diff --git a/app/assets/javascripts/pages/projects/network/show/index.js b/app/assets/javascripts/pages/projects/network/show/index.js index e7dfd2d0128..a0b14fed10f 100644 --- a/app/assets/javascripts/pages/projects/network/show/index.js +++ b/app/assets/javascripts/pages/projects/network/show/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import ShortcutsNetwork from '../../../../shortcuts_network'; import Network from '../network'; diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/target_branch_dropdown.js b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/target_branch_dropdown.js index 0c3926d76b5..4ef0d11dd36 100644 --- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/target_branch_dropdown.js +++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/target_branch_dropdown.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default class TargetBranchDropdown { constructor() { this.$dropdown = $('.js-target-branch-dropdown'); diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown.js b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown.js index 95ed9c7dc21..95b57d5e048 100644 --- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown.js +++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown.js @@ -1,5 +1,7 @@ /* eslint-disable class-methods-use-this */ +import $ from 'jquery'; + const defaultTimezone = 'UTC'; export default class TimezoneDropdown { diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js index cfd30d6053f..c3ac54733a3 100644 --- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js +++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import Translate from '../../../../vue_shared/translate'; import GlFieldErrors from '../../../../gl_field_errors'; diff --git a/app/assets/javascripts/pages/projects/pipelines/charts/index.js b/app/assets/javascripts/pages/projects/pipelines/charts/index.js index bb92f4e1459..07b6992eba1 100644 --- a/app/assets/javascripts/pages/projects/pipelines/charts/index.js +++ b/app/assets/javascripts/pages/projects/pipelines/charts/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Chart from 'chart.js'; const options = { diff --git a/app/assets/javascripts/pages/projects/pipelines/new/index.js b/app/assets/javascripts/pages/projects/pipelines/new/index.js index da20bd995e9..9aa8945e268 100644 --- a/app/assets/javascripts/pages/projects/pipelines/new/index.js +++ b/app/assets/javascripts/pages/projects/pipelines/new/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import NewBranchForm from '~/new_branch_form'; document.addEventListener('DOMContentLoaded', () => { diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js index d23ad9a92f4..c1e3425ec75 100644 --- a/app/assets/javascripts/pages/projects/project.js +++ b/app/assets/javascripts/pages/projects/project.js @@ -1,5 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, consistent-return, no-new, prefer-arrow-callback, no-return-assign, one-var, one-var-declaration-per-line, object-shorthand, no-else-return, newline-per-chained-call, no-shadow, vars-on-top, prefer-template, max-len */ +import $ from 'jquery'; import Cookies from 'js-cookie'; import { __ } from '~/locale'; import { visitUrl } from '~/lib/utils/url_utility'; diff --git a/app/assets/javascripts/pages/projects/releases/edit/index.js b/app/assets/javascripts/pages/projects/releases/edit/index.js index 0bf53a8de09..c70271b09c4 100644 --- a/app/assets/javascripts/pages/projects/releases/edit/index.js +++ b/app/assets/javascripts/pages/projects/releases/edit/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import initForm from '~/pages/projects/init_form'; document.addEventListener('DOMContentLoaded', () => initForm($('.release-form'))); diff --git a/app/assets/javascripts/pages/projects/shared/project_avatar.js b/app/assets/javascripts/pages/projects/shared/project_avatar.js index 56627aa155c..447877752fe 100644 --- a/app/assets/javascripts/pages/projects/shared/project_avatar.js +++ b/app/assets/javascripts/pages/projects/shared/project_avatar.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default function projectAvatar() { $('.js-choose-project-avatar-button').bind('click', function onClickAvatar() { const form = $(this).closest('form'); diff --git a/app/assets/javascripts/pages/projects/shared/project_new.js b/app/assets/javascripts/pages/projects/shared/project_new.js index 86faba0b910..56d5574aa2f 100644 --- a/app/assets/javascripts/pages/projects/shared/project_new.js +++ b/app/assets/javascripts/pages/projects/shared/project_new.js @@ -1,5 +1,6 @@ /* eslint-disable func-names, no-var, no-underscore-dangle, prefer-template, prefer-arrow-callback*/ +import $ from 'jquery'; import VisibilitySelect from '../../../visibility_select'; function highlightChanges($elm) { diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js index 9b87f249f09..a6a172402d8 100644 --- a/app/assets/javascripts/pages/projects/show/index.js +++ b/app/assets/javascripts/pages/projects/show/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import ShortcutsNavigation from '~/shortcuts_navigation'; import NotificationsForm from '~/notifications_form'; import UserCallout from '~/user_callout'; diff --git a/app/assets/javascripts/pages/projects/snippets/edit/index.js b/app/assets/javascripts/pages/projects/snippets/edit/index.js index c15f798b630..53606acc508 100644 --- a/app/assets/javascripts/pages/projects/snippets/edit/index.js +++ b/app/assets/javascripts/pages/projects/snippets/edit/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import initSnippet from '~/snippet/snippet_bundle'; import initForm from '~/pages/projects/init_form'; diff --git a/app/assets/javascripts/pages/projects/snippets/new/index.js b/app/assets/javascripts/pages/projects/snippets/new/index.js index c15f798b630..53606acc508 100644 --- a/app/assets/javascripts/pages/projects/snippets/new/index.js +++ b/app/assets/javascripts/pages/projects/snippets/new/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import initSnippet from '~/snippet/snippet_bundle'; import initForm from '~/pages/projects/init_form'; diff --git a/app/assets/javascripts/pages/projects/tags/new/index.js b/app/assets/javascripts/pages/projects/tags/new/index.js index 191c98b36bb..8d0edf7e06c 100644 --- a/app/assets/javascripts/pages/projects/tags/new/index.js +++ b/app/assets/javascripts/pages/projects/tags/new/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import RefSelectDropdown from '../../../../ref_select_dropdown'; import ZenMode from '../../../../zen_mode'; import GLForm from '../../../../gl_form'; diff --git a/app/assets/javascripts/pages/projects/tree/show/index.js b/app/assets/javascripts/pages/projects/tree/show/index.js index ed7d3f1747c..7ad082a5e61 100644 --- a/app/assets/javascripts/pages/projects/tree/show/index.js +++ b/app/assets/javascripts/pages/projects/tree/show/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import initBlob from '~/blob_edit/blob_bundle'; import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue'; diff --git a/app/assets/javascripts/pages/projects/wikis/index.js b/app/assets/javascripts/pages/projects/wikis/index.js index b9f8707fd6e..ec01c66ffda 100644 --- a/app/assets/javascripts/pages/projects/wikis/index.js +++ b/app/assets/javascripts/pages/projects/wikis/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Wikis from './wikis'; import ShortcutsWiki from '../../../shortcuts_wiki'; import ZenMode from '../../../zen_mode'; diff --git a/app/assets/javascripts/pages/search/show/search.js b/app/assets/javascripts/pages/search/show/search.js index cf44e291199..2e1fe78b3fa 100644 --- a/app/assets/javascripts/pages/search/show/search.js +++ b/app/assets/javascripts/pages/search/show/search.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Flash from '~/flash'; import Api from '~/api'; diff --git a/app/assets/javascripts/pages/sessions/new/index.js b/app/assets/javascripts/pages/sessions/new/index.js index a0aa0499776..80a7114f94d 100644 --- a/app/assets/javascripts/pages/sessions/new/index.js +++ b/app/assets/javascripts/pages/sessions/new/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import UsernameValidator from './username_validator'; import SigninTabsMemoizer from './signin_tabs_memoizer'; import OAuthRememberMe from './oauth_remember_me'; diff --git a/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js b/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js index ffc2dd6bbca..53030045292 100644 --- a/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js +++ b/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + /** * OAuth-based login buttons have a separate "remember me" checkbox. * diff --git a/app/assets/javascripts/pages/sessions/new/username_validator.js b/app/assets/javascripts/pages/sessions/new/username_validator.js index 745543c22da..825de01b5a2 100644 --- a/app/assets/javascripts/pages/sessions/new/username_validator.js +++ b/app/assets/javascripts/pages/sessions/new/username_validator.js @@ -1,5 +1,6 @@ /* eslint-disable comma-dangle, consistent-return, class-methods-use-this, arrow-parens, no-param-reassign, max-len */ +import $ from 'jquery'; import _ from 'underscore'; import axios from '~/lib/utils/axios_utils'; import flash from '~/flash'; diff --git a/app/assets/javascripts/pages/snippets/form.js b/app/assets/javascripts/pages/snippets/form.js index f996d3cd74e..72d05da1069 100644 --- a/app/assets/javascripts/pages/snippets/form.js +++ b/app/assets/javascripts/pages/snippets/form.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import GLForm from '~/gl_form'; import ZenMode from '~/zen_mode'; diff --git a/app/assets/javascripts/pages/users/activity_calendar.js b/app/assets/javascripts/pages/users/activity_calendar.js index 57306322aa4..8ce938c958b 100644 --- a/app/assets/javascripts/pages/users/activity_calendar.js +++ b/app/assets/javascripts/pages/users/activity_calendar.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import { scaleLinear, scaleThreshold } from 'd3-scale'; import { select } from 'd3-selection'; diff --git a/app/assets/javascripts/pages/users/index.js b/app/assets/javascripts/pages/users/index.js index 899dcd42e37..6b1626b0161 100644 --- a/app/assets/javascripts/pages/users/index.js +++ b/app/assets/javascripts/pages/users/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import UserCallout from '~/user_callout'; import Cookies from 'js-cookie'; import UserTabs from './user_tabs'; diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js index c1217623467..124bc2ba710 100644 --- a/app/assets/javascripts/pages/users/user_tabs.js +++ b/app/assets/javascripts/pages/users/user_tabs.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import axios from '~/lib/utils/axios_utils'; import Activities from '~/activities'; import { localTimeAgo } from '~/lib/utils/datetime_utility'; diff --git a/app/assets/javascripts/performance_bar.js b/app/assets/javascripts/performance_bar.js index 0562a681c4b..c22598ee665 100644 --- a/app/assets/javascripts/performance_bar.js +++ b/app/assets/javascripts/performance_bar.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import 'vendor/peek'; import 'vendor/peek.performance_bar'; import { getParameterValues } from './lib/utils/url_utility'; @@ -13,8 +14,6 @@ export default class PerformanceBar { init(opts) { const $container = $(opts.container); - this.$sqlProfileLink = $container.find('.js-toggle-modal-peek-sql'); - this.$sqlProfileModal = $container.find('#modal-peek-pg-queries'); this.$lineProfileLink = $container.find('.js-toggle-modal-peek-line-profile'); this.$lineProfileModal = $('#modal-peek-line-profile'); this.initEventListeners(); @@ -22,7 +21,6 @@ export default class PerformanceBar { } initEventListeners() { - this.$sqlProfileLink.on('click', () => this.handleSQLProfileLink()); this.$lineProfileLink.on('click', e => this.handleLineProfileLink(e)); $(document).on('click', '.js-lineprof-file', PerformanceBar.toggleLineProfileFile); } @@ -35,10 +33,6 @@ export default class PerformanceBar { } } - handleSQLProfileLink() { - PerformanceBar.toggleModal(this.$sqlProfileModal); - } - handleLineProfileLink(e) { const lineProfilerParameter = getParameterValues('lineprofiler'); const lineProfilerParameterRegex = new RegExp(`lineprofiler=${lineProfilerParameter[0]}`); diff --git a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue index b86e95f0b4a..be213c2ee78 100644 --- a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue @@ -1,4 +1,5 @@ <script> + import $ from 'jquery'; import jobNameComponent from './job_name_component.vue'; import jobComponent from './job_component.vue'; import tooltip from '../../../vue_shared/directives/tooltip'; diff --git a/app/assets/javascripts/pipelines/components/stage.vue b/app/assets/javascripts/pipelines/components/stage.vue index ecf2b10486e..8bc7a1f20b2 100644 --- a/app/assets/javascripts/pipelines/components/stage.vue +++ b/app/assets/javascripts/pipelines/components/stage.vue @@ -1,4 +1,5 @@ <script> + import $ from 'jquery'; /** * Renders each stage of the pipeline mini graph. diff --git a/app/assets/javascripts/preview_markdown.js b/app/assets/javascripts/preview_markdown.js index 464bfb351e7..246a265ef2b 100644 --- a/app/assets/javascripts/preview_markdown.js +++ b/app/assets/javascripts/preview_markdown.js @@ -1,5 +1,10 @@ /* eslint-disable func-names, no-var, object-shorthand, comma-dangle, prefer-arrow-callback */ +import $ from 'jquery'; +import axios from '~/lib/utils/axios_utils'; +import flash from '~/flash'; +import { __ } from '~/locale'; + // MarkdownPreview // // Handles toggling the "Write" and "Preview" tab clicks, rendering the preview @@ -7,10 +12,6 @@ // more than `x` users are referenced. // -import axios from '~/lib/utils/axios_utils'; -import flash from '~/flash'; -import { __ } from '~/locale'; - var lastTextareaPreviewed; var lastTextareaHeight = null; var markdownPreview; diff --git a/app/assets/javascripts/profile/gl_crop.js b/app/assets/javascripts/profile/gl_crop.js index 4bdda611cfc..8f93156cdd1 100644 --- a/app/assets/javascripts/profile/gl_crop.js +++ b/app/assets/javascripts/profile/gl_crop.js @@ -1,5 +1,6 @@ /* eslint-disable no-useless-escape, max-len, quotes, no-var, no-underscore-dangle, func-names, space-before-function-paren, 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 */ +import $ from 'jquery'; import 'cropper'; import _ from 'underscore'; diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js index a811781853b..3c1bef23446 100644 --- a/app/assets/javascripts/profile/profile.js +++ b/app/assets/javascripts/profile/profile.js @@ -1,4 +1,6 @@ /* eslint-disable comma-dangle, no-unused-vars, class-methods-use-this, quotes, consistent-return, func-names, prefer-arrow-callback, space-before-function-paren, max-len */ + +import $ from 'jquery'; import Cookies from 'js-cookie'; import axios from '~/lib/utils/axios_utils'; import { __ } from '~/locale'; diff --git a/app/assets/javascripts/project_edit.js b/app/assets/javascripts/project_edit.js index 7572fec15e0..47bf2226781 100644 --- a/app/assets/javascripts/project_edit.js +++ b/app/assets/javascripts/project_edit.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default function setupProjectEdit() { const $transferForm = $('.js-project-transfer-form'); const $selectNamespace = $transferForm.find('select.select2'); diff --git a/app/assets/javascripts/project_find_file.js b/app/assets/javascripts/project_find_file.js index 4fd639cce8e..4c4acd487f8 100644 --- a/app/assets/javascripts/project_find_file.js +++ b/app/assets/javascripts/project_find_file.js @@ -1,5 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, consistent-return, one-var, one-var-declaration-per-line, no-cond-assign, max-len, object-shorthand, no-param-reassign, comma-dangle, prefer-template, no-unused-vars, no-return-assign */ +import $ from 'jquery'; import fuzzaldrinPlus from 'fuzzaldrin-plus'; import axios from '~/lib/utils/axios_utils'; import flash from '~/flash'; diff --git a/app/assets/javascripts/project_fork.js b/app/assets/javascripts/project_fork.js index 65d46fa9a73..6fedd94a6a9 100644 --- a/app/assets/javascripts/project_fork.js +++ b/app/assets/javascripts/project_fork.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default () => { $('.js-fork-thumbnail').on('click', function forkThumbnailClicked() { if ($(this).hasClass('disabled')) return false; diff --git a/app/assets/javascripts/project_label_subscription.js b/app/assets/javascripts/project_label_subscription.js index 64b7dd540f9..f31beb4dc78 100644 --- a/app/assets/javascripts/project_label_subscription.js +++ b/app/assets/javascripts/project_label_subscription.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { __ } from './locale'; import axios from './lib/utils/axios_utils'; import flash from './flash'; diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js index 412aca7bfed..cb2e6855d1d 100644 --- a/app/assets/javascripts/project_select.js +++ b/app/assets/javascripts/project_select.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-var, comma-dangle, object-shorthand, one-var, one-var-declaration-per-line, no-else-return, quotes, max-len */ + +import $ from 'jquery'; import Api from './api'; import ProjectSelectComboButton from './project_select_combo_button'; diff --git a/app/assets/javascripts/project_select_combo_button.js b/app/assets/javascripts/project_select_combo_button.js index 99cea683d9a..9b404896e86 100644 --- a/app/assets/javascripts/project_select_combo_button.js +++ b/app/assets/javascripts/project_select_combo_button.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import AccessorUtilities from './lib/utils/accessor'; export default class ProjectSelectComboButton { diff --git a/app/assets/javascripts/project_visibility.js b/app/assets/javascripts/project_visibility.js index c3f5e8cb907..7c95c71e239 100644 --- a/app/assets/javascripts/project_visibility.js +++ b/app/assets/javascripts/project_visibility.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + function setVisibilityOptions(namespaceSelector) { if (!namespaceSelector || !('selectedIndex' in namespaceSelector)) { return; diff --git a/app/assets/javascripts/projects/project_import_gitlab_project.js b/app/assets/javascripts/projects/project_import_gitlab_project.js index d2c7d77bb2d..4e20fce1460 100644 --- a/app/assets/javascripts/projects/project_import_gitlab_project.js +++ b/app/assets/javascripts/projects/project_import_gitlab_project.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { getParameterValues } from '../lib/utils/url_utility'; export default () => { diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js index 8da37d14f0b..93603dfc14d 100644 --- a/app/assets/javascripts/projects/project_new.js +++ b/app/assets/javascripts/projects/project_new.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { addSelectOnFocusBehaviour } from '../lib/utils/common_utils'; let hasUserDefinedProjectPath = false; diff --git a/app/assets/javascripts/projects_dropdown/index.js b/app/assets/javascripts/projects_dropdown/index.js index e78ebce2923..e1ca70c51a6 100644 --- a/app/assets/javascripts/projects_dropdown/index.js +++ b/app/assets/javascripts/projects_dropdown/index.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import Translate from '../vue_shared/translate'; diff --git a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js index 03bb281395a..0a60f4845b2 100644 --- a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js +++ b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import { s__, n__, sprintf } from '~/locale'; import axios from '../lib/utils/axios_utils'; diff --git a/app/assets/javascripts/protected_branches/protected_branch_create.js b/app/assets/javascripts/protected_branches/protected_branch_create.js index 8fc87633e18..7c61c070a35 100644 --- a/app/assets/javascripts/protected_branches/protected_branch_create.js +++ b/app/assets/javascripts/protected_branches/protected_branch_create.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import ProtectedBranchAccessDropdown from './protected_branch_access_dropdown'; import CreateItemDropdown from '../create_item_dropdown'; diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit_list.js b/app/assets/javascripts/protected_branches/protected_branch_edit_list.js index b40d3827c30..10253c0febc 100644 --- a/app/assets/javascripts/protected_branches/protected_branch_edit_list.js +++ b/app/assets/javascripts/protected_branches/protected_branch_edit_list.js @@ -1,5 +1,6 @@ /* eslint-disable no-new */ +import $ from 'jquery'; import ProtectedBranchEdit from './protected_branch_edit'; export default class ProtectedBranchEditList { diff --git a/app/assets/javascripts/protected_tags/protected_tag_create.js b/app/assets/javascripts/protected_tags/protected_tag_create.js index 2f94ffe2507..2f8116df0d2 100644 --- a/app/assets/javascripts/protected_tags/protected_tag_create.js +++ b/app/assets/javascripts/protected_tags/protected_tag_create.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import ProtectedTagAccessDropdown from './protected_tag_access_dropdown'; import CreateItemDropdown from '../create_item_dropdown'; diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit_list.js b/app/assets/javascripts/protected_tags/protected_tag_edit_list.js index bd9fc872266..b35bf4d4606 100644 --- a/app/assets/javascripts/protected_tags/protected_tag_edit_list.js +++ b/app/assets/javascripts/protected_tags/protected_tag_edit_list.js @@ -1,5 +1,6 @@ /* eslint-disable no-new */ +import $ from 'jquery'; import ProtectedTagEdit from './protected_tag_edit'; export default class ProtectedTagEditList { diff --git a/app/assets/javascripts/ref_select_dropdown.js b/app/assets/javascripts/ref_select_dropdown.js index 56c25a35e6d..95c5cf7b345 100644 --- a/app/assets/javascripts/ref_select_dropdown.js +++ b/app/assets/javascripts/ref_select_dropdown.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + class RefSelectDropdown { constructor($dropdownButton, availableRefs) { const availableRefsValue = availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML); diff --git a/app/assets/javascripts/render_gfm.js b/app/assets/javascripts/render_gfm.js index 05a623ca6d9..94fffcd2f61 100644 --- a/app/assets/javascripts/render_gfm.js +++ b/app/assets/javascripts/render_gfm.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import renderMath from './render_math'; import renderMermaid from './render_mermaid'; import syntaxHighlight from './syntax_highlight'; diff --git a/app/assets/javascripts/render_math.js b/app/assets/javascripts/render_math.js index eabdb01b2a9..8572bf64d46 100644 --- a/app/assets/javascripts/render_math.js +++ b/app/assets/javascripts/render_math.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import { __ } from './locale'; import flash from './flash'; diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js index 8d3cc849f81..2088a49590a 100644 --- a/app/assets/javascripts/right_sidebar.js +++ b/app/assets/javascripts/right_sidebar.js @@ -1,5 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-unused-vars, consistent-return, one-var, one-var-declaration-per-line, quotes, prefer-template, object-shorthand, comma-dangle, no-else-return, no-param-reassign, max-len */ +import $ from 'jquery'; import _ from 'underscore'; import Cookies from 'js-cookie'; import flash from './flash'; diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js index fdfa4f28aba..7dd3e9858c6 100644 --- a/app/assets/javascripts/search_autocomplete.js +++ b/app/assets/javascripts/search_autocomplete.js @@ -1,4 +1,6 @@ /* eslint-disable no-return-assign, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-unused-vars, no-cond-assign, consistent-return, object-shorthand, prefer-arrow-callback, func-names, space-before-function-paren, prefer-template, quotes, class-methods-use-this, no-sequences, wrap-iife, no-lonely-if, no-else-return, no-param-reassign, vars-on-top, max-len */ + +import $ from 'jquery'; import axios from './lib/utils/axios_utils'; import DropdownUtils from './filtered_search/dropdown_utils'; import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from './lib/utils/common_utils'; diff --git a/app/assets/javascripts/settings_panels.js b/app/assets/javascripts/settings_panels.js index d0e4f533d8a..eecde4550f9 100644 --- a/app/assets/javascripts/settings_panels.js +++ b/app/assets/javascripts/settings_panels.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + function expandSection($section) { $section.find('.js-settings-toggle').text('Collapse'); $section.find('.settings-content').off('scroll.expandSection').scrollTop(0); diff --git a/app/assets/javascripts/shared/milestones/form.js b/app/assets/javascripts/shared/milestones/form.js index db466f722c4..2f974d6ff9d 100644 --- a/app/assets/javascripts/shared/milestones/form.js +++ b/app/assets/javascripts/shared/milestones/form.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import ZenMode from '../../zen_mode'; import DueDateSelectors from '../../due_date_select'; import GLForm from '../../gl_form'; diff --git a/app/assets/javascripts/shared/sessions/u2f.js b/app/assets/javascripts/shared/sessions/u2f.js index 1d075f7e872..6ae9faf1dde 100644 --- a/app/assets/javascripts/shared/sessions/u2f.js +++ b/app/assets/javascripts/shared/sessions/u2f.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import U2FAuthenticate from '../../u2f/authenticate'; export default () => { diff --git a/app/assets/javascripts/shortcuts.js b/app/assets/javascripts/shortcuts.js index c5dddd001bb..e31e067033f 100644 --- a/app/assets/javascripts/shortcuts.js +++ b/app/assets/javascripts/shortcuts.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Cookies from 'js-cookie'; import Mousetrap from 'mousetrap'; import axios from './lib/utils/axios_utils'; diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/shortcuts_issuable.js index 14545824e74..3031230277d 100644 --- a/app/assets/javascripts/shortcuts_issuable.js +++ b/app/assets/javascripts/shortcuts_issuable.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Mousetrap from 'mousetrap'; import _ from 'underscore'; import Sidebar from './right_sidebar'; diff --git a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js index 782e4ba4fad..5626cccc022 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js +++ b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import '~/smart_interval'; diff --git a/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js b/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js index b10e2cc60ef..1eadebc7004 100644 --- a/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js +++ b/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + function isValidProjectId(id) { return id > 0; } diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js index ef748f18301..9f5d852260e 100644 --- a/app/assets/javascripts/sidebar/mount_sidebar.js +++ b/app/assets/javascripts/sidebar/mount_sidebar.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking'; import SidebarAssignees from './components/assignees/sidebar_assignees.vue'; diff --git a/app/assets/javascripts/single_file_diff.js b/app/assets/javascripts/single_file_diff.js index 6142ce6c6a3..1afff0dba38 100644 --- a/app/assets/javascripts/single_file_diff.js +++ b/app/assets/javascripts/single_file_diff.js @@ -1,5 +1,6 @@ /* eslint-disable func-names, prefer-arrow-callback, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, one-var-declaration-per-line, consistent-return, no-param-reassign, max-len */ +import $ from 'jquery'; import { __ } from './locale'; import axios from './lib/utils/axios_utils'; import createFlash from './flash'; diff --git a/app/assets/javascripts/smart_interval.js b/app/assets/javascripts/smart_interval.js index 8e931995fc6..77ab7c964e6 100644 --- a/app/assets/javascripts/smart_interval.js +++ b/app/assets/javascripts/smart_interval.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + /** * Instances of SmartInterval extend the functionality of `setInterval`, make it configurable * and controllable by a public API. diff --git a/app/assets/javascripts/snippet/snippet_bundle.js b/app/assets/javascripts/snippet/snippet_bundle.js index ce0fd3f6ff8..dcee17453b8 100644 --- a/app/assets/javascripts/snippet/snippet_bundle.js +++ b/app/assets/javascripts/snippet/snippet_bundle.js @@ -1,5 +1,7 @@ /* global ace */ +import $ from 'jquery'; + export default () => { const editor = ace.edit('editor'); diff --git a/app/assets/javascripts/star.js b/app/assets/javascripts/star.js index 3deb629d5f2..f5a7fdae5d7 100644 --- a/app/assets/javascripts/star.js +++ b/app/assets/javascripts/star.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Flash from './flash'; import { __, s__ } from './locale'; import { spriteIcon } from './lib/utils/common_utils'; diff --git a/app/assets/javascripts/subscription_select.js b/app/assets/javascripts/subscription_select.js index 3ed064f87a9..ebe1c6dd02d 100644 --- a/app/assets/javascripts/subscription_select.js +++ b/app/assets/javascripts/subscription_select.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default function subscriptionSelect() { $('.js-subscription-event').each((i, element) => { const fieldName = $(element).data('fieldName'); diff --git a/app/assets/javascripts/syntax_highlight.js b/app/assets/javascripts/syntax_highlight.js index 62bdef76c55..f52990ba232 100644 --- a/app/assets/javascripts/syntax_highlight.js +++ b/app/assets/javascripts/syntax_highlight.js @@ -1,5 +1,7 @@ /* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-else-return, prefer-arrow-callback, max-len */ +import $ from 'jquery'; + // Syntax Highlighter // // Applies a syntax highlighting color scheme CSS class to any element with the diff --git a/app/assets/javascripts/task_list.js b/app/assets/javascripts/task_list.js index 8fa78b636f8..48782e63b9b 100644 --- a/app/assets/javascripts/task_list.js +++ b/app/assets/javascripts/task_list.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import 'deckar01-task_list'; import axios from './lib/utils/axios_utils'; import Flash from './flash'; diff --git a/app/assets/javascripts/templates/issuable_template_selector.js b/app/assets/javascripts/templates/issuable_template_selector.js index b5b64f44a11..6fea03af46a 100644 --- a/app/assets/javascripts/templates/issuable_template_selector.js +++ b/app/assets/javascripts/templates/issuable_template_selector.js @@ -1,5 +1,6 @@ /* eslint-disable no-useless-return, max-len */ +import $ from 'jquery'; import Api from '../api'; import TemplateSelector from '../blob/template_selector'; diff --git a/app/assets/javascripts/templates/issuable_template_selectors.js b/app/assets/javascripts/templates/issuable_template_selectors.js index 66d868c5839..50e58ec5c46 100644 --- a/app/assets/javascripts/templates/issuable_template_selectors.js +++ b/app/assets/javascripts/templates/issuable_template_selectors.js @@ -1,4 +1,6 @@ /* eslint-disable no-new, class-methods-use-this */ + +import $ from 'jquery'; import IssuableTemplateSelector from './issuable_template_selector'; export default class IssuableTemplateSelectors { diff --git a/app/assets/javascripts/terminal/terminal.js b/app/assets/javascripts/terminal/terminal.js index 904b0093f7b..caffcddf3b0 100644 --- a/app/assets/javascripts/terminal/terminal.js +++ b/app/assets/javascripts/terminal/terminal.js @@ -1,5 +1,7 @@ /* global Terminal */ +import $ from 'jquery'; + (() => { class GLTerminal { diff --git a/app/assets/javascripts/tree.js b/app/assets/javascripts/tree.js index 1a0b2c0415b..afbb958d058 100644 --- a/app/assets/javascripts/tree.js +++ b/app/assets/javascripts/tree.js @@ -1,4 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, quotes, consistent-return, no-var, one-var, one-var-declaration-per-line, no-else-return, prefer-arrow-callback, class-methods-use-this */ + +import $ from 'jquery'; import { visitUrl } from './lib/utils/url_utility'; export default class TreeView { diff --git a/app/assets/javascripts/u2f/authenticate.js b/app/assets/javascripts/u2f/authenticate.js index fd42f9c3baa..96af6d2fcca 100644 --- a/app/assets/javascripts/u2f/authenticate.js +++ b/app/assets/javascripts/u2f/authenticate.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import importU2FLibrary from './util'; import U2FError from './error'; diff --git a/app/assets/javascripts/u2f/register.js b/app/assets/javascripts/u2f/register.js index 869fac658e8..01e259a741d 100644 --- a/app/assets/javascripts/u2f/register.js +++ b/app/assets/javascripts/u2f/register.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import importU2FLibrary from './util'; import U2FError from './error'; diff --git a/app/assets/javascripts/ui_development_kit.js b/app/assets/javascripts/ui_development_kit.js index 78dda172ee6..9b242ea779d 100644 --- a/app/assets/javascripts/ui_development_kit.js +++ b/app/assets/javascripts/ui_development_kit.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Api from './api'; export default () => { diff --git a/app/assets/javascripts/user_callout.js b/app/assets/javascripts/user_callout.js index a783122d500..97d5cf96bcb 100644 --- a/app/assets/javascripts/user_callout.js +++ b/app/assets/javascripts/user_callout.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Cookies from 'js-cookie'; export default class UserCallout { diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index 3385aba0279..f3b961eb109 100644 --- a/app/assets/javascripts/users_select.js +++ b/app/assets/javascripts/users_select.js @@ -1,6 +1,8 @@ /* eslint-disable func-names, space-before-function-paren, one-var, no-var, prefer-rest-params, wrap-iife, 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, no-lonely-if, yoda, prefer-spread, no-void, camelcase, no-param-reassign */ /* global Issuable */ /* global emitSidebarEvent */ + +import $ from 'jquery'; import _ from 'underscore'; import axios from './lib/utils/axios_utils'; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue index de98a77be6f..7ff7fc7988a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue @@ -63,7 +63,7 @@ }; this.isRemovingSourceBranch = true; - this.service.mergeResource.save(options) + this.service.merge(options) .then(res => res.data) .then((data) => { if (data.status === 'merge_when_pipeline_succeeds') { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge.js deleted file mode 100644 index ebfd6765934..00000000000 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge.js +++ /dev/null @@ -1,44 +0,0 @@ -import emptyStateSVG from 'icons/_mr_widget_empty_state.svg'; - -export default { - name: 'MRWidgetNothingToMerge', - props: { - mr: { - type: Object, - required: true, - }, - }, - data() { - return { emptyStateSVG }; - }, - template: ` - <div class="mr-widget-body mr-widget-empty-state"> - <div class="row"> - <div class="artwork col-sm-5 col-sm-push-7 col-xs-12 text-center"> - <span v-html="emptyStateSVG"></span> - </div> - <div class="text col-sm-7 col-sm-pull-5 col-xs-12"> - <span> - Merge requests are a place to propose changes you have made to a project - and discuss those changes with others. - </span> - <p> - Interested parties can even contribute by pushing commits if they want to. - </p> - <p> - Currently there are no changes in this merge request's source branch. - Please push new commits or use a different branch. - </p> - <div> - <a - v-if="mr.newBlobPath" - :href="mr.newBlobPath" - class="btn btn-inverted btn-save"> - Create file - </a> - </div> - </div> - </div> - </div> - `, -}; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js index bbca641f65e..44e1a616a19 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import statusIcon from '../mr_widget_status_icon.vue'; import tooltip from '../../../vue_shared/directives/tooltip'; import eventHub from '../../event_hub'; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue new file mode 100644 index 00000000000..3d9161f6926 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue @@ -0,0 +1,47 @@ +<script> +import emptyStateSVG from 'icons/_mr_widget_empty_state.svg'; + +export default { + name: 'MRWidgetNothingToMerge', + props: { + mr: { + type: Object, + required: true, + }, + }, + data() { + return { emptyStateSVG }; + }, +}; +</script> + +<template> + <div class="mr-widget-body mr-widget-empty-state"> + <div class="row"> + <div class="artwork col-sm-5 col-sm-push-7 col-xs-12 text-center"> + <span v-html="emptyStateSVG"></span> + </div> + <div class="text col-sm-7 col-sm-pull-5 col-xs-12"> + <span> + Merge requests are a place to propose changes you have made to a project + and discuss those changes with others. + </span> + <p> + Interested parties can even contribute by pushing commits if they want to. + </p> + <p> + Currently there are no changes in this merge request's source branch. + Please push new commits or use a different branch. + </p> + <div> + <a + v-if="mr.newBlobPath" + :href="mr.newBlobPath" + class="btn btn-inverted btn-save"> + Create file + </a> + </div> + </div> + </div> + </div> +</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js index b867dd90a41..20624aad0ad 100644 --- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js +++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js @@ -24,7 +24,7 @@ export { default as MergingState } from './components/states/mr_widget_merging.v export { default as WipState } from './components/states/mr_widget_wip'; export { default as ArchivedState } from './components/states/mr_widget_archived.vue'; export { default as ConflictsState } from './components/states/mr_widget_conflicts.vue'; -export { default as NothingToMergeState } from './components/states/mr_widget_nothing_to_merge'; +export { default as NothingToMergeState } from './components/states/nothing_to_merge.vue'; export { default as MissingBranchState } from './components/states/mr_widget_missing_branch.vue'; export { default as NotAllowedState } from './components/states/mr_widget_not_allowed.vue'; export { default as ReadyToMergeState } from './components/states/mr_widget_ready_to_merge'; diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js index 01365b70897..cc8bc6af1e1 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js @@ -71,7 +71,8 @@ export default { return this.mr.deployments.length; }, shouldRenderSourceBranchRemovalStatus() { - return !this.mr.canRemoveSourceBranch && this.mr.shouldRemoveSourceBranch; + return !this.mr.canRemoveSourceBranch && this.mr.shouldRemoveSourceBranch && + (!this.mr.isNothingToMergeState && !this.mr.isMergedState); }, }, methods: { diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index 5d07bcf1bb9..a47ca9fae86 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -125,6 +125,10 @@ export default class MergeRequestStore { return this.state === stateKey.nothingToMerge; } + get isMergedState() { + return this.state === stateKey.merged; + } + initRebase(data) { this.canPushToSourceBranch = data.can_push_to_source_branch; this.rebaseInProgress = data.rebase_in_progress; diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js b/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js index 29d5bd4a1da..483ad52b8cc 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js @@ -49,6 +49,7 @@ export const stateKey = { notAllowedToMerge: 'notAllowedToMerge', readyToMerge: 'readyToMerge', rebase: 'rebase', + merged: 'merged', }; export default { diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue index d2e968a8419..12c7d125062 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/field.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue @@ -1,4 +1,5 @@ <script> + import $ from 'jquery'; import Flash from '../../../flash'; import GLForm from '../../../gl_form'; import markdownHeader from './header.vue'; diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index 177d2cfc8da..d91fe3cf0c5 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -1,4 +1,5 @@ <script> + import $ from 'jquery'; import tooltip from '../../directives/tooltip'; import toolbarButton from './toolbar_button.vue'; import icon from '../icon.vue'; diff --git a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue index 63d8329e495..b33a0101dbf 100644 --- a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue +++ b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue @@ -1,4 +1,6 @@ <script> + import $ from 'jquery'; + /** * Given an array of tabs, renders non linked bootstrap tabs. * When a tab is clicked it will trigger an event and provide the clicked scope. diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue index c1dd4d42d9d..5ede53d8d01 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue @@ -1,4 +1,5 @@ <script> +import { __ } from '~/locale'; import LabelsSelect from '~/labels_select'; import LoadingIcon from '../../loading_icon.vue'; @@ -31,6 +32,11 @@ export default { required: false, default: false, }, + isProject: { + type: Boolean, + required: false, + default: false, + }, abilityName: { type: String, required: true, @@ -73,6 +79,20 @@ export default { hiddenInputName() { return this.showCreate ? `${this.abilityName}[label_names][]` : 'label_id[]'; }, + createLabelTitle() { + if (this.isProject) { + return __('Create project label'); + } + + return __('Create group label'); + }, + manageLabelsTitle() { + if (this.isProject) { + return __('Manage project labels'); + } + + return __('Manage group labels'); + }, }, mounted() { this.labelsDropdown = new LabelsSelect(this.$refs.dropdownButton, { @@ -137,10 +157,14 @@ dropdown-menu-labels dropdown-menu-selectable" <dropdown-footer v-if="showCreate" :labels-web-url="labelsWebUrl" + :create-label-title="createLabelTitle" + :manage-labels-title="manageLabelsTitle" /> </div> <dropdown-create-label v-if="showCreate" + :is-project="isProject" + :header-title="createLabelTitle" /> </div> </div> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue index 4200d1e8473..34a07f33a23 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue @@ -1,5 +1,14 @@ <script> +import { __ } from '~/locale'; + export default { + props: { + headerTitle: { + type: String, + required: false, + default: () => __('Create new label'), + }, + }, created() { this.suggestedColors = gon.suggested_label_colors; }, @@ -21,7 +30,7 @@ export default { > </i> </button> - {{ __('Create new label') }} + {{ headerTitle }} <button type="button" class="dropdown-title-button dropdown-menu-close" diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue index e951a863811..5f61e9fbe80 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue @@ -1,10 +1,22 @@ <script> +import { __ } from '~/locale'; + export default { props: { labelsWebUrl: { type: String, required: true, }, + createLabelTitle: { + type: String, + required: false, + default: () => __('Create new label'), + }, + manageLabelsTitle: { + type: String, + required: false, + default: () => __('Manage labels'), + }, }, }; </script> @@ -17,7 +29,7 @@ export default { href="#" class="dropdown-toggle-page" > - {{ __('Create new label') }} + {{ createLabelTitle }} </a> </li> <li> @@ -26,7 +38,7 @@ export default { class="dropdown-external-link" :href="labelsWebUrl" > - {{ __('Manage labels') }} + {{ manageLabelsTitle }} </a> </li> </ul> diff --git a/app/assets/javascripts/vue_shared/directives/popover.js b/app/assets/javascripts/vue_shared/directives/popover.js index 05fa563cbd0..eb35294906b 100644 --- a/app/assets/javascripts/vue_shared/directives/popover.js +++ b/app/assets/javascripts/vue_shared/directives/popover.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + /** * Helper to user bootstrap popover in vue.js. * Follow docs for html attributes: https://getbootstrap.com/docs/3.3/javascript/#static-popover diff --git a/app/assets/javascripts/vue_shared/directives/tooltip.js b/app/assets/javascripts/vue_shared/directives/tooltip.js index dc896cf5c7d..b7f7e9fec15 100644 --- a/app/assets/javascripts/vue_shared/directives/tooltip.js +++ b/app/assets/javascripts/vue_shared/directives/tooltip.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + export default { bind(el) { $(el).tooltip(); diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js index 4592003f57e..f68a4f28714 100644 --- a/app/assets/javascripts/zen_mode.js +++ b/app/assets/javascripts/zen_mode.js @@ -5,6 +5,7 @@ /*= provides zen_mode:enter */ /*= provides zen_mode:leave */ +import $ from 'jquery'; import 'vendor/jquery.scrollTo'; import Dropzone from 'dropzone'; import Mousetrap from 'mousetrap'; diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index ddd9dbb2be4..e12b5aab381 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -17,8 +17,6 @@ */ @mixin markdown-table { width: auto; - display: block; - overflow-x: auto; } /* diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 8b680c2dc52..b487f6278c2 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -194,8 +194,6 @@ .commit-actions { @media (min-width: $screen-sm-min) { - font-size: 0; - .fa-spinner { font-size: 12px; } @@ -204,7 +202,7 @@ .ci-status-link { display: inline-block; position: relative; - top: 1px; + top: 2px; } .btn-clipboard, @@ -226,7 +224,7 @@ .ci-status-icon { position: relative; - top: 1px; + top: 2px; } } diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 4c9732c26d9..e21a9f0afc9 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -137,12 +137,22 @@ z-index: 200; overflow: hidden; - a:not(.btn-retry), - .btn-link { + a:not(.btn) { color: inherit; + + &:hover { + color: $gl-link-hover-color; + + .avatar { + border-color: rgba($avatar-border, .2); + } + + } + } .btn-link { + color: inherit; outline: none; } @@ -214,7 +224,7 @@ &:hover { text-decoration: underline; - color: $md-link-color; + color: $gl-link-hover-color; } } } @@ -486,16 +496,6 @@ } } - a:not(.btn-retry) { - &:hover { - color: $md-link-color; - - .avatar { - border-color: rgba($avatar-border, .2); - } - } - } - .dropdown-menu-toggle { width: 100%; padding-top: 6px; @@ -503,6 +503,20 @@ .dropdown-menu { width: 100%; + + /* + * Overwrite hover style for dropdown items, so that they are not blue + * This should be removed during dev of https://gitlab.com/gitlab-org/gitlab-ce/issues/44040 + */ + li a { + &:hover, + &:active, + &:focus, + &.is-focused { + @include dropdown-item-hover; + } + } + } } diff --git a/app/assets/stylesheets/pages/wiki.scss b/app/assets/stylesheets/pages/wiki.scss index e70a57c2a67..9a0ec936979 100644 --- a/app/assets/stylesheets/pages/wiki.scss +++ b/app/assets/stylesheets/pages/wiki.scss @@ -180,6 +180,11 @@ ul.wiki-pages-list.content-list { } } +.wiki-holder { + overflow-x: auto; + overflow-y: hidden; +} + .wiki { table { @include markdown-table; diff --git a/app/controllers/projects/discussions_controller.rb b/app/controllers/projects/discussions_controller.rb index ee507009e50..cba9a53dc4b 100644 --- a/app/controllers/projects/discussions_controller.rb +++ b/app/controllers/projects/discussions_controller.rb @@ -19,6 +19,12 @@ class Projects::DiscussionsController < Projects::ApplicationController render_discussion end + def show + render json: { + discussion_html: view_to_html_string('discussions/_diff_with_notes', discussion: discussion, expanded: true) + } + end + private def render_discussion diff --git a/app/helpers/import_helper.rb b/app/helpers/import_helper.rb index 9149d79ecb8..4664b1728c4 100644 --- a/app/helpers/import_helper.rb +++ b/app/helpers/import_helper.rb @@ -1,4 +1,6 @@ module ImportHelper + include ::Gitlab::Utils::StrongMemoize + def has_ci_cd_only_params? false end @@ -75,17 +77,18 @@ module ImportHelper private def github_project_url(full_path) - "#{github_root_url}/#{full_path}" + URI.join(github_root_url, full_path).to_s end def github_root_url - return @github_url if defined?(@github_url) + strong_memoize(:github_url) do + provider = Gitlab::Auth::OAuth::Provider.config_for('github') - provider = Gitlab.config.omniauth.providers.find { |p| p.name == 'github' } - @github_url = provider.fetch('url', 'https://github.com') if provider + provider&.dig('url').presence || 'https://github.com' + end end def gitea_project_url(full_path) - "#{@gitea_host_url.sub(%r{/+\z}, '')}/#{full_path}" + URI.join(@gitea_host_url, full_path).to_s end end diff --git a/app/helpers/javascript_helper.rb b/app/helpers/javascript_helper.rb index d5e77c7e271..cd4075b340d 100644 --- a/app/helpers/javascript_helper.rb +++ b/app/helpers/javascript_helper.rb @@ -2,9 +2,4 @@ module JavascriptHelper def page_specific_javascript_tag(js) javascript_include_tag asset_path(js) end - - # deprecated; use webpack_bundle_tag directly instead - def page_specific_javascript_bundle_tag(bundle) - webpack_bundle_tag(bundle) - end end diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index b2c641a5dbd..87ff607dc3f 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -174,6 +174,39 @@ module LabelsHelper end end + def create_label_title(subject) + case subject + when Group + _('Create group label') + when Project + _('Create project label') + else + _('Create new label') + end + end + + def manage_labels_title(subject) + case subject + when Group + _('Manage group labels') + when Project + _('Manage project labels') + else + _('Manage labels') + end + end + + def view_labels_title(subject) + case subject + when Group + _('View group labels') + when Project + _('View project labels') + else + _('View labels') + end + end + # Required for Banzai::Filter::LabelReferenceFilter module_function :render_colored_label, :text_color_for_bg, :escape_once end diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index a70e73a6da9..20aed60cb7a 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -169,7 +169,7 @@ module NotesHelper reopenPath: reopen_issuable_path(issuable), notesPath: notes_url, totalNotes: issuable.discussions.length, - lastFetchedAt: Time.now + lastFetchedAt: Time.now.to_i }.to_json end diff --git a/app/models/compare.rb b/app/models/compare.rb index 3a8bbcb1acd..feb4b89c781 100644 --- a/app/models/compare.rb +++ b/app/models/compare.rb @@ -1,4 +1,6 @@ class Compare + include Gitlab::Utils::StrongMemoize + delegate :same, :head, :base, to: :@compare attr_reader :project @@ -11,9 +13,10 @@ class Compare end end - def initialize(compare, project, straight: false) + def initialize(compare, project, base_sha: nil, straight: false) @compare = compare @project = project + @base_sha = base_sha @straight = straight end @@ -22,40 +25,36 @@ class Compare end def start_commit - return @start_commit if defined?(@start_commit) + strong_memoize(:start_commit) do + commit = @compare.base - commit = @compare.base - @start_commit = commit ? ::Commit.new(commit, project) : nil + ::Commit.new(commit, project) if commit + end end def head_commit - return @head_commit if defined?(@head_commit) + strong_memoize(:head_commit) do + commit = @compare.head - commit = @compare.head - @head_commit = commit ? ::Commit.new(commit, project) : nil + ::Commit.new(commit, project) if commit + end end alias_method :commit, :head_commit - def base_commit - return @base_commit if defined?(@base_commit) - - @base_commit = if start_commit && head_commit - project.merge_base_commit(start_commit.id, head_commit.id) - else - nil - end - end - def start_commit_sha - start_commit.try(:sha) + start_commit&.sha end def base_commit_sha - base_commit.try(:sha) + strong_memoize(:base_commit) do + next unless start_commit && head_commit + + @base_sha || project.merge_base_commit(start_commit.id, head_commit.id)&.sha + end end def head_commit_sha - commit.try(:sha) + commit&.sha end def raw_diffs(*args) diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index 1db91c3c90c..2a69a205629 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -10,9 +10,14 @@ class CompareService @start_ref_name = new_start_ref_name end - def execute(target_project, target_ref, straight: false) + def execute(target_project, target_ref, base_sha: nil, straight: false) raw_compare = target_project.repository.compare_source_branch(target_ref, start_project.repository, start_ref_name, straight: straight) - Compare.new(raw_compare, target_project, straight: straight) if raw_compare + return unless raw_compare + + Compare.new(raw_compare, + target_project, + base_sha: base_sha, + straight: straight) end end diff --git a/app/views/discussions/_diff_with_notes.html.haml b/app/views/discussions/_diff_with_notes.html.haml index f9bfc01f213..8680ec2e298 100644 --- a/app/views/discussions/_diff_with_notes.html.haml +++ b/app/views/discussions/_diff_with_notes.html.haml @@ -2,8 +2,12 @@ - blob = discussion.blob - discussions = { discussion.original_line_code => [discussion] } - diff_file_class = diff_file.text? ? 'text-file' : 'js-image-file' +- diff_data = {} +- expanded = discussion.expanded? || local_assigns.fetch(:expanded, nil) +- unless expanded + - diff_data = { lines_path: project_merge_request_discussion_path(discussion.project, discussion.noteable, discussion) } -.diff-file.file-holder{ class: diff_file_class } +.diff-file.file-holder{ class: diff_file_class, data: diff_data } .js-file-title.file-title.file-title-flex-parent .file-header-content = render "projects/diffs/file_header", diff_file: diff_file, url: discussion_path(discussion), show_toggle: false @@ -11,17 +15,24 @@ - if diff_file.text? .diff-content.code.js-syntax-highlight %table - = render partial: "projects/diffs/line", - collection: discussion.truncated_diff_lines, - as: :line, - locals: { diff_file: diff_file, - discussions: discussions, - discussion_expanded: true, - plain: true } + - if expanded + - discussions = { discussion.original_line_code => [discussion] } + = render partial: "projects/diffs/line", + collection: discussion.truncated_diff_lines, + as: :line, + locals: { diff_file: diff_file, + discussions: discussions, + discussion_expanded: true, + plain: true } + - else + %tr.line_holder.line-holder-placeholder + %td.old_line.diff-line-num + %td.new_line.diff-line-num + %td.line_content + .js-code-placeholder + = render "discussions/diff_discussion", discussions: [discussion], expanded: true - else - partial = (diff_file.new_file? || diff_file.deleted_file?) ? 'single_image_diff' : 'replaced_image_diff' - = render partial: "projects/diffs/#{partial}", locals: { diff_file: diff_file, position: discussion.position.to_json, click_to_comment: false } - .note-container = render partial: "discussions/notes", locals: { discussion: discussion, show_toggle: false, show_image_comment_badge: true, disable_collapse_class: true } diff --git a/app/views/discussions/_discussion.html.haml b/app/views/discussions/_discussion.html.haml index 8b9fa3d6b05..e9589213f80 100644 --- a/app/views/discussions/_discussion.html.haml +++ b/app/views/discussions/_discussion.html.haml @@ -8,7 +8,7 @@ .discussion.js-toggle-container{ data: { discussion_id: discussion.id } } .discussion-header .discussion-actions - %button.note-action-button.discussion-toggle-button.js-toggle-button{ type: "button" } + %button.note-action-button.discussion-toggle-button.js-toggle-button{ type: "button", class: ("js-toggle-lazy-diff" unless expanded) } - if expanded = icon("chevron-up") - else diff --git a/app/views/peek/views/_gc.html.haml b/app/views/peek/views/_gc.html.haml new file mode 100644 index 00000000000..9fc83e56ee7 --- /dev/null +++ b/app/views/peek/views/_gc.html.haml @@ -0,0 +1,7 @@ +- local_assigns.fetch(:view) + +%span.bold + %span{ title: 'Invoke Time', data: { defer_to: "#{view.defer_key}-gc_time" } }... + \/ + %span{ title: 'Invoke Count', data: { defer_to: "#{view.defer_key}-invokes" } }... +gc diff --git a/app/views/peek/views/_gitaly.html.haml b/app/views/peek/views/_gitaly.html.haml index a7d040d6821..945bb287429 100644 --- a/app/views/peek/views/_gitaly.html.haml +++ b/app/views/peek/views/_gitaly.html.haml @@ -1,7 +1,17 @@ - local_assigns.fetch(:view) -%strong - %span{ data: { defer_to: "#{view.defer_key}-duration" } } ... +%button.btn-blank.btn-link.bold{ type: 'button', data: { toggle: 'modal', target: '#modal-peek-gitaly-details' } } + %span{ data: { defer_to: "#{view.defer_key}-duration" } }... \/ - %span{ data: { defer_to: "#{view.defer_key}-calls" } } ... - Gitaly + %span{ data: { defer_to: "#{view.defer_key}-calls" } }... +#modal-peek-gitaly-details.modal{ tabindex: -1, role: 'dialog' } + .modal-dialog.modal-full + .modal-content + .modal-header + %button.close{ type: 'button', data: { dismiss: 'modal' }, 'aria-label' => 'Close' } + %span{ 'aria-hidden' => 'true' } + × + %h4 + Gitaly requests + .modal-body{ data: { defer_to: "#{view.defer_key}-details" } }... +gitaly diff --git a/app/views/peek/views/_redis.html.haml b/app/views/peek/views/_redis.html.haml new file mode 100644 index 00000000000..f7fba6c95fc --- /dev/null +++ b/app/views/peek/views/_redis.html.haml @@ -0,0 +1,7 @@ +- local_assigns.fetch(:view) + +%span.bold + %span{ data: { defer_to: "#{view.defer_key}-duration" } }... + \/ + %span{ data: { defer_to: "#{view.defer_key}-calls" } }... +redis diff --git a/app/views/peek/views/_sidekiq.html.haml b/app/views/peek/views/_sidekiq.html.haml new file mode 100644 index 00000000000..7efbc05890d --- /dev/null +++ b/app/views/peek/views/_sidekiq.html.haml @@ -0,0 +1,7 @@ +- local_assigns.fetch(:view) + +%span.bold + %span{ data: { defer_to: "#{view.defer_key}-duration" } }... + \/ + %span{ data: { defer_to: "#{view.defer_key}-calls" } }... +sidekiq diff --git a/app/views/peek/views/_sql.html.haml b/app/views/peek/views/_sql.html.haml index dd8b524064f..36583df898a 100644 --- a/app/views/peek/views/_sql.html.haml +++ b/app/views/peek/views/_sql.html.haml @@ -1,13 +1,14 @@ -%strong - %a.js-toggle-modal-peek-sql - %span{ data: { defer_to: "#{view.defer_key}-duration" } }... - \/ - %span{ data: { defer_to: "#{view.defer_key}-calls" } }... +%button.btn-blank.btn-link.bold{ type: 'button', data: { toggle: 'modal', target: '#modal-peek-pg-queries' } } + %span{ data: { defer_to: "#{view.defer_key}-duration" } }... + \/ + %span{ data: { defer_to: "#{view.defer_key}-calls" } }... #modal-peek-pg-queries.modal{ tabindex: -1 } .modal-dialog.modal-full .modal-content .modal-header - %button.close.btn.btn-link.btn-sm{ type: 'button', data: { dismiss: 'modal' } } X + %button.close{ type: 'button', data: { dismiss: 'modal' }, 'aria-label' => 'Close' } + %span{ 'aria-hidden' => 'true' } + × %h4 SQL queries .modal-body{ data: { defer_to: "#{view.defer_key}-queries" } }... diff --git a/app/views/shared/boards/_show.html.haml b/app/views/shared/boards/_show.html.haml index 44b09545a61..dac60094686 100644 --- a/app/views/shared/boards/_show.html.haml +++ b/app/views/shared/boards/_show.html.haml @@ -27,7 +27,7 @@ ":issue-link-base" => "issueLinkBase", ":root-path" => "rootPath", ":board-id" => "boardId", - ":key" => "_uid" } + ":key" => "list.id" } = render "shared/boards/components/sidebar", group: group - if @project %board-add-issues-modal{ "new-issue-path" => new_project_issue_path(@project), diff --git a/app/views/shared/issuable/_label_page_create.html.haml b/app/views/shared/issuable/_label_page_create.html.haml index d5e7d3b87b7..91aa329eb93 100644 --- a/app/views/shared/issuable/_label_page_create.html.haml +++ b/app/views/shared/issuable/_label_page_create.html.haml @@ -1,5 +1,6 @@ +- subject = @project || @group .dropdown-page-two.dropdown-new-label - = dropdown_title("Create new label", options: { back: true }) + = dropdown_title(create_label_title(subject), options: { back: true }) = dropdown_content do .dropdown-labels-error.js-label-error %input#new_label_name.default-dropdown-input{ type: "text", placeholder: _('Name new label') } diff --git a/app/views/shared/issuable/_label_page_default.html.haml b/app/views/shared/issuable/_label_page_default.html.haml index 6a83321abcb..2bd922bca2b 100644 --- a/app/views/shared/issuable/_label_page_default.html.haml +++ b/app/views/shared/issuable/_label_page_default.html.haml @@ -3,6 +3,7 @@ - show_footer = local_assigns.fetch(:show_footer, true) - filter_placeholder = local_assigns.fetch(:filter_placeholder, 'Search') - show_boards_content = local_assigns.fetch(:show_boards_content, false) +- subject = @project || @group .dropdown-page-one = dropdown_title(title) - if show_boards_content @@ -17,11 +18,11 @@ - if can?(current_user, :admin_label, current_board_parent) %li %a.dropdown-toggle-page{ href: "#" } - = _('Create new label') + = create_label_title(subject) %li = link_to labels_path, :"data-is-link" => true do - if show_create && can?(current_user, :admin_label, current_board_parent) - = _('Manage labels') + = manage_labels_title(subject) - else - = _('View labels') + = view_labels_title(subject) = dropdown_loading diff --git a/app/views/shared/issuable/form/_contribution.html.haml b/app/views/shared/issuable/form/_contribution.html.haml index 0f2d313a5cc..de508278d7c 100644 --- a/app/views/shared/issuable/form/_contribution.html.haml +++ b/app/views/shared/issuable/form/_contribution.html.haml @@ -14,7 +14,7 @@ .checkbox = form.label :allow_maintainer_to_push do = form.check_box :allow_maintainer_to_push, disabled: !issuable.can_allow_maintainer_to_push?(current_user) - = _('Allow edits from maintainers') + = _('Allow edits from maintainers.') = link_to 'About this feature', help_page_path('user/project/merge_requests/maintainer_access') .help-block = allow_maintainer_push_unavailable_reason(issuable) diff --git a/changelogs/unreleased/34604-fix-generated-url-for-external-repository.yml b/changelogs/unreleased/34604-fix-generated-url-for-external-repository.yml new file mode 100644 index 00000000000..c4b5f59b724 --- /dev/null +++ b/changelogs/unreleased/34604-fix-generated-url-for-external-repository.yml @@ -0,0 +1,5 @@ +--- +title: Fix generated URL when listing repoitories for import +merge_request: 17692 +author: +type: fixed diff --git a/changelogs/unreleased/35475-lazy-diff.yml b/changelogs/unreleased/35475-lazy-diff.yml new file mode 100644 index 00000000000..bafa66ebe39 --- /dev/null +++ b/changelogs/unreleased/35475-lazy-diff.yml @@ -0,0 +1,5 @@ +--- +title: lazy load diffs on merge request discussions +merge_request: +author: +type: performance diff --git a/changelogs/unreleased/42579-fix-sidebar-dropdown-hover-style.yml b/changelogs/unreleased/42579-fix-sidebar-dropdown-hover-style.yml new file mode 100644 index 00000000000..c0a247dc895 --- /dev/null +++ b/changelogs/unreleased/42579-fix-sidebar-dropdown-hover-style.yml @@ -0,0 +1,5 @@ +--- +title: Fix hover style of dropdown items in the right sidebar +merge_request: 17519 +author: +type: fixed diff --git a/changelogs/unreleased/42814-fix-remove-source-branch-when-mwps.yml b/changelogs/unreleased/42814-fix-remove-source-branch-when-mwps.yml new file mode 100644 index 00000000000..08e77ee7c3b --- /dev/null +++ b/changelogs/unreleased/42814-fix-remove-source-branch-when-mwps.yml @@ -0,0 +1,6 @@ +--- +title: Fix "Remove source branch" button in Merge request widget during merge when pipeline + succeeds state +merge_request: 17192 +author: +type: fixed diff --git a/changelogs/unreleased/43702-update-label-dropdown-wording.yml b/changelogs/unreleased/43702-update-label-dropdown-wording.yml new file mode 100644 index 00000000000..97100ec89de --- /dev/null +++ b/changelogs/unreleased/43702-update-label-dropdown-wording.yml @@ -0,0 +1,5 @@ +--- +title: Update wording to specify create/manage project vs group labels in labels dropdown +merge_request: 17640 +author: +type: changed diff --git a/changelogs/unreleased/43720-update-fe-webpack-docs.yml b/changelogs/unreleased/43720-update-fe-webpack-docs.yml new file mode 100644 index 00000000000..9e461eaaec8 --- /dev/null +++ b/changelogs/unreleased/43720-update-fe-webpack-docs.yml @@ -0,0 +1,6 @@ +--- +title: Update documentation to reflect current minimum required versions of node and + yarn +merge_request: 17706 +author: +type: other diff --git a/changelogs/unreleased/43805-list-gitaly-calls-and-arguments-in-the-performance-bar.yml b/changelogs/unreleased/43805-list-gitaly-calls-and-arguments-in-the-performance-bar.yml new file mode 100644 index 00000000000..4c63e69f0bb --- /dev/null +++ b/changelogs/unreleased/43805-list-gitaly-calls-and-arguments-in-the-performance-bar.yml @@ -0,0 +1,5 @@ +--- +title: Add Gitaly call details to performance bar +merge_request: +author: +type: added diff --git a/changelogs/unreleased/44024-fix-table-extra-column.yml b/changelogs/unreleased/44024-fix-table-extra-column.yml new file mode 100644 index 00000000000..92c354a0844 --- /dev/null +++ b/changelogs/unreleased/44024-fix-table-extra-column.yml @@ -0,0 +1,5 @@ +--- +title: Fix markdown table showing extra column +merge_request: 17669 +author: +type: fixed diff --git a/changelogs/unreleased/44139-fix-issue-boards-dup-keys.yml b/changelogs/unreleased/44139-fix-issue-boards-dup-keys.yml new file mode 100644 index 00000000000..dd5f2f06d6c --- /dev/null +++ b/changelogs/unreleased/44139-fix-issue-boards-dup-keys.yml @@ -0,0 +1,6 @@ +--- +title: Use object ID to prevent duplicate keys Vue warning on Issue Boards page during + development +merge_request: 17682 +author: +type: other diff --git a/changelogs/unreleased/44149-issue-comment-buttons.yml b/changelogs/unreleased/44149-issue-comment-buttons.yml new file mode 100644 index 00000000000..c874c0d3d66 --- /dev/null +++ b/changelogs/unreleased/44149-issue-comment-buttons.yml @@ -0,0 +1,5 @@ +--- +title: Fix broken loading state for close issue button +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/add-indexes-to-todos-for-heavy-users-like-sean.yml b/changelogs/unreleased/add-indexes-to-todos-for-heavy-users-like-sean.yml new file mode 100644 index 00000000000..f0e5103a9d9 --- /dev/null +++ b/changelogs/unreleased/add-indexes-to-todos-for-heavy-users-like-sean.yml @@ -0,0 +1,5 @@ +--- +title: Add partial indexes on todos to handle users with many todos +merge_request: +author: +type: performance diff --git a/changelogs/unreleased/fix-code-search-500-with-non-ascii-filename.yml b/changelogs/unreleased/fix-code-search-500-with-non-ascii-filename.yml new file mode 100644 index 00000000000..29e3b7be985 --- /dev/null +++ b/changelogs/unreleased/fix-code-search-500-with-non-ascii-filename.yml @@ -0,0 +1,5 @@ +--- +title: Fix code and wiki search results when filename is non-ASCII +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/fix-emoji-popup.yml b/changelogs/unreleased/fix-emoji-popup.yml new file mode 100644 index 00000000000..c81d061a5d7 --- /dev/null +++ b/changelogs/unreleased/fix-emoji-popup.yml @@ -0,0 +1,5 @@ +--- +title: Hide emoji popup after multiple spaces +merge_request: +author: Jan Beckmann +type: fixed diff --git a/changelogs/unreleased/osw-stop-recalculating-merge-base-on-mr-loading.yml b/changelogs/unreleased/osw-stop-recalculating-merge-base-on-mr-loading.yml new file mode 100644 index 00000000000..1673e1d3658 --- /dev/null +++ b/changelogs/unreleased/osw-stop-recalculating-merge-base-on-mr-loading.yml @@ -0,0 +1,5 @@ +--- +title: Avoid re-fetching merge-base SHA from Gitaly unnecessarily +merge_request: +author: +type: performance diff --git a/changelogs/unreleased/refactor-move-mr-widget-nothing-to-merge-vue-component.yml b/changelogs/unreleased/refactor-move-mr-widget-nothing-to-merge-vue-component.yml new file mode 100644 index 00000000000..dc8ff95dc27 --- /dev/null +++ b/changelogs/unreleased/refactor-move-mr-widget-nothing-to-merge-vue-component.yml @@ -0,0 +1,5 @@ +--- +title: Move NothingToMerge vue component +merge_request: 17544 +author: George Tsiolis +type: performance diff --git a/changelogs/unreleased/tc-api-fix-expose_url.yml b/changelogs/unreleased/tc-api-fix-expose_url.yml new file mode 100644 index 00000000000..c701f64d6bf --- /dev/null +++ b/changelogs/unreleased/tc-api-fix-expose_url.yml @@ -0,0 +1,5 @@ +--- +title: Ensure the API returns https links when https is configured +merge_request: 17681 +author: +type: fixed diff --git a/config/application.rb b/config/application.rb index 422b16a7719..0ff95e33a9c 100644 --- a/config/application.rb +++ b/config/application.rb @@ -70,7 +70,6 @@ module Gitlab # - Webhook URLs (:hook) # - Sentry DSN (:sentry_dsn) # - Deploy keys (:key) - # - Secret variable values (:value) config.filter_parameters += [/token$/, /password/, /secret/] config.filter_parameters += %i( certificate @@ -82,7 +81,6 @@ module Gitlab sentry_dsn trace variables - value ) # Enable escaping HTML in JSON. diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb index 59385cdf379..58941aae1b0 100644 --- a/config/initializers/backtrace_silencers.rb +++ b/config/initializers/backtrace_silencers.rb @@ -1,7 +1,2 @@ -# Be sure to restart your server when you modify this file. - -# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. -# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } - -# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. -# Rails.backtrace_cleaner.remove_silencers! +Rails.backtrace_cleaner.remove_silencers! +Rails.backtrace_cleaner.add_silencer { |line| line !~ Gitlab::APP_DIRS_PATTERN } diff --git a/config/initializers/peek.rb b/config/initializers/peek.rb index 11759801112..ba04a2bf5fa 100644 --- a/config/initializers/peek.rb +++ b/config/initializers/peek.rb @@ -16,11 +16,11 @@ else end Peek.into PEEK_DB_VIEW +Peek.into Peek::Views::Gitaly +Peek.into Peek::Views::Rblineprof Peek.into Peek::Views::Redis Peek.into Peek::Views::Sidekiq -Peek.into Peek::Views::Rblineprof Peek.into Peek::Views::GC -Peek.into Peek::Views::Gitaly # rubocop:disable Naming/ClassAndModuleCamelCase class PEEK_DB_CLIENT diff --git a/config/routes/project.rb b/config/routes/project.rb index b82ed27664c..c803737d40b 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -130,7 +130,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do post :bulk_update end - resources :discussions, only: [], constraints: { id: /\h{40}/ } do + resources :discussions, only: [:show], constraints: { id: /\h{40}/ } do member do post :resolve delete :resolve, action: :unresolve diff --git a/db/migrate/20180309160427_add_partial_indexes_on_todos.rb b/db/migrate/20180309160427_add_partial_indexes_on_todos.rb new file mode 100644 index 00000000000..18a5c69df1b --- /dev/null +++ b/db/migrate/20180309160427_add_partial_indexes_on_todos.rb @@ -0,0 +1,28 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddPartialIndexesOnTodos < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + disable_ddl_transaction! + + INDEX_NAME_PENDING="index_todos_on_user_id_and_id_pending" + INDEX_NAME_DONE="index_todos_on_user_id_and_id_done" + + def up + unless index_exists?(:todos, [:user_id, :id], name: INDEX_NAME_PENDING) + add_concurrent_index(:todos, [:user_id, :id], where: "state='pending'", name: INDEX_NAME_PENDING) + end + unless index_exists?(:todos, [:user_id, :id], name: INDEX_NAME_DONE) + add_concurrent_index(:todos, [:user_id, :id], where: "state='done'", name: INDEX_NAME_DONE) + end + end + + def down + remove_concurrent_index(:todos, [:user_id, :id], where: "state='pending'", name: INDEX_NAME_PENDING) + remove_concurrent_index(:todos, [:user_id, :id], where: "state='done'", name: INDEX_NAME_DONE) + end +end diff --git a/db/schema.rb b/db/schema.rb index 970b1ad9948..ab4370e2754 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180309121820) do +ActiveRecord::Schema.define(version: 20180309160427) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -1778,6 +1778,8 @@ ActiveRecord::Schema.define(version: 20180309121820) do add_index "todos", ["note_id"], name: "index_todos_on_note_id", using: :btree add_index "todos", ["project_id"], name: "index_todos_on_project_id", using: :btree add_index "todos", ["target_type", "target_id"], name: "index_todos_on_target_type_and_target_id", using: :btree + add_index "todos", ["user_id", "id"], name: "index_todos_on_user_id_and_id_done", where: "((state)::text = 'done'::text)", using: :btree + add_index "todos", ["user_id", "id"], name: "index_todos_on_user_id_and_id_pending", where: "((state)::text = 'pending'::text)", using: :btree add_index "todos", ["user_id"], name: "index_todos_on_user_id", using: :btree create_table "trending_projects", force: :cascade do |t| diff --git a/doc/administration/monitoring/performance/img/performance_bar.png b/doc/administration/monitoring/performance/img/performance_bar.png Binary files differindex b3c6bc474e3..48212f6276a 100644 --- a/doc/administration/monitoring/performance/img/performance_bar.png +++ b/doc/administration/monitoring/performance/img/performance_bar.png diff --git a/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png b/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png Binary files differnew file mode 100644 index 00000000000..52176df9ecd --- /dev/null +++ b/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md index b9464945cea..ec1cbce1bad 100644 --- a/doc/administration/monitoring/performance/performance_bar.md +++ b/doc/administration/monitoring/performance/performance_bar.md @@ -11,10 +11,12 @@ It allows you to see (from left to right): - the timing of the page (backend, frontend) - time taken and number of DB queries, click through for details of these queries ![SQL profiling using the Performance Bar](img/performance_bar_sql_queries.png) -- time taken and number of calls to Redis -- time taken and number of background jobs created by Sidekiq +- time taken and number of [Gitaly] calls, click through for details of these calls +![Gitaly profiling using the Performance Bar](img/performance_bar_gitaly_calls.png) - profile of the code used to generate the page, line by line for either _all_, _app & lib_ , or _views_. In the profile view, the numbers in the left panel represent wall time, cpu time, and number of calls (based on [rblineprof](https://github.com/tmm1/rblineprof)). ![Line profiling using the Performance Bar](img/performance_bar_line_profiling.png) +- time taken and number of calls to Redis +- time taken and number of background jobs created by Sidekiq - time taken and number of Ruby GC calls ## Enable the Performance Bar via the Admin panel @@ -39,3 +41,5 @@ You can toggle the Bar using the same shortcut. ![GitLab Performance Bar Admin Settings](img/performance_bar_configuration_settings.png) --- + +[Gitaly]: ../../gitaly/index.md diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md index 1eb90c30ebd..fea92e740cb 100644 --- a/doc/development/ee_features.md +++ b/doc/development/ee_features.md @@ -360,27 +360,15 @@ Instead place EE specs in the `ee/spec` folder. ## JavaScript code in `assets/javascripts/` -To separate EE-specific JS-files we can also move the files into an `ee` folder. +To separate EE-specific JS-files we should also move the files into an `ee` folder. For example there can be an `app/assets/javascripts/protected_branches/protected_branches_bundle.js` and an EE counterpart `ee/app/assets/javascripts/protected_branches/protected_branches_bundle.js`. -That way we can create a separate webpack bundle in `webpack.config.js`: - -```javascript - protected_branches: '~/protected_branches', - ee_protected_branches: 'ee/protected_branches/protected_branches_bundle.js', -``` - -With the separate bundle in place, we can decide which bundle to load inside the -view, using the `page_specific_javascript_bundle_tag` helper. - -```haml -- content_for :page_specific_javascripts do - = page_specific_javascript_bundle_tag('protected_branches') -``` +See the frontend guide [performance section](./fe_guide/performance.md) for +information on managing page-specific javascript within EE. ## SCSS code in `assets/stylesheets` diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md index 12dfc10812b..2280cf79f86 100644 --- a/doc/development/fe_guide/index.md +++ b/doc/development/fe_guide/index.md @@ -14,8 +14,8 @@ support through [webpack][webpack]. We also utilize [webpack][webpack] to handle the bundling, minification, and compression of our assets. -Working with our frontend assets requires Node (v4.3 or greater) and Yarn -(v0.17 or greater). You can find information on how to install these on our +Working with our frontend assets requires Node (v6.0 or greater) and Yarn +(v1.2 or greater). You can find information on how to install these on our [installation guide][install]. [jQuery][jquery] is used throughout the application's JavaScript, with diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md index 98e43931a02..1320efaf767 100644 --- a/doc/development/fe_guide/performance.md +++ b/doc/development/fe_guide/performance.md @@ -23,7 +23,7 @@ controlled by the server. 1. The backend code will most likely be using etags. You do not and should not check for status `304 Not Modified`. The browser will transform it for you. -### Lazy Loading +### Lazy Loading Images To improve the time to first render we are using lazy loading for images. This works by setting the actual image source on the `data-src` attribute. After the HTML is rendered and JavaScript is loaded, @@ -47,41 +47,103 @@ properties once, and handle the actual animation with transforms. ## Reducing Asset Footprint -### Page-specific JavaScript +### Universal code -Certain pages may require the use of a third party library, such as [d3][d3] for -the User Activity Calendar and [Chart.js][chartjs] for the Graphs pages. These -libraries increase the page size significantly, and impact load times due to -bandwidth bottlenecks and the browser needing to parse more JavaScript. - -In cases where libraries are only used on a few specific pages, we use -"page-specific JavaScript" to prevent the main `main.js` file from -becoming unnecessarily large. - -Steps to split page-specific JavaScript from the main `main.js`: - -1. Create a directory for the specific page(s), e.g. `graphs/`. -1. In that directory, create a `namespace_bundle.js` file, e.g. `graphs_bundle.js`. -1. Add the new "bundle" file to the list of entry files in `config/webpack.config.js`. - - For example: `graphs: './graphs/graphs_bundle.js',`. -1. Move code reliant on these libraries into the `graphs` directory. -1. In `graphs_bundle.js` add CommonJS `require('./path_to_some_component.js');` statements to load any other files in this directory. Make sure to use relative urls. -1. In the relevant views, add the scripts to the page with the following: - -```haml -- content_for :page_specific_javascripts do - = webpack_bundle_tag 'lib_chart' - = webpack_bundle_tag 'graphs' -``` +Code that is contained within `main.js` and `commons/index.js` are loaded and +run on _all_ pages. **DO NOT ADD** anything to these files unless it is truly +needed _everywhere_. These bundles include ubiquitous libraries like `vue`, +`axios`, and `jQuery`, as well as code for the main navigation and sidebar. +Where possible we should aim to remove modules from these bundles to reduce our +code footprint. + +### Page-specific JavaScript -The above loads `chart.js` and `graphs_bundle.js` for this page only. `chart.js` -is separated from the bundle file so it can be cached separately from the bundle -and reused for other pages that also rely on the library. For an example, see -[this Haml file][page-specific-js-example]. +Webpack has been configured to automatically generate entry point bundles based +on the file structure within `app/assets/javascripts/pages/*`. The directories +within the `pages` directory correspond to Rails controllers and actions. These +auto-generated bundles will be automatically included on the corresponding +pages. + +For example, if you were to visit [gitlab.com/gitlab-org/gitlab-ce/issues](https://gitlab.com/gitlab-org/gitlab-ce/issues), +you would be accessing the `app/controllers/projects/issues_controller.rb` +controller with the `index` action. If a corresponding file exists at +`pages/projects/issues/index/index.js`, it will be compiled into a webpack +bundle and included on the page. + +> **Note:** Previously we had encouraged the use of +> `content_for :page_specific_javascripts` within haml files, along with +> manually generated webpack bundles. However under this new system you should +> not ever need to manually add an entry point to the `webpack.config.js` file. + +> **Tip:** +> If you are unsure what controller and action corresponds to a given page, you +> can find this out by inspecting `document.body.dataset.page` within your +> browser's developer console while on any page within gitlab. + +#### Important Considerations: + +- **Keep Entry Points Lite:** + Page-specific javascript entry points should be as lite as possible. These + files are exempt from unit tests, and should be used primarily for + instantiation and dependency injection of classes and methods that live in + modules outside of the entry point script. Just import, read the DOM, + instantiate, and nothing else. + +- **Entry Points May Be Asynchronous:** + _DO NOT ASSUME_ that the DOM has been fully loaded and available when an + entry point script is run. If you require that some code be run after the + DOM has loaded, you should attach an event handler to the `DOMContentLoaded` + event with: + + ```javascript + import initMyWidget from './my_widget'; + + document.addEventListener('DOMContentLoaded', () => { + initMyWidget(); + }); + ``` + +- **Supporting Module Placement:** + - If a class or a module is _specific to a particular route_, try to locate + it close to the entry point it will be used. For instance, if + `my_widget.js` is only imported within `pages/widget/show/index.js`, you + should place the module at `pages/widget/show/my_widget.js` and import it + with a relative path (e.g. `import initMyWidget from './my_widget';`). + + - If a class or module is _used by multiple routes_, place it within a + shared directory at the closest common parent directory for the entry + points that import it. For example, if `my_widget.js` is imported within + both `pages/widget/show/index.js` and `pages/widget/run/index.js`, then + place the module at `pages/widget/shared/my_widget.js` and import it with + a relative path if possible (e.g. `../shared/my_widget`). + +- **Enterprise Edition Caveats:** + For GitLab Enterprise Edition, page-specific entry points will override their + Community Edition counterparts with the same name, so if + `ee/app/assets/javascripts/pages/foo/bar/index.js` exists, it will take + precedence over `app/assets/javascripts/pages/foo/bar/index.js`. If you want + to minimize duplicate code, you can import one entry point from the other. + This is not done automatically to allow for flexibility in overriding + functionality. ### Code Splitting -> *TODO* flesh out this section once webpack is ready for code-splitting +For any code that does not need to be run immediately upon page load, (e.g. +modals, dropdowns, and other behaviors that can be lazy-loaded), you can split +your module into asynchronous chunks with dynamic import statements. These +imports return a Promise which will be resolved once the script has loaded: + +```javascript +import(/* webpackChunkName: 'emoji' */ '~/emoji') + .then(/* do something */) + .catch(/* report error */) +``` + +Please try to use `webpackChunkName` when generating these dynamic imports as +it will provide a deterministic filename for the chunk which can then be cached +the browser across GitLab versions. + +More information is available in [webpack's code splitting documentation](https://webpack.js.org/guides/code-splitting/#dynamic-imports). ### Minimizing page size @@ -95,7 +157,8 @@ General tips: - Prefer font formats with better compression, e.g. WOFF2 is better than WOFF, which is better than TTF. - Compress and minify assets wherever possible (For CSS/JS, Sprockets and webpack do this for us). - If some functionality can reasonably be achieved without adding extra libraries, avoid them. -- Use page-specific JavaScript as described above to dynamically load libraries that are only needed on certain pages. +- Use page-specific JavaScript as described above to load libraries that are only needed on certain pages. +- Use code-splitting dynamic imports wherever possible to lazy-load code that is not needed initially. - [High Performance Animations][high-perf-animations] ------- @@ -112,8 +175,5 @@ General tips: [pagespeed-insights]: https://developers.google.com/speed/pagespeed/insights/ [google-devtools-profiling]: https://developers.google.com/web/tools/chrome-devtools/profile/?hl=en [browser-diet]: https://browserdiet.com/ -[d3]: https://d3js.org/ -[chartjs]: http://www.chartjs.org/ -[page-specific-js-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/13bb9ed77f405c5f6ee4fdbc964ecf635c9a223f/app/views/projects/graphs/_head.html.haml#L6-8 [high-perf-animations]: https://www.html5rocks.com/en/tutorials/speed/high-performance-animations/ [flip]: https://aerotwist.com/blog/flip-your-animations/ diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md index 917d28b48ee..7b5fa6ca42f 100644 --- a/doc/development/fe_guide/style_guide_js.md +++ b/doc/development/fe_guide/style_guide_js.md @@ -548,6 +548,57 @@ On those a default key should not be provided. 1. Properties in a Vue Component: Check [order of properties in components rule][vue-order]. +#### `:key` +When using `v-for` you need to provide a *unique* `:key` attribute for each item. + +1. If the elements of the array being iterated have an unique `id` it is advised to use it: + ```html + <div + v-for="item in items" + :key="item.id" + > + <!-- content --> + </div> + ``` + +1. When the elements being iterated don't have a unique id, you can use the array index as the `:key` attribute + ```html + <div + v-for="(item, index) in items" + :key="index" + > + <!-- content --> + </div> + ``` + + +1. When using `v-for` with `template` and there is more than one child element, the `:key` values must be unique. It's advised to use `kebab-case` namespaces. + ```html + <template v-for="(item, index) in items"> + <span :key="`span-${index}`"></span> + <button :key="`button-${index}`"></button> + </template> + ``` + +1. When dealing with nested `v-for` use the same guidelines as above. + ```html + <div + v-for="item in items" + :key="item.id" + > + <span + v-for="element in array" + :key="element.id" + > + <!-- content --> + </span> + </div> + ``` + + +Useful links: +1. [`key`](https://vuejs.org/v2/guide/list.html#key) +1. [Vue Style Guide: Keyed v-for](https://vuejs.org/v2/style-guide/#Keyed-v-for-essential ) #### Vue and Bootstrap 1. Tooltips: Do not rely on `has-tooltip` class name for Vue components diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md index 093a3ca4407..c1170fa3b13 100644 --- a/doc/development/fe_guide/vue.md +++ b/doc/development/fe_guide/vue.md @@ -53,13 +53,13 @@ you can find a clear separation of concerns: ``` new_feature ├── components -│ └── component.js.es6 +│ └── component.vue │ └── ... -├── store -│ └── new_feature_store.js.es6 -├── service -│ └── new_feature_service.js.es6 -├── new_feature_bundle.js.es6 +├── stores +│ └── new_feature_store.js +├── services +│ └── new_feature_service.js +├── new_feature_bundle.js ``` _For consistency purposes, we recommend you to follow the same structure._ diff --git a/doc/development/new_fe_guide/development/security.md b/doc/development/new_fe_guide/development/security.md index debda7de0c6..5bb38f17988 100644 --- a/doc/development/new_fe_guide/development/security.md +++ b/doc/development/new_fe_guide/development/security.md @@ -1,3 +1,14 @@ # Security -> TODO: Add content +## Avoid inline scripts and styles + +Inline scripts and styles should be avoided in almost all cases. In an effort to protect users from [XSS vulnerabilities](https://en.wikipedia.org/wiki/Cross-site_scripting), we will be disabling inline scripts using Content Security Policy. + +## Including external resources + +External fonts, CSS, and JavaScript should never be used with the exception of Google Analytics and Piwik - and only when the instance has enabled it. Assets should always be hosted and served locally from the GitLab instance. Embedded resources via `iframes` should never be used except in certain circumstances such as with ReCaptcha, which cannot be used without an `iframe`. + +## Resources for security testing + +- [Mozilla's HTTP Observatory CLI](https://github.com/mozilla/http-observatory-cli) +- [Qualys SSL Labs Server Test](https://www.ssllabs.com/ssltest/analyze.html) diff --git a/doc/downgrade_ee_to_ce/README.md b/doc/downgrade_ee_to_ce/README.md index 75bae324585..ff1ac94ac58 100644 --- a/doc/downgrade_ee_to_ce/README.md +++ b/doc/downgrade_ee_to_ce/README.md @@ -70,7 +70,7 @@ To downgrade an Omnibus installation, it is sufficient to install the Community Edition package on top of the currently installed one. You can do this manually, by directly [downloading the package](https://packages.gitlab.com/gitlab/gitlab-ce) you need, or by adding our CE package repository and following the -[CE installation instructions](https://about.gitlab.com/downloads/). +[CE installation instructions](https://about.gitlab.com/downloads/?version=ce). **Source Installation** diff --git a/doc/install/installation.md b/doc/install/installation.md index 6eb767b00b3..1abbfd78738 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -162,13 +162,14 @@ page](https://golang.org/dl). ## 4. Node -Since GitLab 8.17, GitLab requires the use of node >= v4.3.0 to compile -javascript assets, and yarn >= v0.17.0 to manage javascript dependencies. -In many distros the versions provided by the official package repositories -are out of date, so we'll need to install through the following commands: - - # install node v7.x - curl --location https://deb.nodesource.com/setup_7.x | sudo bash - +Since GitLab 8.17, GitLab requires the use of Node to compile javascript +assets, and Yarn to manage javascript dependencies. The current minimum +requirements for these are node >= v6.0.0 and yarn >= v1.2.0. In many distros +the versions provided by the official package repositories are out of date, so +we'll need to install through the following commands: + + # install node v8.x + curl --location https://deb.nodesource.com/setup_8.x | sudo bash - sudo apt-get install -y nodejs curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - diff --git a/doc/update/10.5-to-10.6.md b/doc/update/10.5-to-10.6.md index af8343b5958..f5c5c305726 100644 --- a/doc/update/10.5-to-10.6.md +++ b/doc/update/10.5-to-10.6.md @@ -56,8 +56,8 @@ sudo gem install bundler --no-ri --no-rdoc ### 4. Update Node -GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets. -We require a minimum version of node v6.0.0. +GitLab utilizes [webpack](http://webpack.js.org) to compile frontend assets. +This requires a minimum version of node v6.0.0. You can check which version you are running with `node -v`. If you are running a version older than `v6.0.0` you will need to update to a newer version. You @@ -66,8 +66,8 @@ from source at the nodejs.org website. <https://nodejs.org/en/download/> -Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage -JavaScript dependencies. +GitLab also requires the use of yarn `>= v1.2.0` to manage JavaScript +dependencies. ```bash curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - diff --git a/doc/user/project/merge_requests/img/allow_maintainer_push.png b/doc/user/project/merge_requests/img/allow_maintainer_push.png Binary files differindex 1631527071b..91cc399f4ff 100644 --- a/doc/user/project/merge_requests/img/allow_maintainer_push.png +++ b/doc/user/project/merge_requests/img/allow_maintainer_push.png diff --git a/lib/api/helpers/related_resources_helpers.rb b/lib/api/helpers/related_resources_helpers.rb index 1f677529b07..7f4d6e58b34 100644 --- a/lib/api/helpers/related_resources_helpers.rb +++ b/lib/api/helpers/related_resources_helpers.rb @@ -15,7 +15,7 @@ module API url_options = Gitlab::Application.routes.default_url_options protocol, host, port = url_options.slice(:protocol, :host, :port).values - URI::HTTP.build(scheme: protocol, host: host, port: port, path: path).to_s + URI::Generic.build(scheme: protocol, host: host, port: port, path: path).to_s end private diff --git a/lib/generators/rails/post_deployment_migration/post_deployment_migration_generator.rb b/lib/generators/rails/post_deployment_migration/post_deployment_migration_generator.rb index 7cb4bccb23c..91175b49c79 100644 --- a/lib/generators/rails/post_deployment_migration/post_deployment_migration_generator.rb +++ b/lib/generators/rails/post_deployment_migration/post_deployment_migration_generator.rb @@ -3,7 +3,7 @@ require 'rails/generators' module Rails class PostDeploymentMigrationGenerator < Rails::Generators::NamedBase def create_migration_file - timestamp = Time.now.strftime('%Y%m%d%H%I%S') + timestamp = Time.now.strftime('%Y%m%d%H%M%S') template "migration.rb", "db/post_migrate/#{timestamp}_#{file_name}.rb" end diff --git a/lib/gitlab.rb b/lib/gitlab.rb index 11f7c8b9510..aa9fd36d9ff 100644 --- a/lib/gitlab.rb +++ b/lib/gitlab.rb @@ -2,6 +2,7 @@ require_dependency 'gitlab/git' module Gitlab COM_URL = 'https://gitlab.com'.freeze + APP_DIRS_PATTERN = %r{^/?(app|config|ee|lib|spec|\(\w*\))} def self.com? # Check `staging?` as well to keep parity with gitlab.com diff --git a/lib/gitlab/auth/saml/config.rb b/lib/gitlab/auth/saml/config.rb index e654e7fe438..2760b1a3247 100644 --- a/lib/gitlab/auth/saml/config.rb +++ b/lib/gitlab/auth/saml/config.rb @@ -4,7 +4,7 @@ module Gitlab class Config class << self def options - Gitlab.config.omniauth.providers.find { |provider| provider.name == 'saml' } + Gitlab::Auth::OAuth::Provider.config_for('saml') end def groups diff --git a/lib/gitlab/diff/diff_refs.rb b/lib/gitlab/diff/diff_refs.rb index 88e0db830f6..81df47964be 100644 --- a/lib/gitlab/diff/diff_refs.rb +++ b/lib/gitlab/diff/diff_refs.rb @@ -44,7 +44,11 @@ module Gitlab project.commit(head_sha) else straight = start_sha == base_sha - CompareService.new(project, head_sha).execute(project, start_sha, straight: straight) + + CompareService.new(project, head_sha).execute(project, + start_sha, + base_sha: base_sha, + straight: straight) end end end diff --git a/lib/gitlab/git/gitlab_projects.rb b/lib/gitlab/git/gitlab_projects.rb index 5e1e22ae65c..a142ed6b2ef 100644 --- a/lib/gitlab/git/gitlab_projects.rb +++ b/lib/gitlab/git/gitlab_projects.rb @@ -67,7 +67,7 @@ module Gitlab tags_option = tags ? '--tags' : '--no-tags' logger.info "Fetching remote #{name} for repository #{repository_absolute_path}." - cmd = %W(git fetch #{name} --quiet) + cmd = %W(#{Gitlab.config.git.bin_path} fetch #{name} --quiet) cmd << '--prune' if prune cmd << '--force' if force cmd << tags_option @@ -85,7 +85,7 @@ module Gitlab def push_branches(remote_name, timeout, force, branch_names) logger.info "Pushing branches from #{repository_absolute_path} to remote #{remote_name}: #{branch_names}" - cmd = %w(git push) + cmd = %W(#{Gitlab.config.git.bin_path} push) cmd << '--force' if force cmd += %W(-- #{remote_name}).concat(branch_names) @@ -102,7 +102,7 @@ module Gitlab branches = branch_names.map { |branch_name| ":#{branch_name}" } logger.info "Pushing deleted branches from #{repository_absolute_path} to remote #{remote_name}: #{branch_names}" - cmd = %W(git push -- #{remote_name}).concat(branches) + cmd = %W(#{Gitlab.config.git.bin_path} push -- #{remote_name}).concat(branches) success = run(cmd, repository_absolute_path) @@ -143,7 +143,7 @@ module Gitlab end def remove_origin_in_repo - cmd = %w(git remote rm origin) + cmd = %W(#{Gitlab.config.git.bin_path} remote rm origin) run(cmd, repository_absolute_path) end @@ -223,7 +223,7 @@ module Gitlab masked_source = mask_password_in_url(source) logger.info "Importing project from <#{masked_source}> to <#{repository_absolute_path}>." - cmd = %W(git clone --bare -- #{source} #{repository_absolute_path}) + cmd = %W(#{Gitlab.config.git.bin_path} clone --bare -- #{source} #{repository_absolute_path}) success = run_with_timeout(cmd, timeout, nil) @@ -266,7 +266,7 @@ module Gitlab FileUtils.mkdir_p(File.dirname(to_path), mode: 0770) logger.info "Forking repository from <#{from_path}> to <#{to_path}>." - cmd = %W(git clone --bare --no-local -- #{from_path} #{to_path}) + cmd = %W(#{Gitlab.config.git.bin_path} clone --bare --no-local -- #{from_path} #{to_path}) run(cmd, nil) && Gitlab::Git::Repository.create_hooks(to_path, global_hooks_path) end diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb index 9cd76630484..8ca30ffc232 100644 --- a/lib/gitlab/gitaly_client.rb +++ b/lib/gitlab/gitaly_client.rb @@ -119,6 +119,9 @@ module Gitlab # def self.call(storage, service, rpc, request, remote_storage: nil, timeout: nil) start = Gitlab::Metrics::System.monotonic_time + request_hash = request.is_a?(Google::Protobuf::MessageExts) ? request.to_h : {} + @current_call_id ||= SecureRandom.uuid + enforce_gitaly_request_limits(:call) kwargs = request_kwargs(storage, timeout, remote_storage: remote_storage) @@ -135,6 +138,10 @@ module Gitlab gitaly_controller_action_duration_seconds.observe( current_transaction_labels.merge(gitaly_service: service.to_s, rpc: rpc.to_s), duration) + + add_call_details(id: @current_call_id, feature: service, duration: duration, request: request_hash) + + @current_call_id = nil end def self.handle_grpc_unavailable!(ex) @@ -252,12 +259,16 @@ module Gitlab feature_stack.unshift(feature) begin start = Gitlab::Metrics::System.monotonic_time + @current_call_id = SecureRandom.uuid + call_details = { id: @current_call_id } yield is_enabled ensure total_time = Gitlab::Metrics::System.monotonic_time - start gitaly_migrate_call_duration_seconds.observe({ gitaly_enabled: is_enabled, feature: feature }, total_time) feature_stack.shift Thread.current[:gitaly_feature_stack] = nil if feature_stack.empty? + + add_call_details(call_details.merge(feature: feature, duration: total_time)) end end end @@ -344,6 +355,22 @@ module Gitlab end end + def self.add_call_details(details) + id = details.delete(:id) + + return unless id && RequestStore.active? && RequestStore.store[:peek_enabled] + + RequestStore.store['gitaly_call_details'] ||= {} + RequestStore.store['gitaly_call_details'][id] ||= {} + RequestStore.store['gitaly_call_details'][id].merge!(details) + end + + def self.list_call_details + return {} unless RequestStore.active? && RequestStore.store[:peek_enabled] + + RequestStore.store['gitaly_call_details'] || {} + end + def self.expected_server_version path = Rails.root.join(SERVER_VERSION_FILE) path.read.chomp diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index 4f160e4a447..a61beafae0d 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -197,10 +197,7 @@ module Gitlab end def github_omniauth_provider - @github_omniauth_provider ||= - Gitlab.config.omniauth.providers - .find { |provider| provider.name == 'github' } - .to_h + @github_omniauth_provider ||= Gitlab::Auth::OAuth::Provider.config_for('github').to_h end def rate_limit_counter diff --git a/lib/gitlab/gitlab_import/client.rb b/lib/gitlab/gitlab_import/client.rb index 075b3982608..5482504e72e 100644 --- a/lib/gitlab/gitlab_import/client.rb +++ b/lib/gitlab/gitlab_import/client.rb @@ -72,7 +72,7 @@ module Gitlab end def config - Gitlab.config.omniauth.providers.find {|provider| provider.name == "gitlab"} + Gitlab::Auth::OAuth::Provider.config_for('gitlab') end def gitlab_options diff --git a/lib/gitlab/legacy_github_import/client.rb b/lib/gitlab/legacy_github_import/client.rb index 53c910d44bd..d8ed0ebca9d 100644 --- a/lib/gitlab/legacy_github_import/client.rb +++ b/lib/gitlab/legacy_github_import/client.rb @@ -83,7 +83,7 @@ module Gitlab end def config - Gitlab.config.omniauth.providers.find { |provider| provider.name == "github" } + Gitlab::Auth::OAuth::Provider.config_for('github') end def github_options diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb index 757ef71b95a..1e45d074e0a 100644 --- a/lib/gitlab/search_results.rb +++ b/lib/gitlab/search_results.rb @@ -7,8 +7,8 @@ module Gitlab def initialize(opts = {}) @id = opts.fetch(:id, nil) - @filename = opts.fetch(:filename, nil) - @basename = opts.fetch(:basename, nil) + @filename = encode_utf8(opts.fetch(:filename, nil)) + @basename = encode_utf8(opts.fetch(:basename, nil)) @ref = opts.fetch(:ref, nil) @startline = opts.fetch(:startline, nil) @data = encode_utf8(opts.fetch(:data, nil)) diff --git a/lib/google_api/auth.rb b/lib/google_api/auth.rb index 99a82c849e0..1aeaa387a49 100644 --- a/lib/google_api/auth.rb +++ b/lib/google_api/auth.rb @@ -32,7 +32,7 @@ module GoogleApi private def config - Gitlab.config.omniauth.providers.find { |provider| provider.name == "google_oauth2" } + Gitlab::Auth::OAuth::Provider.config_for('google_oauth2') end def client diff --git a/lib/peek/views/gitaly.rb b/lib/peek/views/gitaly.rb index d519d8e86fa..ab35f7a2258 100644 --- a/lib/peek/views/gitaly.rb +++ b/lib/peek/views/gitaly.rb @@ -10,11 +10,29 @@ module Peek end def results - { duration: formatted_duration, calls: calls } + { + duration: formatted_duration, + calls: calls, + details: details + } end private + def details + ::Gitlab::GitalyClient.list_call_details + .values + .sort { |a, b| b[:duration] <=> a[:duration] } + .map(&method(:format_call_details)) + end + + def format_call_details(call) + pretty_request = call[:request]&.reject { |k, v| v.blank? }.to_h.pretty_inspect + + call.merge(duration: (call[:duration] * 1000).round(3), + request: pretty_request || {}) + end + def formatted_duration ms = duration * 1000 if ms >= 1000 diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 3f05e878cc8..a04f869f2bb 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-06 17:36+0100\n" -"PO-Revision-Date: 2018-03-06 17:36+0100\n" +"POT-Creation-Date: 2018-03-12 19:50+0100\n" +"PO-Revision-Date: 2018-03-12 19:50+0100\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: \n" @@ -28,6 +28,11 @@ msgid_plural "%d commits behind" msgstr[0] "" msgstr[1] "" +msgid "%d exporter" +msgid_plural "%d exporters" +msgstr[0] "" +msgstr[1] "" + msgid "%d issue" msgid_plural "%d issues" msgstr[0] "" @@ -43,6 +48,11 @@ msgid_plural "%d merge requests" msgstr[0] "" msgstr[1] "" +msgid "%d metric" +msgid_plural "%d metrics" +msgstr[0] "" +msgstr[1] "" + msgid "%s additional commit has been omitted to prevent performance issues." msgid_plural "%s additional commits have been omitted to prevent performance issues." msgstr[0] "" @@ -102,6 +112,9 @@ msgstr "" msgid "2FA enabled" msgstr "" +msgid "<strong>Removes</strong> source branch" +msgstr "" + msgid "A collection of graphs regarding Continuous Integration" msgstr "" @@ -111,6 +124,9 @@ msgstr "" msgid "A project is where you house your files (repository), plan your work (issues), and publish your documentation (wiki), %{among_other_things_link}." msgstr "" +msgid "A user with write access to the source branch selected this option" +msgstr "" + msgid "About auto deploy" msgstr "" @@ -213,7 +229,7 @@ msgstr "" msgid "All features are enabled for blank projects, from templates, or when importing, but you can disable them afterward in the project settings." msgstr "" -msgid "Allow edits from maintainers" +msgid "Allow edits from maintainers." msgstr "" msgid "Allows you to add and manage Kubernetes clusters." @@ -857,6 +873,9 @@ msgstr "" msgid "ClusterIntegration|Learn more about environments" msgstr "" +msgid "ClusterIntegration|Learn more about security configuration" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "" @@ -914,6 +933,9 @@ msgstr "" msgid "ClusterIntegration|Save changes" msgstr "" +msgid "ClusterIntegration|Security" +msgstr "" + msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster" msgstr "" @@ -941,6 +963,9 @@ msgstr "" msgid "ClusterIntegration|Something went wrong while installing %{title}" msgstr "" +msgid "ClusterIntegration|The default cluster configuration grants access to a wide set of functionalities needed to successfully build and deploy a containerised application." +msgstr "" + msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below" msgstr "" @@ -1182,6 +1207,9 @@ msgstr "" msgid "Create empty bare repository" msgstr "" +msgid "Create group label" +msgstr "" + msgid "Create lists from labels. Issues with that label appear in that list." msgstr "" @@ -1197,6 +1225,9 @@ msgstr "" msgid "Create new..." msgstr "" +msgid "Create project label" +msgstr "" + msgid "CreateNewFork|Fork" msgstr "" @@ -1776,9 +1807,18 @@ msgstr "" msgid "Labels" msgstr "" +msgid "Labels can be applied to %{features}. Group labels are available for any project within the group." +msgstr "" + msgid "Labels can be applied to issues and merge requests to categorize them." msgstr "" +msgid "Labels|Promote Label" +msgstr "" + +msgid "Labels|Promote label %{labelTitle} to Group Label?" +msgstr "" + msgid "Last %d day" msgid_plural "Last %d days" msgstr[0] "" @@ -1850,9 +1890,15 @@ msgstr "" msgid "Login" msgstr "" +msgid "Manage group labels" +msgstr "" + msgid "Manage labels" msgstr "" +msgid "Manage project labels" +msgstr "" + msgid "Mar" msgstr "" @@ -1907,6 +1953,12 @@ msgstr "" msgid "Milestones|Milestone %{milestoneTitle} was not found" msgstr "" +msgid "Milestones|Promote %{milestoneTitle} to group milestone?" +msgstr "" + +msgid "Milestones|Promote Milestone" +msgstr "" + msgid "MissingSSHKeyWarningLink|add an SSH key" msgstr "" @@ -2002,6 +2054,9 @@ msgstr "" msgid "No file chosen" msgstr "" +msgid "No labels created yet." +msgstr "" + msgid "No repository" msgstr "" @@ -2251,9 +2306,15 @@ msgstr "" msgid "Pipelines|Loading Pipelines" msgstr "" +msgid "Pipelines|Project cache successfully reset." +msgstr "" + msgid "Pipelines|Run Pipeline" msgstr "" +msgid "Pipelines|Something went wrong while cleaning runners cache." +msgstr "" + msgid "Pipelines|There are currently no %{scope} pipelines." msgstr "" @@ -2380,9 +2441,6 @@ msgstr "" msgid "Project avatar in repository: %{link}" msgstr "" -msgid "Project cache successfully reset." -msgstr "" - msgid "Project details" msgstr "" @@ -2446,6 +2504,12 @@ msgstr "" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "" +msgid "PrometheusService|%{exporters} with %{metrics} were found" +msgstr "" + +msgid "PrometheusService|<p class=\"text-tertiary\">No <a href=\"%{docsUrl}\">common metrics</a> were found</p>" +msgstr "" + msgid "PrometheusService|Active" msgstr "" @@ -2458,6 +2522,9 @@ msgstr "" msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." msgstr "" +msgid "PrometheusService|Common metrics" +msgstr "" + msgid "PrometheusService|Finding and configuring metrics..." msgstr "" @@ -2479,15 +2546,9 @@ msgstr "" msgid "PrometheusService|Missing environment variable" msgstr "" -msgid "PrometheusService|Monitored" -msgstr "" - msgid "PrometheusService|More information" msgstr "" -msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." -msgstr "" - msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" msgstr "" @@ -2503,7 +2564,16 @@ msgstr "" msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below" msgstr "" -msgid "PrometheusService|View environments" +msgid "PrometheusService|Waiting for your first deployment to an environment to find common metrics" +msgstr "" + +msgid "Promote" +msgstr "" + +msgid "Promote to Group Label" +msgstr "" + +msgid "Promote to Group Milestone" msgstr "" msgid "Protip:" @@ -2515,9 +2585,6 @@ msgstr "" msgid "Public - The project can be accessed without any authentication." msgstr "" -msgid "Push access to this project is necessary in order to enable this option" -msgstr "" - msgid "Push events" msgstr "" @@ -3338,9 +3405,6 @@ msgstr "" msgid "Trigger this manual action" msgstr "" -msgid "Unable to reset project cache." -msgstr "" - msgid "Unlock" msgstr "" @@ -3383,12 +3447,18 @@ msgstr "" msgid "View file @ " msgstr "" +msgid "View group labels" +msgstr "" + msgid "View labels" msgstr "" msgid "View open merge request" msgstr "" +msgid "View project labels" +msgstr "" + msgid "View replaced file @ " msgstr "" diff --git a/package.json b/package.json index 6549da99f97..472bdbebda8 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "webpack-prod": "NODE_ENV=production webpack --config config/webpack.config.js" }, "dependencies": { - "@gitlab-org/gitlab-svgs": "^1.13.0", + "@gitlab-org/gitlab-svgs": "^1.14.0", "autosize": "^4.0.0", "axios": "^0.17.1", "babel-core": "^6.26.0", diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index 3d13f806b11..52ff47d57f9 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -343,7 +343,7 @@ describe 'Issue Boards', :js do wait_for_requests - click_link 'Create new label' + click_link 'Create project label' fill_in('new_label_name', with: 'Testing New Label') diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index b2dbfcd0031..d4c44c1adf9 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -312,12 +312,12 @@ describe 'Issue Boards', :js do expect(card).not_to have_content(stretch.title) end - it 'creates new label' do + it 'creates project label' do click_card(card) page.within('.labels') do click_link 'Edit' - click_link 'Create new label' + click_link 'Create project label' fill_in 'new_label_name', with: 'test label' first('.suggest-colors-dropdown a').click click_button 'Create' diff --git a/spec/features/boards/sub_group_project_spec.rb b/spec/features/boards/sub_group_project_spec.rb index 11a54079f4f..5fdb8044db2 100644 --- a/spec/features/boards/sub_group_project_spec.rb +++ b/spec/features/boards/sub_group_project_spec.rb @@ -24,7 +24,7 @@ describe 'Sub-group project issue boards', :js do page.within '.labels' do click_link 'Edit' - click_link 'Create new label' + click_link 'Create project label' end page.within '.dropdown-new-label' do diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index ef6b8edd0ad..38c618d300e 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -306,10 +306,10 @@ describe 'New/edit issue', :js do visit new_project_issue_path(sub_group_project) end - it 'creates new label from dropdown' do + it 'creates project label from dropdown' do click_button 'Labels' - click_link 'Create new label' + click_link 'Create project label' page.within '.dropdown-new-label' do fill_in 'new_label_name', with: 'test label' diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb index 64b4f9e7e67..b835558b142 100644 --- a/spec/features/issues/issue_sidebar_spec.rb +++ b/spec/features/issues/issue_sidebar_spec.rb @@ -117,22 +117,22 @@ feature 'Issue Sidebar' do end end - it 'shows option to create a new label' do + it 'shows option to create a project label' do page.within('.block.labels') do - expect(page).to have_content 'Create new' + expect(page).to have_content 'Create project' end end - context 'creating a new label', :js do + context 'creating a project label', :js do before do page.within('.block.labels') do - click_link 'Create new' + click_link 'Create project' end end it 'shows dropdown switches to "create label" section' do page.within('.block.labels') do - expect(page).to have_content 'Create new label' + expect(page).to have_content 'Create project label' end end diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb index 890774922aa..db92a3504f3 100644 --- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb @@ -125,6 +125,12 @@ describe 'Merge request > User merges when pipeline succeeds', :js do expect(page).to have_content "canceled the automatic merge" end + it 'allows to remove source branch' do + click_link "Remove source branch" + + expect(page).to have_content "The source branch will be removed" + end + context 'when pipeline succeeds' do before do build.success diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb index 3e83a549682..b4ad4b64d8e 100644 --- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb +++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb @@ -108,6 +108,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do it 'shows resolved discussion when toggled' do find(".timeline-content .discussion[data-discussion-id='#{note.discussion_id}'] .discussion-toggle-button").click + expect(page.find(".line-holder-placeholder")).to be_visible expect(page.find(".timeline-content #note_#{note.id}")).to be_visible end end diff --git a/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb b/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb index 8a834adbf17..565e375600b 100644 --- a/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb +++ b/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb @@ -5,15 +5,18 @@ describe 'Merge request > User scrolls to note on load', :js do let(:user) { project.creator } let(:merge_request) { create(:merge_request, source_project: project, author: user) } let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) } + let(:resolved_note) { create(:diff_note_on_merge_request, :resolved, noteable: merge_request, project: project) } let(:fragment_id) { "#note_#{note.id}" } + let(:collapsed_fragment_id) { "#note_#{resolved_note.id}" } before do sign_in(user) page.current_window.resize_to(1000, 300) - visit "#{project_merge_request_path(project, merge_request)}#{fragment_id}" end - it 'scrolls down to fragment' do + it 'scrolls note into view' do + visit "#{project_merge_request_path(project, merge_request)}#{fragment_id}" + page_height = page.current_window.size[1] page_scroll_y = page.evaluate_script("window.scrollY") fragment_position_top = page.evaluate_script("Math.round($('#{fragment_id}').offset().top)") @@ -23,4 +26,13 @@ describe 'Merge request > User scrolls to note on load', :js do expect(fragment_position_top).to be >= page_scroll_y expect(fragment_position_top).to be < (page_scroll_y + page_height) end + + it 'expands collapsed notes' do + visit "#{project_merge_request_path(project, merge_request)}#{collapsed_fragment_id}" + note_element = find(collapsed_fragment_id) + note_container = note_element.ancestor('.js-toggle-container') + + expect(note_element.visible?).to eq true + expect(note_container.find('.line_content.noteable_line.old', match: :first).visible?).to eq true + end end diff --git a/spec/helpers/import_helper_spec.rb b/spec/helpers/import_helper_spec.rb index 9afff47f4e9..57d843c1be2 100644 --- a/spec/helpers/import_helper_spec.rb +++ b/spec/helpers/import_helper_spec.rb @@ -27,25 +27,48 @@ describe ImportHelper do describe '#provider_project_link' do context 'when provider is "github"' do + let(:github_server_url) { nil } + + before do + setting = Settingslogic.new('name' => 'github') + setting['url'] = github_server_url if github_server_url + + allow(Gitlab.config.omniauth).to receive(:providers).and_return([setting]) + end + context 'when provider does not specify a custom URL' do it 'uses default GitHub URL' do - allow(Gitlab.config.omniauth).to receive(:providers) - .and_return([Settingslogic.new('name' => 'github')]) - expect(helper.provider_project_link('github', 'octocat/Hello-World')) .to include('href="https://github.com/octocat/Hello-World"') end end context 'when provider specify a custom URL' do + let(:github_server_url) { 'https://github.company.com' } + it 'uses custom URL' do - allow(Gitlab.config.omniauth).to receive(:providers) - .and_return([Settingslogic.new('name' => 'github', 'url' => 'https://github.company.com')]) + expect(helper.provider_project_link('github', 'octocat/Hello-World')) + .to include('href="https://github.company.com/octocat/Hello-World"') + end + end + + context "when custom URL contains a '/' char at the end" do + let(:github_server_url) { 'https://github.company.com/' } + it "doesn't render double slash" do expect(helper.provider_project_link('github', 'octocat/Hello-World')) .to include('href="https://github.company.com/octocat/Hello-World"') end end + + context 'when provider is missing' do + it 'uses the default URL' do + allow(Gitlab.config.omniauth).to receive(:providers).and_return([]) + + expect(helper.provider_project_link('github', 'octocat/Hello-World')) + .to include('href="https://github.com/octocat/Hello-World"') + end + end end context 'when provider is "gitea"' do diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index 619baa78bfa..a2cda58e5d2 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -139,4 +139,76 @@ describe LabelsHelper do expect(text_color_for_bg('#000')).to eq '#FFFFFF' end end + + describe 'create_label_title' do + set(:group) { create(:group) } + + context 'with a group as subject' do + it 'returns "Create group label"' do + expect(create_label_title(group)).to eq 'Create group label' + end + end + + context 'with a project as subject' do + set(:project) { create(:project, namespace: group) } + + it 'returns "Create project label"' do + expect(create_label_title(project)).to eq 'Create project label' + end + end + + context 'with no subject' do + it 'returns "Create new label"' do + expect(create_label_title(nil)).to eq 'Create new label' + end + end + end + + describe 'manage_labels_title' do + set(:group) { create(:group) } + + context 'with a group as subject' do + it 'returns "Manage group labels"' do + expect(manage_labels_title(group)).to eq 'Manage group labels' + end + end + + context 'with a project as subject' do + set(:project) { create(:project, namespace: group) } + + it 'returns "Manage project labels"' do + expect(manage_labels_title(project)).to eq 'Manage project labels' + end + end + + context 'with no subject' do + it 'returns "Manage labels"' do + expect(manage_labels_title(nil)).to eq 'Manage labels' + end + end + end + + describe 'view_labels_title' do + set(:group) { create(:group) } + + context 'with a group as subject' do + it 'returns "View group labels"' do + expect(view_labels_title(group)).to eq 'View group labels' + end + end + + context 'with a project as subject' do + set(:project) { create(:project, namespace: group) } + + it 'returns "View project labels"' do + expect(view_labels_title(project)).to eq 'View project labels' + end + end + + context 'with no subject' do + it 'returns "View labels"' do + expect(view_labels_title(nil)).to eq 'View labels' + end + end + end end diff --git a/spec/javascripts/activities_spec.js b/spec/javascripts/activities_spec.js index 7a9c539e9d0..909a1bf76bc 100644 --- a/spec/javascripts/activities_spec.js +++ b/spec/javascripts/activities_spec.js @@ -1,5 +1,6 @@ /* eslint-disable no-unused-expressions, no-prototype-builtins, no-new, no-shadow, max-len */ +import $ from 'jquery'; import 'vendor/jquery.endless-scroll'; import Activities from '~/activities'; diff --git a/spec/javascripts/ajax_loading_spinner_spec.js b/spec/javascripts/ajax_loading_spinner_spec.js index 95c2c122403..261375d3a0e 100644 --- a/spec/javascripts/ajax_loading_spinner_spec.js +++ b/spec/javascripts/ajax_loading_spinner_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import AjaxLoadingSpinner from '~/ajax_loading_spinner'; describe('Ajax Loading Spinner', () => { @@ -10,7 +11,7 @@ describe('Ajax Loading Spinner', () => { }); it('change current icon with spinner icon and disable link while waiting ajax response', (done) => { - spyOn(jQuery, 'ajax').and.callFake((req) => { + spyOn($, 'ajax').and.callFake((req) => { const xhr = new XMLHttpRequest(); const ajaxLoadingSpinner = document.querySelector('.js-ajax-loading-spinner'); const icon = ajaxLoadingSpinner.querySelector('i'); @@ -33,7 +34,7 @@ describe('Ajax Loading Spinner', () => { }); it('use original icon again and enabled the link after complete the ajax request', (done) => { - spyOn(jQuery, 'ajax').and.callFake((req) => { + spyOn($, 'ajax').and.callFake((req) => { const xhr = new XMLHttpRequest(); const ajaxLoadingSpinner = document.querySelector('.js-ajax-loading-spinner'); diff --git a/spec/javascripts/autosave_spec.js b/spec/javascripts/autosave_spec.js index b568d7fa8b0..38ae5b7e00c 100644 --- a/spec/javascripts/autosave_spec.js +++ b/spec/javascripts/autosave_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Autosave from '~/autosave'; import AccessorUtilities from '~/lib/utils/accessor'; diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index 8e4bbb90ccb..e81055bc08f 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, max-len */ +import $ from 'jquery'; import Cookies from 'js-cookie'; import loadAwardsHandler from '~/awards_handler'; diff --git a/spec/javascripts/behaviors/autosize_spec.js b/spec/javascripts/behaviors/autosize_spec.js index 960b731892a..c411c5174fb 100644 --- a/spec/javascripts/behaviors/autosize_spec.js +++ b/spec/javascripts/behaviors/autosize_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import '~/behaviors/autosize'; function load() { diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index d5300d9c63d..c37c62c63dd 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import '~/behaviors/quick_submit'; describe('Quick Submit behavior', () => { diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index e500bbe750f..a434949b9da 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import '~/behaviors/requires_input'; describe('requiresInput', () => { diff --git a/spec/javascripts/blob/blob_file_dropzone_spec.js b/spec/javascripts/blob/blob_file_dropzone_spec.js index 47de63e6690..0b1de504435 100644 --- a/spec/javascripts/blob/blob_file_dropzone_spec.js +++ b/spec/javascripts/blob/blob_file_dropzone_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import BlobFileDropzone from '~/blob/blob_file_dropzone'; describe('BlobFileDropzone', () => { @@ -27,7 +28,7 @@ describe('BlobFileDropzone', () => { name: 'some-file.jpg', type: 'jpg', }; - const fakeEvent = jQuery.Event('drop', { + const fakeEvent = $.Event('drop', { dataTransfer: { files: [file] }, }); diff --git a/spec/javascripts/blob/viewer/index_spec.js b/spec/javascripts/blob/viewer/index_spec.js index 892411a6a40..f920c4ca945 100644 --- a/spec/javascripts/blob/viewer/index_spec.js +++ b/spec/javascripts/blob/viewer/index_spec.js @@ -1,4 +1,6 @@ /* eslint-disable no-new */ + +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import BlobViewer from '~/blob/viewer/index'; import axios from '~/lib/utils/axios_utils'; diff --git a/spec/javascripts/bootstrap_jquery_spec.js b/spec/javascripts/bootstrap_jquery_spec.js index 48994b7c523..0fd6f9dc810 100644 --- a/spec/javascripts/bootstrap_jquery_spec.js +++ b/spec/javascripts/bootstrap_jquery_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var */ +import $ from 'jquery'; import '~/commons/bootstrap'; (function() { diff --git a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js index 270f925e699..2fa50975f0f 100644 --- a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import VariableList from '~/ci_variable_list/ci_variable_list'; import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; diff --git a/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js b/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js index eb508a7f059..1ea8d86cb7e 100644 --- a/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import setupNativeFormVariableList from '~/ci_variable_list/native_form_variable_list'; describe('NativeFormVariableList', () => { diff --git a/spec/javascripts/commits_spec.js b/spec/javascripts/commits_spec.js index 1daccc8dd02..977298b9221 100644 --- a/spec/javascripts/commits_spec.js +++ b/spec/javascripts/commits_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import 'vendor/jquery.endless-scroll'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; diff --git a/spec/javascripts/create_item_dropdown_spec.js b/spec/javascripts/create_item_dropdown_spec.js index 143137c23ec..ee26122be12 100644 --- a/spec/javascripts/create_item_dropdown_spec.js +++ b/spec/javascripts/create_item_dropdown_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import CreateItemDropdown from '~/create_item_dropdown'; const DROPDOWN_ITEM_DATA = [{ diff --git a/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js b/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js index 1b1f28f3ddb..480c138b9db 100644 --- a/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js +++ b/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import { diff --git a/spec/javascripts/feature_highlight/feature_highlight_spec.js b/spec/javascripts/feature_highlight/feature_highlight_spec.js index f3f80cb3771..d2dd39d49d1 100644 --- a/spec/javascripts/feature_highlight/feature_highlight_spec.js +++ b/spec/javascripts/feature_highlight/feature_highlight_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import * as featureHighlightHelper from '~/feature_highlight/feature_highlight_helper'; import * as featureHighlight from '~/feature_highlight/feature_highlight'; import axios from '~/lib/utils/axios_utils'; diff --git a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js index 71c14582329..8c5a0961a02 100644 --- a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js @@ -1,8 +1,9 @@ +import $ from 'jquery'; import FilteredSearchDropdownManager from '~/filtered_search/filtered_search_dropdown_manager'; describe('Filtered Search Dropdown Manager', () => { beforeEach(() => { - spyOn(jQuery, 'ajax'); + spyOn($, 'ajax'); }); describe('addWordToInput', () => { diff --git a/spec/javascripts/gfm_auto_complete_spec.js b/spec/javascripts/gfm_auto_complete_spec.js index 50a587ef351..dc0a5bc275c 100644 --- a/spec/javascripts/gfm_auto_complete_spec.js +++ b/spec/javascripts/gfm_auto_complete_spec.js @@ -1,5 +1,6 @@ /* eslint no-param-reassign: "off" */ +import $ from 'jquery'; import GfmAutoComplete from '~/gfm_auto_complete'; import 'vendor/jquery.caret'; diff --git a/spec/javascripts/gl_dropdown_spec.js b/spec/javascripts/gl_dropdown_spec.js index 67b854f61c0..0e4a7017406 100644 --- a/spec/javascripts/gl_dropdown_spec.js +++ b/spec/javascripts/gl_dropdown_spec.js @@ -1,5 +1,6 @@ /* eslint-disable comma-dangle, no-param-reassign, no-unused-expressions, max-len */ +import $ from 'jquery'; import '~/gl_dropdown'; import '~/lib/utils/common_utils'; import * as urlUtils from '~/lib/utils/url_utility'; diff --git a/spec/javascripts/gl_field_errors_spec.js b/spec/javascripts/gl_field_errors_spec.js index 2779686a6f5..4e93fd91751 100644 --- a/spec/javascripts/gl_field_errors_spec.js +++ b/spec/javascripts/gl_field_errors_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, arrow-body-style */ +import $ from 'jquery'; import GlFieldErrors from '~/gl_field_errors'; describe('GL Style Field Errors', function() { diff --git a/spec/javascripts/gl_form_spec.js b/spec/javascripts/gl_form_spec.js index 9c1fc0fda9e..74383f901b2 100644 --- a/spec/javascripts/gl_form_spec.js +++ b/spec/javascripts/gl_form_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import autosize from 'autosize'; import GLForm from '~/gl_form'; import '~/lib/utils/text_utility'; diff --git a/spec/javascripts/groups/components/app_spec.js b/spec/javascripts/groups/components/app_spec.js index 46c7b9f54f2..d8428bd0e08 100644 --- a/spec/javascripts/groups/components/app_spec.js +++ b/spec/javascripts/groups/components/app_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import * as utils from '~/lib/utils/url_utility'; diff --git a/spec/javascripts/header_spec.js b/spec/javascripts/header_spec.js index 2443ffd48f3..16ac438f7ac 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/javascripts/header_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import initTodoToggle from '~/header'; describe('Header', function () { diff --git a/spec/javascripts/integrations/integration_settings_form_spec.js b/spec/javascripts/integrations/integration_settings_form_spec.js index d0fba908e34..050b1f2074e 100644 --- a/spec/javascripts/integrations/integration_settings_form_spec.js +++ b/spec/javascripts/integrations/integration_settings_form_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import MockAdaptor from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import IntegrationSettingsForm from '~/integrations/integration_settings_form'; diff --git a/spec/javascripts/issuable_spec.js b/spec/javascripts/issuable_spec.js index d53ffecbd35..57bf746f080 100644 --- a/spec/javascripts/issuable_spec.js +++ b/spec/javascripts/issuable_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import MockAdaptor from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import IssuableIndex from '~/issuable_index'; diff --git a/spec/javascripts/issuable_time_tracker_spec.js b/spec/javascripts/issuable_time_tracker_spec.js index 365e9fe6a4b..ba9040524b1 100644 --- a/spec/javascripts/issuable_time_tracker_spec.js +++ b/spec/javascripts/issuable_time_tracker_spec.js @@ -1,5 +1,6 @@ /* eslint-disable no-unused-vars, space-before-function-paren, func-call-spacing, no-spaced-func, semi, max-len, quotes, space-infix-ops, padded-blocks */ +import $ from 'jquery'; import Vue from 'vue'; import timeTracker from '~/sidebar/components/time_tracking/time_tracker.vue'; diff --git a/spec/javascripts/issue_show/components/description_spec.js b/spec/javascripts/issue_show/components/description_spec.js index ff7f99eec14..d96151a8a3a 100644 --- a/spec/javascripts/issue_show/components/description_spec.js +++ b/spec/javascripts/issue_show/components/description_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import descriptionComponent from '~/issue_show/components/description.vue'; import * as taskList from '~/task_list'; diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index 177962ecf82..f37426a72d4 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -1,4 +1,6 @@ /* eslint-disable space-before-function-paren, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */ + +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import Issue from '~/issue'; diff --git a/spec/javascripts/job_spec.js b/spec/javascripts/job_spec.js index b4599688c6d..c6bbacf237a 100644 --- a/spec/javascripts/job_spec.js +++ b/spec/javascripts/job_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils'; diff --git a/spec/javascripts/labels_issue_sidebar_spec.js b/spec/javascripts/labels_issue_sidebar_spec.js index 7d992f62f64..5aafb6ad8f0 100644 --- a/spec/javascripts/labels_issue_sidebar_spec.js +++ b/spec/javascripts/labels_issue_sidebar_spec.js @@ -1,4 +1,6 @@ /* eslint-disable no-new */ + +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import IssuableContext from '~/issuable_context'; diff --git a/spec/javascripts/labels_select_spec.js b/spec/javascripts/labels_select_spec.js index b8f7b1dc855..a2b89c0aef5 100644 --- a/spec/javascripts/labels_select_spec.js +++ b/spec/javascripts/labels_select_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import LabelsSelect from '~/labels_select'; const mockUrl = '/foo/bar/url'; diff --git a/spec/javascripts/line_highlighter_spec.js b/spec/javascripts/line_highlighter_spec.js index 89f4b85541d..d2bdc9e160c 100644 --- a/spec/javascripts/line_highlighter_spec.js +++ b/spec/javascripts/line_highlighter_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, no-param-reassign, quotes, prefer-template, no-else-return, new-cap, dot-notation, no-return-assign, comma-dangle, no-new, one-var, one-var-declaration-per-line, jasmine/no-spec-dupes, no-underscore-dangle, max-len */ +import $ from 'jquery'; import LineHighlighter from '~/line_highlighter'; (function() { diff --git a/spec/javascripts/merge_request_notes_spec.js b/spec/javascripts/merge_request_notes_spec.js index 0d16b23302f..eb644e698da 100644 --- a/spec/javascripts/merge_request_notes_spec.js +++ b/spec/javascripts/merge_request_notes_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import 'autosize'; import '~/gl_form'; diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js index bdfd16ac995..74ceff76d37 100644 --- a/spec/javascripts/merge_request_spec.js +++ b/spec/javascripts/merge_request_spec.js @@ -1,4 +1,6 @@ /* eslint-disable space-before-function-paren, no-return-assign */ + +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import MergeRequest from '~/merge_request'; @@ -27,7 +29,7 @@ import IssuablesHelper from '~/helpers/issuables_helper'; }); it('modifies the Markdown field', function() { - spyOn(jQuery, 'ajax').and.stub(); + spyOn($, 'ajax').and.stub(); const changeEvent = document.createEvent('HTMLEvents'); changeEvent.initEvent('change', true, true); $('input[type=checkbox]').attr('checked', true)[0].dispatchEvent(changeEvent); @@ -48,7 +50,7 @@ import IssuablesHelper from '~/helpers/issuables_helper'; describe('class constructor', () => { beforeEach(() => { - spyOn(jQuery, 'ajax').and.stub(); + spyOn($, 'ajax').and.stub(); }); it('calls .initCloseReopenReport', () => { diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index fda24db98b4..79c8cf0ba32 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -1,4 +1,6 @@ /* eslint-disable no-var, comma-dangle, object-shorthand */ + +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import * as urlUtils from '~/lib/utils/url_utility'; diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js index 6fa6f44f953..009b3fd75b7 100644 --- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js +++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js @@ -1,5 +1,6 @@ /* eslint-disable no-new */ +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown'; diff --git a/spec/javascripts/namespace_select_spec.js b/spec/javascripts/namespace_select_spec.js index 9d7625ca269..3b2641f7646 100644 --- a/spec/javascripts/namespace_select_spec.js +++ b/spec/javascripts/namespace_select_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import NamespaceSelect from '~/namespace_select'; describe('NamespaceSelect', () => { diff --git a/spec/javascripts/new_branch_spec.js b/spec/javascripts/new_branch_spec.js index 50a5e4ff056..5e5d8f8f34f 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/javascripts/new_branch_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-return-assign, quotes, max-len */ +import $ from 'jquery'; import NewBranchForm from '~/new_branch_form'; (function() { diff --git a/spec/javascripts/notes/components/comment_form_spec.js b/spec/javascripts/notes/components/comment_form_spec.js index 6a7131528a3..224debbeff6 100644 --- a/spec/javascripts/notes/components/comment_form_spec.js +++ b/spec/javascripts/notes/components/comment_form_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import Autosize from 'autosize'; import store from '~/notes/stores'; @@ -199,6 +200,20 @@ describe('issue_comment_form component', () => { done(); }); }); + + describe('when clicking close/reopen button', () => { + it('should disable button and show a loading spinner', (done) => { + const toggleStateButton = vm.$el.querySelector('.js-action-button'); + + toggleStateButton.click(); + Vue.nextTick(() => { + expect(toggleStateButton.disabled).toEqual(true); + expect(toggleStateButton.querySelector('.js-loading-button-icon')).not.toBeNull(); + + done(); + }); + }); + }); }); describe('issue is confidential', () => { diff --git a/spec/javascripts/notes/components/note_app_spec.js b/spec/javascripts/notes/components/note_app_spec.js index e1c612f5100..ac39418c3e6 100644 --- a/spec/javascripts/notes/components/note_app_spec.js +++ b/spec/javascripts/notes/components/note_app_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import Vue from 'vue'; import notesApp from '~/notes/components/notes_app.vue'; diff --git a/spec/javascripts/notes/components/noteable_note_spec.js b/spec/javascripts/notes/components/noteable_note_spec.js index 88a7ffb0b9c..cfd037633e9 100644 --- a/spec/javascripts/notes/components/noteable_note_spec.js +++ b/spec/javascripts/notes/components/noteable_note_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import Vue from 'vue'; import store from '~/notes/stores'; diff --git a/spec/javascripts/notes/mock_data.js b/spec/javascripts/notes/mock_data.js index bf60cb12f52..5be13ed0dfe 100644 --- a/spec/javascripts/notes/mock_data.js +++ b/spec/javascripts/notes/mock_data.js @@ -1,7 +1,7 @@ /* eslint-disable */ export const notesDataMock = { discussionsPath: '/gitlab-org/gitlab-ce/issues/26/discussions.json', - lastFetchedAt: '1501862675', + lastFetchedAt: 1501862675, markdownDocsPath: '/help/user/markdown', newSessionPath: '/users/sign_in?redirect_to_referer=yes', notesPath: '/gitlab-org/gitlab-ce/noteable/issue/98/notes', diff --git a/spec/javascripts/notes/stores/actions_spec.js b/spec/javascripts/notes/stores/actions_spec.js index ab80ed7bbfb..91249b2c79e 100644 --- a/spec/javascripts/notes/stores/actions_spec.js +++ b/spec/javascripts/notes/stores/actions_spec.js @@ -1,5 +1,6 @@ import Vue from 'vue'; import _ from 'underscore'; +import { headersInterceptor } from 'spec/helpers/vue_resource_helper'; import * as actions from '~/notes/stores/actions'; import store from '~/notes/stores'; import testAction from '../../helpers/vuex_action_helper'; @@ -87,6 +88,7 @@ describe('Actions Notes Store', () => { store.dispatch('closeIssue', { notesData: { closeIssuePath: '' } }) .then(() => { expect(store.state.noteableData.state).toEqual('closed'); + expect(store.state.isToggleStateButtonLoading).toEqual(false); done(); }) .catch(done.fail); @@ -98,6 +100,7 @@ describe('Actions Notes Store', () => { store.dispatch('reopenIssue', { notesData: { reopenIssuePath: '' } }) .then(() => { expect(store.state.noteableData.state).toEqual('reopened'); + expect(store.state.isToggleStateButtonLoading).toEqual(false); done(); }) .catch(done.fail); @@ -116,6 +119,20 @@ describe('Actions Notes Store', () => { }); }); + describe('toggleStateButtonLoading', () => { + it('should set loading as true', (done) => { + testAction(actions.toggleStateButtonLoading, true, {}, [ + { type: 'TOGGLE_STATE_BUTTON_LOADING', payload: true }, + ], done); + }); + + it('should set loading as false', (done) => { + testAction(actions.toggleStateButtonLoading, false, {}, [ + { type: 'TOGGLE_STATE_BUTTON_LOADING', payload: false }, + ], done); + }); + }); + describe('toggleIssueLocalState', () => { it('sets issue state as closed', (done) => { testAction(actions.toggleIssueLocalState, 'closed', {}, [ @@ -129,4 +146,68 @@ describe('Actions Notes Store', () => { ], done); }); }); + + describe('poll', () => { + beforeEach((done) => { + jasmine.clock().install(); + + spyOn(Vue.http, 'get').and.callThrough(); + + store.dispatch('setNotesData', notesDataMock) + .then(done) + .catch(done.fail); + }); + + afterEach(() => { + jasmine.clock().uninstall(); + }); + + it('calls service with last fetched state', (done) => { + const interceptor = (request, next) => { + next(request.respondWith(JSON.stringify({ + notes: [], + last_fetched_at: '123456', + }), { + status: 200, + headers: { + 'poll-interval': '1000', + }, + })); + }; + + Vue.http.interceptors.push(interceptor); + Vue.http.interceptors.push(headersInterceptor); + + store.dispatch('poll') + .then(() => new Promise(resolve => requestAnimationFrame(resolve))) + .then(() => { + expect(Vue.http.get).toHaveBeenCalledWith(jasmine.anything(), { + url: jasmine.anything(), + method: 'get', + headers: { + 'X-Last-Fetched-At': undefined, + }, + }); + expect(store.state.lastFetchedAt).toBe('123456'); + + jasmine.clock().tick(1500); + }) + .then(() => new Promise((resolve) => { + requestAnimationFrame(resolve); + })) + .then(() => { + expect(Vue.http.get.calls.count()).toBe(2); + expect(Vue.http.get.calls.mostRecent().args[1].headers).toEqual({ + 'X-Last-Fetched-At': '123456', + }); + }) + .then(() => store.dispatch('stopPolling')) + .then(() => { + Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor); + Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor); + }) + .then(done) + .catch(done.fail); + }); + }); }); diff --git a/spec/javascripts/notes/stores/mutation_spec.js b/spec/javascripts/notes/stores/mutation_spec.js index e4baefc5bfc..98f101d6bc5 100644 --- a/spec/javascripts/notes/stores/mutation_spec.js +++ b/spec/javascripts/notes/stores/mutation_spec.js @@ -101,10 +101,21 @@ describe('Notes Store mutations', () => { const state = { notes: [], }; + const legacyNote = { + id: 2, + individual_note: true, + notes: [{ + note: '1', + }, { + note: '2', + }], + }; - mutations.SET_INITIAL_NOTES(state, [note]); + mutations.SET_INITIAL_NOTES(state, [note, legacyNote]); expect(state.notes[0].id).toEqual(note.id); - expect(state.notes.length).toEqual(1); + expect(state.notes[1].notes[0].note).toBe(legacyNote.notes[0].note); + expect(state.notes[2].notes[0].note).toBe(legacyNote.notes[1].note); + expect(state.notes.length).toEqual(3); }); }); @@ -217,4 +228,70 @@ describe('Notes Store mutations', () => { expect(state.notes[0].notes[0].note).toEqual('Foo'); }); }); + + describe('CLOSE_ISSUE', () => { + it('should set issue as closed', () => { + const state = { + notes: [], + targetNoteHash: null, + lastFetchedAt: null, + isToggleStateButtonLoading: false, + notesData: {}, + userData: {}, + noteableData: {}, + }; + + mutations.CLOSE_ISSUE(state); + expect(state.noteableData.state).toEqual('closed'); + }); + }); + + describe('REOPEN_ISSUE', () => { + it('should set issue as closed', () => { + const state = { + notes: [], + targetNoteHash: null, + lastFetchedAt: null, + isToggleStateButtonLoading: false, + notesData: {}, + userData: {}, + noteableData: {}, + }; + + mutations.REOPEN_ISSUE(state); + expect(state.noteableData.state).toEqual('reopened'); + }); + }); + + describe('TOGGLE_STATE_BUTTON_LOADING', () => { + it('should set isToggleStateButtonLoading as true', () => { + const state = { + notes: [], + targetNoteHash: null, + lastFetchedAt: null, + isToggleStateButtonLoading: false, + notesData: {}, + userData: {}, + noteableData: {}, + }; + + mutations.TOGGLE_STATE_BUTTON_LOADING(state, true); + expect(state.isToggleStateButtonLoading).toEqual(true); + }); + + it('should set isToggleStateButtonLoading as false', () => { + const state = { + notes: [], + targetNoteHash: null, + lastFetchedAt: null, + isToggleStateButtonLoading: true, + notesData: {}, + userData: {}, + noteableData: {}, + }; + + mutations.TOGGLE_STATE_BUTTON_LOADING(state, false); + expect(state.isToggleStateButtonLoading).toEqual(false); + }); + }); }); diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index d4a148e6ab1..ba0a70bed17 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -1,4 +1,5 @@ /* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */ +import $ from 'jquery'; import _ from 'underscore'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; diff --git a/spec/javascripts/oauth_remember_me_spec.js b/spec/javascripts/oauth_remember_me_spec.js index b24563f738b..8816fe6defb 100644 --- a/spec/javascripts/oauth_remember_me_spec.js +++ b/spec/javascripts/oauth_remember_me_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import OAuthRememberMe from '~/pages/sessions/new/oauth_remember_me'; describe('OAuthRememberMe', () => { diff --git a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js b/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js index 349549b9e1f..b0dc6ccc3d4 100644 --- a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js +++ b/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import '~/lib/utils/text_utility'; import AbuseReports from '~/pages/admin/abuse_reports/abuse_reports'; diff --git a/spec/javascripts/project_select_combo_button_spec.js b/spec/javascripts/project_select_combo_button_spec.js index dda83645c92..1b65f767f96 100644 --- a/spec/javascripts/project_select_combo_button_spec.js +++ b/spec/javascripts/project_select_combo_button_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import ProjectSelectComboButton from '~/project_select_combo_button'; const fixturePath = 'static/project_select_combo_button.html.raw'; diff --git a/spec/javascripts/projects/project_new_spec.js b/spec/javascripts/projects/project_new_spec.js index 8731ce35d81..84515d2bf97 100644 --- a/spec/javascripts/projects/project_new_spec.js +++ b/spec/javascripts/projects/project_new_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import projectNew from '~/projects/project_new'; describe('New Project', () => { diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index 35bb630bf5d..80770a61011 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, max-len */ +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import '~/commons/bootstrap'; import axios from '~/lib/utils/axios_utils'; diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 206f95abc1a..40115792652 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, max-len, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign, comma-dangle, object-shorthand, prefer-template, quotes, new-parens, vars-on-top, new-cap, max-len */ +import $ from 'jquery'; import '~/gl_dropdown'; import SearchAutocomplete from '~/search_autocomplete'; import '~/lib/utils/common_utils'; diff --git a/spec/javascripts/search_spec.js b/spec/javascripts/search_spec.js index 38e94d45e55..522851c584b 100644 --- a/spec/javascripts/search_spec.js +++ b/spec/javascripts/search_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Api from '~/api'; import Search from '~/pages/search/show/search'; diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js index 5d6a885d4cc..faaf710cf6f 100644 --- a/spec/javascripts/shortcuts_issuable_spec.js +++ b/spec/javascripts/shortcuts_issuable_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import initCopyAsGFM from '~/behaviors/copy_as_gfm'; import ShortcutsIssuable from '~/shortcuts_issuable'; diff --git a/spec/javascripts/shortcuts_spec.js b/spec/javascripts/shortcuts_spec.js index a2a609edef9..ee92295ef5e 100644 --- a/spec/javascripts/shortcuts_spec.js +++ b/spec/javascripts/shortcuts_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Shortcuts from '~/shortcuts'; describe('Shortcuts', () => { diff --git a/spec/javascripts/sidebar/sidebar_move_issue_spec.js b/spec/javascripts/sidebar/sidebar_move_issue_spec.js index 0da5d91e376..d8e636cbdf0 100644 --- a/spec/javascripts/sidebar/sidebar_move_issue_spec.js +++ b/spec/javascripts/sidebar/sidebar_move_issue_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import Vue from 'vue'; import SidebarMediator from '~/sidebar/sidebar_mediator'; diff --git a/spec/javascripts/smart_interval_spec.js b/spec/javascripts/smart_interval_spec.js index 7265e1b6cb5..a54219d58c2 100644 --- a/spec/javascripts/smart_interval_spec.js +++ b/spec/javascripts/smart_interval_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import SmartInterval from '~/smart_interval'; diff --git a/spec/javascripts/syntax_highlight_spec.js b/spec/javascripts/syntax_highlight_spec.js index 763a15e710b..0d1fa680e00 100644 --- a/spec/javascripts/syntax_highlight_spec.js +++ b/spec/javascripts/syntax_highlight_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, quotes */ +import $ from 'jquery'; import syntaxHighlight from '~/syntax_highlight'; describe('Syntax Highlighter', function() { diff --git a/spec/javascripts/todos_spec.js b/spec/javascripts/todos_spec.js index 35871dddf89..898bbb3819b 100644 --- a/spec/javascripts/todos_spec.js +++ b/spec/javascripts/todos_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import * as urlUtils from '~/lib/utils/url_utility'; import Todos from '~/pages/dashboard/todos/index/todos'; import '~/lib/utils/common_utils'; diff --git a/spec/javascripts/toggle_buttons_spec.js b/spec/javascripts/toggle_buttons_spec.js index 205e396d682..17d0b94ebe0 100644 --- a/spec/javascripts/toggle_buttons_spec.js +++ b/spec/javascripts/toggle_buttons_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import setupToggleButtons from '~/toggle_buttons'; import getSetTimeoutPromise from './helpers/set_timeout_promise_helper'; diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index 4d15bcc4956..39c47a5c06d 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import U2FAuthenticate from '~/u2f/authenticate'; import 'vendor/u2f'; import MockU2FDevice from './mock_u2f_device'; diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js index dbe89c2923c..136b4cad737 100644 --- a/spec/javascripts/u2f/register_spec.js +++ b/spec/javascripts/u2f/register_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import U2FRegister from '~/u2f/register'; import 'vendor/u2f'; import MockU2FDevice from './mock_u2f_device'; diff --git a/spec/javascripts/version_check_image_spec.js b/spec/javascripts/version_check_image_spec.js index 9637bd0414a..5f963e8c11e 100644 --- a/spec/javascripts/version_check_image_spec.js +++ b/spec/javascripts/version_check_image_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import VersionCheckImage from '~/version_check_image'; import ClassSpecHelper from './helpers/class_spec_helper'; diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js index dd907ad9015..d47815a5b5a 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js @@ -1,5 +1,6 @@ import Vue from 'vue'; import mwpsComponent from '~/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue'; +import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service'; import eventHub from '~/vue_merge_request_widget/event_hub'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; @@ -25,12 +26,7 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => { targetBranchPath, targetBranch, }, - service: { - cancelAutomaticMerge() {}, - mergeResource: { - save() {}, - }, - }, + service: new MRWidgetService({}), }); }); @@ -90,18 +86,16 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => { describe('removeSourceBranch', () => { it('should set flag and call service then request main component to update the widget', (done) => { - spyOn(vm.service.mergeResource, 'save').and.returnValue(new Promise((resolve) => { - resolve({ - data: { - status: 'merge_when_pipeline_succeeds', - }, - }); + spyOn(vm.service, 'merge').and.returnValue(Promise.resolve({ + data: { + status: 'merge_when_pipeline_succeeds', + }, })); vm.removeSourceBranch(); setTimeout(() => { expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested'); - expect(vm.service.mergeResource.save).toHaveBeenCalledWith({ + expect(vm.service.merge).toHaveBeenCalledWith({ sha, merge_when_pipeline_succeeds: true, should_remove_source_branch: true, diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js index a8a02fa6b66..2a762c9336e 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js @@ -1,9 +1,9 @@ import Vue from 'vue'; -import nothingToMergeComponent from '~/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge'; +import NothingToMerge from '~/vue_merge_request_widget/components/states/nothing_to_merge.vue'; -describe('MRWidgetNothingToMerge', () => { +describe('NothingToMerge', () => { describe('template', () => { - const Component = Vue.extend(nothingToMergeComponent); + const Component = Vue.extend(NothingToMerge); const newBlobPath = '/foo'; const vm = new Component({ el: document.createElement('div'), diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js index 3e310980ffa..32876ca66ac 100644 --- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js +++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js @@ -82,6 +82,10 @@ describe('mrWidgetOptions', () => { }); describe('shouldRenderSourceBranchRemovalStatus', () => { + beforeEach(() => { + vm.mr.state = 'readyToMerge'; + }); + it('should return true when cannot remove source branch and branch will be removed', () => { vm.mr.canRemoveSourceBranch = false; vm.mr.shouldRemoveSourceBranch = true; @@ -102,6 +106,22 @@ describe('mrWidgetOptions', () => { expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false); }); + + it('should return false when in merged state', () => { + vm.mr.canRemoveSourceBranch = false; + vm.mr.shouldRemoveSourceBranch = true; + vm.mr.state = 'merged'; + + expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false); + }); + + it('should return false when in nothing to merge state', () => { + vm.mr.canRemoveSourceBranch = false; + vm.mr.shouldRemoveSourceBranch = true; + vm.mr.state = 'nothingToMerge'; + + expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false); + }); }); describe('shouldRenderDeployments', () => { @@ -407,6 +427,7 @@ describe('mrWidgetOptions', () => { it('renders when user cannot remove branch and branch should be removed', (done) => { vm.mr.canRemoveSourceBranch = false; vm.mr.shouldRemoveSourceBranch = true; + vm.mr.state = 'readyToMerge'; vm.$nextTick(() => { const tooltip = vm.$el.querySelector('.fa-question-circle'); @@ -419,5 +440,18 @@ describe('mrWidgetOptions', () => { done(); }); }); + + it('does not render in merged state', (done) => { + vm.mr.canRemoveSourceBranch = false; + vm.mr.shouldRemoveSourceBranch = true; + vm.mr.state = 'merged'; + + vm.$nextTick(() => { + expect(vm.$el.textContent).toContain('The source branch has been removed'); + expect(vm.$el.textContent).not.toContain('Removes source branch'); + + done(); + }); + }); }); }); diff --git a/spec/javascripts/vue_shared/components/gl_modal_spec.js b/spec/javascripts/vue_shared/components/gl_modal_spec.js index 2805d9a7003..85cb1b90fc6 100644 --- a/spec/javascripts/vue_shared/components/gl_modal_spec.js +++ b/spec/javascripts/vue_shared/components/gl_modal_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import GlModal from '~/vue_shared/components/gl_modal.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; diff --git a/spec/javascripts/vue_shared/components/markdown/field_spec.js b/spec/javascripts/vue_shared/components/markdown/field_spec.js index 5f980bbf36c..69034975422 100644 --- a/spec/javascripts/vue_shared/components/markdown/field_spec.js +++ b/spec/javascripts/vue_shared/components/markdown/field_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import fieldComponent from '~/vue_shared/components/markdown/field.vue'; diff --git a/spec/javascripts/vue_shared/components/modal_spec.js b/spec/javascripts/vue_shared/components/modal_spec.js index 8412df74f98..d01a94c25e5 100644 --- a/spec/javascripts/vue_shared/components/modal_spec.js +++ b/spec/javascripts/vue_shared/components/modal_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import modal from '~/vue_shared/components/modal.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js index 67056793a20..8daaf018396 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js @@ -37,6 +37,32 @@ describe('BaseComponent', () => { vmNonEditable.$destroy(); }); }); + + describe('createLabelTitle', () => { + it('returns `Create project label` when `isProject` prop is true', () => { + expect(vm.createLabelTitle).toBe('Create project label'); + }); + + it('return `Create group label` when `isProject` prop is false', () => { + const mockConfigGroup = Object.assign({}, mockConfig, { isProject: false }); + const vmGroup = createComponent(mockConfigGroup); + expect(vmGroup.createLabelTitle).toBe('Create group label'); + vmGroup.$destroy(); + }); + }); + + describe('manageLabelsTitle', () => { + it('returns `Manage project labels` when `isProject` prop is true', () => { + expect(vm.manageLabelsTitle).toBe('Manage project labels'); + }); + + it('return `Manage group labels` when `isProject` prop is false', () => { + const mockConfigGroup = Object.assign({}, mockConfig, { isProject: false }); + const vmGroup = createComponent(mockConfigGroup); + expect(vmGroup.manageLabelsTitle).toBe('Manage group labels'); + vmGroup.$destroy(); + }); + }); }); describe('methods', () => { diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js index f07aefb2f87..5cb4bb6fea6 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js @@ -6,10 +6,12 @@ import { mockSuggestedColors } from './mock_data'; import mountComponent from '../../../../helpers/vue_mount_component_helper'; -const createComponent = () => { +const createComponent = (headerTitle) => { const Component = Vue.extend(dropdownCreateLabelComponent); - return mountComponent(Component); + return mountComponent(Component, { + headerTitle, + }); }; describe('DropdownCreateLabelComponent', () => { @@ -41,11 +43,19 @@ describe('DropdownCreateLabelComponent', () => { expect(backButtonEl.querySelector('.fa-arrow-left')).not.toBe(null); }); - it('renders component header element', () => { + it('renders component header element as `Create new label` when `headerTitle` prop is not provided', () => { const headerEl = vm.$el.querySelector('.dropdown-title'); expect(headerEl.innerText.trim()).toContain('Create new label'); }); + it('renders component header element with value of `headerTitle` prop', () => { + const headerTitle = 'Create project label'; + const vmWithHeaderTitle = createComponent(headerTitle); + const headerEl = vmWithHeaderTitle.$el.querySelector('.dropdown-title'); + expect(headerEl.innerText.trim()).toContain(headerTitle); + vmWithHeaderTitle.$destroy(); + }); + it('renders `Close` button on component header', () => { const closeButtonEl = vm.$el.querySelector('.dropdown-title button.dropdown-title-button.dropdown-menu-close'); expect(closeButtonEl).not.toBe(null); diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js index 809e0327b1c..0f4fa716f8a 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js @@ -6,15 +6,23 @@ import { mockConfig } from './mock_data'; import mountComponent from '../../../../helpers/vue_mount_component_helper'; -const createComponent = (labelsWebUrl = mockConfig.labelsWebUrl) => { +const createComponent = ( + labelsWebUrl = mockConfig.labelsWebUrl, + createLabelTitle, + manageLabelsTitle, +) => { const Component = Vue.extend(dropdownFooterComponent); return mountComponent(Component, { labelsWebUrl, + createLabelTitle, + manageLabelsTitle, }); }; describe('DropdownFooterComponent', () => { + const createLabelTitle = 'Create project label'; + const manageLabelsTitle = 'Manage project labels'; let vm; beforeEach(() => { @@ -26,17 +34,35 @@ describe('DropdownFooterComponent', () => { }); describe('template', () => { - it('renders `Create new label` link element', () => { + it('renders link element with `Create new label` when `createLabelTitle` prop is not provided', () => { const createLabelEl = vm.$el.querySelector('.dropdown-footer-list .dropdown-toggle-page'); expect(createLabelEl).not.toBeNull(); expect(createLabelEl.innerText.trim()).toBe('Create new label'); }); - it('renders `Manage labels` link element', () => { + it('renders link element with value of `createLabelTitle` prop', () => { + const vmWithCreateLabelTitle = createComponent(mockConfig.labelsWebUrl, createLabelTitle); + const createLabelEl = vmWithCreateLabelTitle.$el.querySelector('.dropdown-footer-list .dropdown-toggle-page'); + expect(createLabelEl.innerText.trim()).toBe(createLabelTitle); + vmWithCreateLabelTitle.$destroy(); + }); + + it('renders link element with `Manage labels` when `manageLabelsTitle` prop is not provided', () => { const manageLabelsEl = vm.$el.querySelector('.dropdown-footer-list .dropdown-external-link'); expect(manageLabelsEl).not.toBeNull(); expect(manageLabelsEl.getAttribute('href')).toBe(vm.labelsWebUrl); expect(manageLabelsEl.innerText.trim()).toBe('Manage labels'); }); + + it('renders link element with value of `manageLabelsTitle` prop', () => { + const vmWithManageLabelsTitle = createComponent( + mockConfig.labelsWebUrl, + createLabelTitle, + manageLabelsTitle, + ); + const manageLabelsEl = vmWithManageLabelsTitle.$el.querySelector('.dropdown-footer-list .dropdown-external-link'); + expect(manageLabelsEl.innerText.trim()).toBe(manageLabelsTitle); + vmWithManageLabelsTitle.$destroy(); + }); }); }); diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js index e9008c29b22..3fcb91b6f5e 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js @@ -34,6 +34,7 @@ export const mockSuggestedColors = [ export const mockConfig = { showCreate: true, + isProject: true, abilityName: 'issue', context: { labels: mockLabels, diff --git a/spec/javascripts/vue_shared/directives/tooltip_spec.js b/spec/javascripts/vue_shared/directives/tooltip_spec.js index b1b3071527b..4a644913e44 100644 --- a/spec/javascripts/vue_shared/directives/tooltip_spec.js +++ b/spec/javascripts/vue_shared/directives/tooltip_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import tooltip from '~/vue_shared/directives/tooltip'; diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js index 8edba1f47a3..7fe3bd92049 100644 --- a/spec/javascripts/zen_mode_spec.js +++ b/spec/javascripts/zen_mode_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Mousetrap from 'mousetrap'; import Dropzone from 'dropzone'; import ZenMode from '~/zen_mode'; diff --git a/spec/lib/api/helpers/related_resources_helpers_spec.rb b/spec/lib/api/helpers/related_resources_helpers_spec.rb new file mode 100644 index 00000000000..b918301f1cb --- /dev/null +++ b/spec/lib/api/helpers/related_resources_helpers_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe API::Helpers::RelatedResourcesHelpers do + subject(:helpers) do + Class.new.include(described_class).new + end + + describe '#expose_url' do + let(:path) { '/api/v4/awesome_endpoint' } + subject(:url) { helpers.expose_url(path) } + + def stub_default_url_options(protocol: 'http', host: 'example.com', port: nil) + expect(Gitlab::Application.routes).to receive(:default_url_options) + .and_return(protocol: protocol, host: host, port: port) + end + + it 'respects the protocol if it is HTTP' do + stub_default_url_options(protocol: 'http') + + is_expected.to start_with('http://') + end + + it 'respects the protocol if it is HTTPS' do + stub_default_url_options(protocol: 'https') + + is_expected.to start_with('https://') + end + + it 'accepts port to be nil' do + stub_default_url_options(port: nil) + + is_expected.to start_with('http://example.com/') + end + + it 'includes port if provided' do + stub_default_url_options(port: 8080) + + is_expected.to start_with('http://example.com:8080/') + end + end +end diff --git a/spec/lib/gitlab/git/gitlab_projects_spec.rb b/spec/lib/gitlab/git/gitlab_projects_spec.rb index 45bcd730332..dfccc15a4f3 100644 --- a/spec/lib/gitlab/git/gitlab_projects_spec.rb +++ b/spec/lib/gitlab/git/gitlab_projects_spec.rb @@ -28,7 +28,7 @@ describe Gitlab::Git::GitlabProjects do describe '#push_branches' do let(:remote_name) { 'remote-name' } let(:branch_name) { 'master' } - let(:cmd) { %W(git push -- #{remote_name} #{branch_name}) } + let(:cmd) { %W(#{Gitlab.config.git.bin_path} push -- #{remote_name} #{branch_name}) } let(:force) { false } subject { gl_projects.push_branches(remote_name, 600, force, [branch_name]) } @@ -46,7 +46,7 @@ describe Gitlab::Git::GitlabProjects do end context 'with --force' do - let(:cmd) { %W(git push --force -- #{remote_name} #{branch_name}) } + let(:cmd) { %W(#{Gitlab.config.git.bin_path} push --force -- #{remote_name} #{branch_name}) } let(:force) { true } it 'executes the command' do @@ -65,7 +65,7 @@ describe Gitlab::Git::GitlabProjects do let(:tags) { true } let(:args) { { force: force, tags: tags, prune: prune }.merge(extra_args) } let(:extra_args) { {} } - let(:cmd) { %W(git fetch #{remote_name} --quiet --prune --tags) } + let(:cmd) { %W(#{Gitlab.config.git.bin_path} fetch #{remote_name} --quiet --prune --tags) } subject { gl_projects.fetch_remote(remote_name, 600, args) } @@ -98,7 +98,7 @@ describe Gitlab::Git::GitlabProjects do context 'with --force' do let(:force) { true } - let(:cmd) { %W(git fetch #{remote_name} --quiet --prune --force --tags) } + let(:cmd) { %W(#{Gitlab.config.git.bin_path} fetch #{remote_name} --quiet --prune --force --tags) } it 'executes the command with forced option' do stub_spawn(cmd, 600, tmp_repo_path, {}, success: true) @@ -109,7 +109,7 @@ describe Gitlab::Git::GitlabProjects do context 'with --no-tags' do let(:tags) { false } - let(:cmd) { %W(git fetch #{remote_name} --quiet --prune --no-tags) } + let(:cmd) { %W(#{Gitlab.config.git.bin_path} fetch #{remote_name} --quiet --prune --no-tags) } it 'executes the command' do stub_spawn(cmd, 600, tmp_repo_path, {}, success: true) @@ -120,7 +120,7 @@ describe Gitlab::Git::GitlabProjects do context 'with no prune' do let(:prune) { false } - let(:cmd) { %W(git fetch #{remote_name} --quiet --tags) } + let(:cmd) { %W(#{Gitlab.config.git.bin_path} fetch #{remote_name} --quiet --tags) } it 'executes the command' do stub_spawn(cmd, 600, tmp_repo_path, {}, success: true) @@ -165,7 +165,7 @@ describe Gitlab::Git::GitlabProjects do describe '#import_project' do let(:project) { create(:project) } let(:import_url) { TestEnv.factory_repo_path_bare } - let(:cmd) { %W(git clone --bare -- #{import_url} #{tmp_repo_path}) } + let(:cmd) { %W(#{Gitlab.config.git.bin_path} clone --bare -- #{import_url} #{tmp_repo_path}) } let(:timeout) { 600 } subject { gl_projects.import_project(import_url, timeout) } diff --git a/spec/lib/gitlab/profiler_spec.rb b/spec/lib/gitlab/profiler_spec.rb index f02b1cf55fb..3d5b56cd5b8 100644 --- a/spec/lib/gitlab/profiler_spec.rb +++ b/spec/lib/gitlab/profiler_spec.rb @@ -94,10 +94,12 @@ describe Gitlab::Profiler do it 'strips out the private token' do expect(custom_logger).to receive(:add) do |severity, _progname, message| + next if message.include?('spec/') + expect(severity).to eq(Logger::DEBUG) expect(message).to include('public').and include(described_class::FILTERED_STRING) expect(message).not_to include(private_token) - end + end.twice custom_logger.debug("public #{private_token}") end diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index c46bb8edebf..57905a74e92 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -108,14 +108,26 @@ describe Gitlab::ProjectSearchResults do context 'when the search returns non-ASCII data' do context 'with UTF-8' do - let(:results) { project.repository.search_files_by_content("файл", 'master') } + let(:results) { project.repository.search_files_by_content('файл', 'master') } it 'returns results as UTF-8' do expect(subject.filename).to eq('encoding/russian.rb') expect(subject.basename).to eq('encoding/russian') expect(subject.ref).to eq('master') expect(subject.startline).to eq(1) - expect(subject.data).to eq("Хороший файл") + expect(subject.data).to eq('Хороший файл') + end + end + + context 'with UTF-8 in the filename' do + let(:results) { project.repository.search_files_by_content('webhook', 'master') } + + it 'returns results as UTF-8' do + expect(subject.filename).to eq('encoding/テスト.txt') + expect(subject.basename).to eq('encoding/テスト') + expect(subject.ref).to eq('master') + expect(subject.startline).to eq(3) + expect(subject.data).to include('WebHookの確認') end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index c27313ed88b..6e202de0db9 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1424,6 +1424,17 @@ describe Ci::Build do { key: 'CI_COMMIT_SHA', value: build.sha, public: true }, { key: 'CI_COMMIT_REF_NAME', value: build.ref, public: true }, { key: 'CI_COMMIT_REF_SLUG', value: build.ref_slug, public: true }, + { key: 'CI_REGISTRY_USER', value: 'gitlab-ci-token', public: true }, + { key: 'CI_REGISTRY_PASSWORD', value: build.token, public: false }, + { key: 'CI_REPOSITORY_URL', value: build.repo_url, public: false }, + { key: 'CI_BUILD_ID', value: build.id.to_s, public: true }, + { key: 'CI_BUILD_TOKEN', value: build.token, public: false }, + { key: 'CI_BUILD_REF', value: build.sha, public: true }, + { key: 'CI_BUILD_BEFORE_SHA', value: build.before_sha, public: true }, + { key: 'CI_BUILD_REF_NAME', value: build.ref, public: true }, + { key: 'CI_BUILD_REF_SLUG', value: build.ref_slug, public: true }, + { key: 'CI_BUILD_NAME', value: 'test', public: true }, + { key: 'CI_BUILD_STAGE', value: 'test', public: true }, { key: 'CI_PROJECT_ID', value: project.id.to_s, public: true }, { key: 'CI_PROJECT_NAME', value: project.path, public: true }, { key: 'CI_PROJECT_PATH', value: project.full_path, public: true }, @@ -1433,9 +1444,7 @@ describe Ci::Build do { key: 'CI_PROJECT_VISIBILITY', value: 'private', public: true }, { key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true }, { key: 'CI_CONFIG_PATH', value: pipeline.ci_yaml_file_path, public: true }, - { key: 'CI_REGISTRY_USER', value: 'gitlab-ci-token', public: true }, - { key: 'CI_REGISTRY_PASSWORD', value: build.token, public: false }, - { key: 'CI_REPOSITORY_URL', value: build.repo_url, public: false } + { key: 'CI_PIPELINE_SOURCE', value: pipeline.source, public: true } ] end @@ -1834,39 +1843,6 @@ describe Ci::Build do it { is_expected.to include(ci_config_path) } end - context 'returns variables in valid order' do - let(:build_pre_var) { { key: 'build', value: 'value' } } - let(:project_pre_var) { { key: 'project', value: 'value' } } - let(:pipeline_pre_var) { { key: 'pipeline', value: 'value' } } - let(:build_yaml_var) { { key: 'yaml', value: 'value' } } - - before do - allow(build).to receive(:predefined_variables) { [build_pre_var] } - allow(build).to receive(:yaml_variables) { [build_yaml_var] } - - allow_any_instance_of(Project) - .to receive(:predefined_variables) { [project_pre_var] } - - allow_any_instance_of(Project) - .to receive(:secret_variables_for) - .with(ref: 'master', environment: nil) do - [create(:ci_variable, key: 'secret', value: 'value')] - end - - allow_any_instance_of(Ci::Pipeline) - .to receive(:predefined_variables) { [pipeline_pre_var] } - end - - it do - is_expected.to eq( - [build_pre_var, - project_pre_var, - pipeline_pre_var, - build_yaml_var, - { key: 'secret', value: 'value', public: false }]) - end - end - context 'when using auto devops' do context 'and is enabled' do before do @@ -1890,6 +1866,81 @@ describe Ci::Build do end end end + + context 'when pipeline variable overrides build variable' do + before do + build.yaml_variables = [{ key: 'MYVAR', value: 'myvar', public: true }] + pipeline.variables.build(key: 'MYVAR', value: 'pipeline value') + end + + it 'overrides YAML variable using a pipeline variable' do + variables = subject.reverse.uniq { |variable| variable[:key] }.reverse + + expect(variables) + .not_to include(key: 'MYVAR', value: 'myvar', public: true) + expect(variables) + .to include(key: 'MYVAR', value: 'pipeline value', public: false) + end + end + + describe 'variables ordering' do + context 'when variables hierarchy is stubbed' do + let(:build_pre_var) { { key: 'build', value: 'value' } } + let(:project_pre_var) { { key: 'project', value: 'value' } } + let(:pipeline_pre_var) { { key: 'pipeline', value: 'value' } } + let(:build_yaml_var) { { key: 'yaml', value: 'value' } } + + before do + allow(build).to receive(:predefined_variables) { [build_pre_var] } + allow(build).to receive(:yaml_variables) { [build_yaml_var] } + + allow_any_instance_of(Project) + .to receive(:predefined_variables) { [project_pre_var] } + + allow_any_instance_of(Project) + .to receive(:secret_variables_for) + .with(ref: 'master', environment: nil) do + [create(:ci_variable, key: 'secret', value: 'value')] + end + + allow_any_instance_of(Ci::Pipeline) + .to receive(:predefined_variables) { [pipeline_pre_var] } + end + + it 'returns variables in order depending on resource hierarchy' do + is_expected.to eq( + [build_pre_var, + project_pre_var, + pipeline_pre_var, + build_yaml_var, + { key: 'secret', value: 'value', public: false }]) + end + end + + context 'when build has environment and user-provided variables' do + let(:expected_variables) do + predefined_variables.map { |variable| variable.fetch(:key) } + + %w[YAML_VARIABLE CI_ENVIRONMENT_NAME CI_ENVIRONMENT_SLUG + CI_ENVIRONMENT_URL] + end + + before do + create(:environment, project: build.project, + name: 'staging') + + build.yaml_variables = [{ key: 'YAML_VARIABLE', + value: 'var', + public: true }] + build.environment = 'staging' + end + + it 'matches explicit variables ordering' do + received_variables = subject.map { |variable| variable.fetch(:key) } + + expect(received_variables).to eq expected_variables + end + end + end end describe 'state transition: any => [:pending]' do diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 14d234f6aab..86bb2fefae1 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -172,10 +172,10 @@ describe Ci::Pipeline, :mailer do it { is_expected.to be_an(Array) } - it 'includes the defined keys' do - keys = subject.map { |v| v[:key] } + it 'includes all predefined variables in a valid order' do + keys = subject.map { |variable| variable.fetch(:key) } - expect(keys).to include('CI_PIPELINE_ID', 'CI_CONFIG_PATH', 'CI_PIPELINE_SOURCE') + expect(keys).to eq %w[CI_PIPELINE_ID CI_CONFIG_PATH CI_PIPELINE_SOURCE] end end diff --git a/spec/models/compare_spec.rb b/spec/models/compare_spec.rb index 04f3cecae00..8e88bb81162 100644 --- a/spec/models/compare_spec.rb +++ b/spec/models/compare_spec.rb @@ -37,33 +37,51 @@ describe Compare do end end - describe '#base_commit' do - let(:base_commit) { Commit.new(another_sample_commit, project) } + describe '#base_commit_sha' do + it 'returns @base_sha if it is present' do + expect(project).not_to receive(:merge_base_commit) - it 'returns project merge base commit' do - expect(project).to receive(:merge_base_commit).with(start_commit.id, head_commit.id).and_return(base_commit) + sha = double + service = described_class.new(raw_compare, project, base_sha: sha) - expect(subject.base_commit).to eq(base_commit) + expect(service.base_commit_sha).to eq(sha) + end + + it 'fetches merge base SHA from repo when @base_sha is nil' do + expect(project).to receive(:merge_base_commit) + .with(start_commit.id, head_commit.id) + .once + .and_call_original + + expect(subject.base_commit_sha) + .to eq(project.repository.merge_base(start_commit.id, head_commit.id)) + end + + it 'is memoized on first call' do + expect(project).to receive(:merge_base_commit) + .with(start_commit.id, head_commit.id) + .once + .and_call_original + + 3.times { subject.base_commit_sha } end it 'returns nil if there is no start_commit' do expect(subject).to receive(:start_commit).and_return(nil) - expect(subject.base_commit).to eq(nil) + expect(subject.base_commit_sha).to eq(nil) end it 'returns nil if there is no head commit' do expect(subject).to receive(:head_commit).and_return(nil) - expect(subject.base_commit).to eq(nil) + expect(subject.base_commit_sha).to eq(nil) end end describe '#diff_refs' do - it 'uses base_commit sha as base_sha' do - expect(subject).to receive(:base_commit).at_least(:once).and_call_original - - expect(subject.diff_refs.base_sha).to eq(subject.base_commit.id) + it 'uses base_commit_sha sha as base_sha' do + expect(subject.diff_refs.base_sha).to eq(subject.base_commit_sha) end it 'uses start_commit sha as start_sha' do diff --git a/vendor/assets/javascripts/peek.js b/vendor/assets/javascripts/peek.js index 695eeb27c17..7c6d226fa6a 100644 --- a/vendor/assets/javascripts/peek.js +++ b/vendor/assets/javascripts/peek.js @@ -1,14 +1,14 @@ /* - * This is a modified version of https://github.com/peek/peek/blob/master/app/assets/javascripts/peek.js + * this is a modified version of https://github.com/peek/peek/blob/master/app/assets/javascripts/peek.js * * - Removed the dependency on jquery.tipsy * - Removed the initializeTipsy and toggleBar functions - * - Customized updatePerformanceBar to handle SQL queries report specificities + * - Customized updatePerformanceBar to handle SQL query and Gitaly call lists * - Changed /peek/results to /-/peek/results * - Removed the keypress, pjax:end, page:change, and turbolinks:load handlers */ (function($) { - var fetchRequestResults, getRequestId, peekEnabled, updatePerformanceBar; + var fetchRequestResults, getRequestId, peekEnabled, updatePerformanceBar, createTable, createTableRow; getRequestId = function() { return $('#peek').data('requestId'); }; @@ -16,39 +16,55 @@ return $('#peek').length; }; updatePerformanceBar = function(results) { - var key, label, data, table, html, tr, duration_td, sql_td, strong; - Object.keys(results.data).forEach(function(key) { Object.keys(results.data[key]).forEach(function(label) { - data = results.data[key][label]; + var data = results.data[key][label]; + var table = createTable(key, label, data); + var target = $('[data-defer-to="' + key + '-' + label + '"]'); + + if (table) { + target.html(table); + } else { + target.text(data); + } + }); + }); + return $(document).trigger('peek:render', [getRequestId(), results]); + }; + createTable = function(key, label, data) { + if (label !== 'queries' && label !== 'details') { + return; + } - if (label == 'queries') { - table = document.createElement('table'); + var table = document.createElement('table'); - for (var i = 0; i < data.length; i += 1) { - tr = document.createElement('tr'); - duration_td = document.createElement('td'); - sql_td = document.createElement('td'); - strong = document.createElement('strong'); + for (var i = 0; i < data.length; i += 1) { + table.appendChild(createTableRow(data[i])); + } - strong.append(data[i]['duration'] + 'ms'); - duration_td.appendChild(strong); - tr.appendChild(duration_td); + table.className = 'table'; - sql_td.appendChild(document.createTextNode(data[i]['sql'])); - tr.appendChild(sql_td); + return table; + }; + createTableRow = function(row) { + var tr = document.createElement('tr'); + var durationTd = document.createElement('td'); + var strong = document.createElement('strong'); - table.appendChild(tr); - } + strong.append(row['duration'] + 'ms'); + durationTd.appendChild(strong); + tr.appendChild(durationTd); - table.className = 'table'; - $("[data-defer-to=" + key + "-" + label + "]").html(table); - } else { - $("[data-defer-to=" + key + "-" + label + "]").text(results.data[key][label]); - } - }); + ['sql', 'feature', 'enabled', 'request'].forEach(function(key) { + if (!row[key]) { return; } + + var td = document.createElement('td'); + + td.appendChild(document.createTextNode(row[key])); + tr.appendChild(td); }); - return $(document).trigger('peek:render', [getRequestId(), results]); + + return tr; }; fetchRequestResults = function() { return $.ajax('/-/peek/results', { diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index c233e255fe0..33f9efc1490 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -137,7 +137,7 @@ sast:container: dast: stage: dast allow_failure: true - image: owasp/zap2docker-stable + image: registry.gitlab.com/gitlab-org/security-products/zaproxy variables: POSTGRES_DB: "false" script: diff --git a/yarn.lock b/yarn.lock index a2eee3a547d..adbb37bea72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -54,9 +54,9 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" -"@gitlab-org/gitlab-svgs@^1.13.0": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.13.0.tgz#9e856ef9fa7bbe49b2dce9789187a89e11311215" +"@gitlab-org/gitlab-svgs@^1.14.0": + version "1.14.0" + resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.14.0.tgz#b4a5cca3106f33224c5486cf674ba3b70cee727e" "@types/jquery@^2.0.40": version "2.0.48" |