diff options
Diffstat (limited to 'app')
15 files changed, 165 insertions, 257 deletions
diff --git a/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignee.vue b/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignee.vue index df07038151e..c39a72a45b9 100644 --- a/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignee.vue +++ b/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignee.vue @@ -27,25 +27,12 @@ export default { <gl-dropdown-item :key="user.username" data-testid="assigneeDropdownItem" - class="assignee-dropdown-item gl-vertical-align-middle" :active="active" active-class="is-active" + :avatar-url="user.avatar_url" + :secondary-text="`@${user.username}`" @click="$emit('update-alert-assignees', user.username)" > - <span class="gl-relative mr-2"> - <img - :alt="user.username" - :src="user.avatar_url" - :width="32" - class="avatar avatar-inline gl-m-0 s32" - data-qa-selector="avatar_image" - /> - </span> - <span class="d-flex gl-flex-direction-column gl-overflow-hidden"> - <strong class="dropdown-menu-user-full-name"> - {{ user.name }} - </strong> - <span class="dropdown-menu-user-username"> {{ user.username }}</span> - </span> + {{ user.name }} </gl-dropdown-item> </template> diff --git a/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignees.vue b/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignees.vue index 5e4fd56738b..3af68d42ddf 100644 --- a/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignees.vue +++ b/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignees.vue @@ -13,7 +13,7 @@ import { } from '@gitlab/ui'; import { debounce } from 'lodash'; import axios from '~/lib/utils/axios_utils'; -import { s__ } from '~/locale'; +import { s__, __ } from '~/locale'; import alertSetAssignees from '../../graphql/mutations/alert_set_assignees.mutation.graphql'; import SidebarAssignee from './sidebar_assignee.vue'; @@ -96,7 +96,10 @@ export default { .sort((a, b) => (a.active === b.active ? 0 : a.active ? -1 : 1)); // eslint-disable-line no-nested-ternary }, dropdownClass() { - return this.isDropdownShowing ? 'show' : 'gl-display-none'; + return this.isDropdownShowing ? 'dropdown-menu-selectable show' : 'gl-display-none'; + }, + dropDownTitle() { + return this.userName ?? __('Select assignee'); }, userListValid() { return !this.isDropdownSearching && this.users.length > 0; @@ -217,81 +220,80 @@ export default { </a> </p> - <div class="dropdown dropdown-menu-selectable" :class="dropdownClass"> - <gl-dropdown - ref="dropdown" - :text="userName" - class="w-100" - toggle-class="dropdown-menu-toggle" - @keydown.esc.native="hideDropdown" - @hide="hideDropdown" - > - <p class="gl-new-dropdown-header-top"> - {{ __('Assign To') }} - </p> - <gl-search-box-by-type v-model.trim="search" :placeholder="__('Search users')" /> - <div class="dropdown-content dropdown-body"> - <template v-if="userListValid"> - <gl-dropdown-item - :active="!userName" - active-class="is-active" - @click="updateAlertAssignees('')" - > - {{ __('Unassigned') }} - </gl-dropdown-item> - <gl-dropdown-divider /> - - <gl-dropdown-section-header> - {{ __('Assignee') }} - </gl-dropdown-section-header> - <sidebar-assignee - v-for="user in sortedUsers" - :key="user.username" - :user="user" - :active="user.active" - @update-alert-assignees="updateAlertAssignees" - /> - </template> - <p v-else-if="userListEmpty" class="mx-3 my-2"> - {{ __('No Matching Results') }} - </p> - <gl-loading-icon v-else /> - </div> - </gl-dropdown> - </div> + <gl-dropdown + ref="dropdown" + :text="dropDownTitle" + class="gl-w-full" + :class="dropdownClass" + toggle-class="dropdown-menu-toggle" + @keydown.esc.native="hideDropdown" + @hide="hideDropdown" + > + <p class="gl-new-dropdown-header-top"> + {{ __('Assign To') }} + </p> + <gl-search-box-by-type v-model.trim="search" :placeholder="__('Search users')" /> + <div class="dropdown-content dropdown-body"> + <template v-if="userListValid"> + <gl-dropdown-item + :active="!userName" + active-class="is-active" + @click="updateAlertAssignees('')" + > + {{ __('Unassigned') }} + </gl-dropdown-item> + <gl-dropdown-divider /> - <gl-loading-icon v-if="isUpdating" :inline="true" /> - <div v-else-if="!isDropdownShowing" class="value gl-m-0" :class="{ 'no-value': !userName }"> - <div v-if="userName" class="gl-display-inline-flex gl-mt-2" data-testid="assigned-users"> - <span class="gl-relative mr-2"> - <img - :alt="userName" - :src="userImg" - :width="32" - class="avatar avatar-inline gl-m-0 s32" - data-qa-selector="avatar_image" + <gl-dropdown-section-header> + {{ __('Assignee') }} + </gl-dropdown-section-header> + <sidebar-assignee + v-for="user in sortedUsers" + :key="user.username" + :user="user" + :active="user.active" + @update-alert-assignees="updateAlertAssignees" /> - </span> - <span class="gl-display-flex gl-flex-direction-column gl-overflow-hidden"> - <strong class="dropdown-menu-user-full-name"> - {{ userFullName }} - </strong> - <span class="dropdown-menu-user-username">{{ userName }}</span> - </span> + </template> + <p v-else-if="userListEmpty" class="gl-mx-5 gl-my-4"> + {{ __('No Matching Results') }} + </p> + <gl-loading-icon v-else /> </div> - <span v-else class="gl-display-flex gl-align-items-center gl-line-height-normal"> - {{ __('None') }} - - <gl-button - class="gl-ml-2" - href="#" - variant="link" - data-testid="unassigned-users" - @click="updateAlertAssignees(currentUser)" - > - {{ __('assign yourself') }} - </gl-button> + </gl-dropdown> + </div> + + <gl-loading-icon v-if="isUpdating" :inline="true" /> + <div v-else-if="!isDropdownShowing" class="value gl-m-0" :class="{ 'no-value': !userName }"> + <div v-if="userName" class="gl-display-inline-flex gl-mt-2" data-testid="assigned-users"> + <span class="gl-relative gl-mr-4"> + <img + :alt="userName" + :src="userImg" + :width="32" + class="avatar avatar-inline gl-m-0 s32" + data-qa-selector="avatar_image" + /> + </span> + <span class="gl-display-flex gl-flex-direction-column gl-overflow-hidden"> + <strong class="dropdown-menu-user-full-name"> + {{ userFullName }} + </strong> + <span class="dropdown-menu-user-username">@{{ userName }}</span> </span> </div> + <span v-else class="gl-display-flex gl-align-items-center gl-line-height-normal"> + {{ __('None') }} - + <gl-button + class="gl-ml-2" + href="#" + variant="link" + data-testid="unassigned-users" + @click="updateAlertAssignees(currentUser)" + > + {{ __('assign yourself') }} + </gl-button> + </span> </div> </div> </template> diff --git a/app/assets/javascripts/issue_show/components/header_actions.vue b/app/assets/javascripts/issue_show/components/header_actions.vue index 4c8c86390f4..a7b05c93c61 100644 --- a/app/assets/javascripts/issue_show/components/header_actions.vue +++ b/app/assets/javascripts/issue_show/components/header_actions.vue @@ -1,12 +1,13 @@ <script> import { GlButton, GlDropdown, GlDropdownItem, GlIcon, GlLink, GlModal } from '@gitlab/ui'; -import { mapGetters } from 'vuex'; +import { mapActions, mapGetters, mapState } from 'vuex'; import createFlash, { FLASH_TYPES } from '~/flash'; import { IssuableType } from '~/issuable_show/constants'; import { IssuableStatus, IssueStateEvent } from '~/issue_show/constants'; import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; import { visitUrl } from '~/lib/utils/url_utility'; import { __, sprintf } from '~/locale'; +import eventHub from '~/notes/event_hub'; import promoteToEpicMutation from '../queries/promote_to_epic.mutation.graphql'; import updateIssueMutation from '../queries/update_issue.mutation.graphql'; @@ -72,15 +73,11 @@ export default { default: '', }, }, - data() { - return { - isUpdatingState: false, - }; - }, computed: { - ...mapGetters(['getNoteableData']), + ...mapState(['isToggleStateButtonLoading']), + ...mapGetters(['openState', 'getBlockedByIssues']), isClosed() { - return this.getNoteableData.state === IssuableStatus.Closed; + return this.openState === IssuableStatus.Closed; }, buttonText() { return this.isClosed @@ -107,9 +104,16 @@ export default { return canClose || canReopen; }, }, + created() { + eventHub.$on('toggle.issuable.state', this.toggleIssueState); + }, + beforeDestroy() { + eventHub.$off('toggle.issuable.state', this.toggleIssueState); + }, methods: { + ...mapActions(['toggleStateButtonLoading']), toggleIssueState() { - if (!this.isClosed && this.getNoteableData?.blocked_by_issues?.length) { + if (!this.isClosed && this.getBlockedByIssues.length) { this.$refs.blockedByIssuesModal.show(); return; } @@ -117,7 +121,7 @@ export default { this.invokeUpdateIssueMutation(); }, invokeUpdateIssueMutation() { - this.isUpdatingState = true; + this.toggleStateButtonLoading(true); this.$apollo .mutate({ @@ -148,11 +152,11 @@ export default { }) .catch(() => createFlash({ message: __('Update failed. Please try again.') })) .finally(() => { - this.isUpdatingState = false; + this.toggleStateButtonLoading(false); }); }, promoteToEpic() { - this.isUpdatingState = true; + this.toggleStateButtonLoading(true); this.$apollo .mutate({ @@ -179,7 +183,7 @@ export default { }) .catch(() => createFlash({ message: this.$options.i18n.promoteErrorMessage })) .finally(() => { - this.isUpdatingState = false; + this.toggleStateButtonLoading(false); }); }, }, @@ -191,7 +195,7 @@ export default { <gl-dropdown class="gl-display-block gl-display-sm-none!" block :text="dropdownText"> <gl-dropdown-item v-if="showToggleIssueStateButton" - :disabled="isUpdatingState" + :disabled="isToggleStateButtonLoading" @click="toggleIssueState" > {{ buttonText }} @@ -199,7 +203,11 @@ export default { <gl-dropdown-item v-if="canCreateIssue" :href="newIssuePath"> {{ newIssueTypeText }} </gl-dropdown-item> - <gl-dropdown-item v-if="canPromoteToEpic" :disabled="isUpdatingState" @click="promoteToEpic"> + <gl-dropdown-item + v-if="canPromoteToEpic" + :disabled="isToggleStateButtonLoading" + @click="promoteToEpic" + > {{ __('Promote to epic') }} </gl-dropdown-item> <gl-dropdown-item v-if="!isIssueAuthor" :href="reportAbusePath"> @@ -220,7 +228,7 @@ export default { class="gl-display-none gl-display-sm-inline-flex!" category="secondary" :data-qa-selector="qaSelector" - :loading="isUpdatingState" + :loading="isToggleStateButtonLoading" :variant="buttonVariant" @click="toggleIssueState" > @@ -243,7 +251,7 @@ export default { </gl-dropdown-item> <gl-dropdown-item v-if="canPromoteToEpic" - :disabled="isUpdatingState" + :disabled="isToggleStateButtonLoading" data-testid="promote-button" @click="promoteToEpic" > @@ -272,7 +280,7 @@ export default { > <p>{{ __('This issue is currently blocked by the following issues:') }}</p> <ul> - <li v-for="issue in getNoteableData.blocked_by_issues" :key="issue.iid"> + <li v-for="issue in getBlockedByIssues" :key="issue.iid"> <gl-link :href="issue.web_url">#{{ issue.iid }}</gl-link> </li> </ul> diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue index 9cc53a320b8..b70e999c765 100644 --- a/app/assets/javascripts/notes/components/comment_form.vue +++ b/app/assets/javascripts/notes/components/comment_form.vue @@ -3,23 +3,23 @@ import $ from 'jquery'; import { mapActions, mapGetters, mapState } from 'vuex'; import { isEmpty } from 'lodash'; import Autosize from 'autosize'; -import { GlAlert, GlIntersperse, GlLink, GlSprintf, GlButton, GlIcon } from '@gitlab/ui'; +import { GlButton, GlIcon } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; -import { deprecatedCreateFlash as Flash } from '../../flash'; -import Autosave from '../../autosave'; +import { deprecatedCreateFlash as Flash } from '~/flash'; +import Autosave from '~/autosave'; import { capitalizeFirstCharacter, convertToCamelCase, splitCamelCase, slugifyWithUnderscore, -} from '../../lib/utils/text_utility'; +} from '~/lib/utils/text_utility'; import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests'; import * as constants from '../constants'; import eventHub from '../event_hub'; -import NoteableWarning from '../../vue_shared/components/notes/noteable_warning.vue'; -import markdownField from '../../vue_shared/components/markdown/field.vue'; -import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; +import NoteableWarning from '~/vue_shared/components/notes/noteable_warning.vue'; +import markdownField from '~/vue_shared/components/markdown/field.vue'; +import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import noteSignedOutWidget from './note_signed_out_widget.vue'; import discussionLockedWidget from './discussion_locked_widget.vue'; import issuableStateMixin from '../mixins/issuable_state'; @@ -34,10 +34,6 @@ export default { userAvatarLink, GlButton, TimelineEntryItem, - GlAlert, - GlIntersperse, - GlLink, - GlSprintf, GlIcon, }, mixins: [issuableStateMixin], @@ -63,9 +59,8 @@ export default { 'getNoteableDataByProp', 'getNotesData', 'openState', - 'getBlockedByIssues', ]), - ...mapState(['isToggleStateButtonLoading', 'isToggleBlockedIssueWarning']), + ...mapState(['isToggleStateButtonLoading']), noteableDisplayName() { return splitCamelCase(this.noteableType).toLowerCase(); }, @@ -143,8 +138,8 @@ export default { ? __('merge request') : __('issue'); }, - isIssueType() { - return this.noteableDisplayName === constants.ISSUE_NOTEABLE_TYPE; + isMergeRequest() { + return this.noteableType === constants.MERGE_REQUEST_NOTEABLE_TYPE; }, trackingLabel() { return slugifyWithUnderscore(`${this.commentButtonTitle} button`); @@ -172,11 +167,9 @@ export default { 'stopPolling', 'restartPolling', 'removePlaceholderNotes', - 'closeIssue', - 'reopenIssue', + 'closeMergeRequest', + 'reopenMergeRequest', 'toggleIssueLocalState', - 'toggleStateButtonLoading', - 'toggleBlockedIssueWarning', ]), setIsSubmitButtonDisabled(note, isSubmitting) { if (!isEmpty(note) && !isSubmitting) { @@ -186,8 +179,6 @@ export default { } }, handleSave(withIssueAction) { - this.isSubmitting = true; - if (this.note.length) { const noteData = { endpoint: this.endpoint, @@ -210,9 +201,10 @@ export default { this.resizeTextarea(); this.stopPolling(); + this.isSubmitting = true; + this.saveNote(noteData) .then(() => { - this.enableButton(); this.restartPolling(); this.discard(); @@ -221,7 +213,6 @@ export default { } }) .catch(() => { - this.enableButton(); this.discard(false); const msg = __( 'Your comment could not be submitted! Please check your network connection and try again.', @@ -229,64 +220,31 @@ export default { Flash(msg, 'alert', this.$el); this.note = noteData.data.note.note; // Restore textarea content. this.removePlaceholderNotes(); + }) + .finally(() => { + this.isSubmitting = false; }); } else { this.toggleIssueState(); } }, - enableButton() { - this.isSubmitting = false; - }, toggleIssueState() { - if ( - this.noteableType.toLowerCase() === constants.ISSUE_NOTEABLE_TYPE && - this.isOpen && - this.getBlockedByIssues && - this.getBlockedByIssues.length > 0 - ) { - this.toggleBlockedIssueWarning(true); + if (!this.isMergeRequest) { + eventHub.$emit('toggle.issuable.state'); return; } - if (this.isOpen) { - this.forceCloseIssue(); - } else { - this.reopenIssue() - .then(() => { - this.enableButton(); - refreshUserMergeRequestCounts(); - }) - .catch(({ data }) => { - this.enableButton(); - this.toggleStateButtonLoading(false); - let errorMessage = sprintf( - __('Something went wrong while reopening the %{issuable}. Please try again later'), - { issuable: this.noteableDisplayName }, - ); - if (data) { - errorMessage = Object.values(data).join('\n'); - } + const toggleMergeRequestState = this.isOpen + ? this.closeMergeRequest + : this.reopenMergeRequest; - Flash(errorMessage); - }); - } - }, - forceCloseIssue() { - this.closeIssue() - .then(() => { - this.enableButton(); - refreshUserMergeRequestCounts(); - }) - .catch(() => { - this.enableButton(); - this.toggleStateButtonLoading(false); - Flash( - sprintf( - __('Something went wrong while closing the %{issuable}. Please try again later'), - { issuable: this.noteableDisplayName }, - ), - ); - }); + const errorMessage = this.isOpen + ? __('Something went wrong while closing the merge request. Please try again later') + : __('Something went wrong while reopening the merge request. Please try again later'); + + toggleMergeRequestState() + .then(refreshUserMergeRequestCounts) + .catch(() => Flash(errorMessage)); }, discard(shouldClear = true) { // `blur` is needed to clear slash commands autocomplete cache if event fired. @@ -384,6 +342,7 @@ export default { name="note[note]" class="note-textarea js-vue-comment-form js-note-text js-gfm-input js-autosize markdown-area" data-qa-selector="comment_field" + data-testid="comment-field" data-supports-quick-actions="true" :aria-label="__('Description')" :placeholder="__('Write a comment or drag your files hereā¦')" @@ -392,36 +351,7 @@ export default { @keydown.ctrl.enter="handleSave()" ></textarea> </markdown-field> - <gl-alert - v-if="isToggleBlockedIssueWarning" - class="gl-mt-5" - :title="__('Are you sure you want to close this blocked issue?')" - :primary-button-text="__('Yes, close issue')" - :secondary-button-text="__('Cancel')" - variant="warning" - :dismissible="false" - @primaryAction="toggleBlockedIssueWarning(false) && forceCloseIssue()" - @secondaryAction="toggleBlockedIssueWarning(false) && enableButton()" - > - <p> - <gl-sprintf - :message=" - __('This issue is currently blocked by the following issues: %{issues}.') - " - > - <template #issues> - <gl-intersperse> - <gl-link - v-for="blockingIssue in getBlockedByIssues" - :key="blockingIssue.web_url" - :href="blockingIssue.web_url" - >#{{ blockingIssue.iid }}</gl-link - > - </gl-intersperse> - </template> - </gl-sprintf> - </p> - </gl-alert> + <div class="note-form-actions"> <div class="btn-group gl-mr-3 comment-type-dropdown js-comment-type-dropdown droplab-dropdown" @@ -430,6 +360,7 @@ export default { :disabled="isSubmitButtonDisabled" class="js-comment-button js-comment-submit-button" data-qa-selector="comment_button" + data-testid="comment-button" type="submit" category="primary" variant="success" @@ -488,15 +419,13 @@ export default { </div> <gl-button - v-if="canToggleIssueState && !isToggleBlockedIssueWarning" + v-if="canToggleIssueState" :loading="isToggleStateButtonLoading" category="secondary" :variant="buttonVariant" - :class="[ - actionButtonClassNames, - 'btn-comment btn-comment-and-close js-action-button', - ]" - :disabled="isToggleStateButtonLoading || isSubmitting" + :class="[actionButtonClassNames, 'btn-comment btn-comment-and-close']" + :disabled="isSubmitting" + data-testid="close-reopen-button" @click="handleSave(true)" >{{ issueActionButtonTitle }}</gl-button > diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index ee668f4406f..f62b17de10c 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -244,21 +244,7 @@ export const toggleResolveNote = ({ commit, dispatch }, { endpoint, isResolved, }); }; -export const toggleBlockedIssueWarning = ({ commit }, value) => { - commit(types.TOGGLE_BLOCKED_ISSUE_WARNING, value); - // Hides Close issue button at the top of issue page - const closeDropdown = document.querySelector('.js-issuable-close-dropdown'); - if (closeDropdown) { - closeDropdown.classList.toggle('d-none'); - } else { - const closeButton = document.querySelector( - '.detail-page-header-actions .btn-close.btn-grouped', - ); - closeButton.classList.toggle('d-md-block'); - } -}; - -export const closeIssue = ({ commit, dispatch, state }) => { +export const closeMergeRequest = ({ commit, dispatch, state }) => { dispatch('toggleStateButtonLoading', true); return axios.put(state.notesData.closePath).then(({ data }) => { commit(types.CLOSE_ISSUE); @@ -267,7 +253,7 @@ export const closeIssue = ({ commit, dispatch, state }) => { }); }; -export const reopenIssue = ({ commit, dispatch, state }) => { +export const reopenMergeRequest = ({ commit, dispatch, state }) => { dispatch('toggleStateButtonLoading', true); return axios.put(state.notesData.reopenPath).then(({ data }) => { commit(types.REOPEN_ISSUE); diff --git a/app/assets/javascripts/notes/stores/modules/index.js b/app/assets/javascripts/notes/stores/modules/index.js index 3194a2099ea..4421a84a6b1 100644 --- a/app/assets/javascripts/notes/stores/modules/index.js +++ b/app/assets/javascripts/notes/stores/modules/index.js @@ -26,7 +26,6 @@ export default () => ({ // View layer isToggleStateButtonLoading: false, - isToggleBlockedIssueWarning: false, isNotesFetched: false, isLoading: true, isLoadingDescriptionVersion: false, diff --git a/app/assets/javascripts/notes/stores/mutation_types.js b/app/assets/javascripts/notes/stores/mutation_types.js index 8270f2a225b..5c4f62f4575 100644 --- a/app/assets/javascripts/notes/stores/mutation_types.js +++ b/app/assets/javascripts/notes/stores/mutation_types.js @@ -44,7 +44,6 @@ export const SET_RESOLVING_DISCUSSION = 'SET_RESOLVING_DISCUSSION'; export const CLOSE_ISSUE = 'CLOSE_ISSUE'; export const REOPEN_ISSUE = 'REOPEN_ISSUE'; export const TOGGLE_STATE_BUTTON_LOADING = 'TOGGLE_STATE_BUTTON_LOADING'; -export const TOGGLE_BLOCKED_ISSUE_WARNING = 'TOGGLE_BLOCKED_ISSUE_WARNING'; export const SET_ISSUE_CONFIDENTIAL = 'SET_ISSUE_CONFIDENTIAL'; export const SET_ISSUABLE_LOCK = 'SET_ISSUABLE_LOCK'; diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js index 85bdf60e8f9..53387b2eaff 100644 --- a/app/assets/javascripts/notes/stores/mutations.js +++ b/app/assets/javascripts/notes/stores/mutations.js @@ -305,10 +305,6 @@ export default { Object.assign(state, { isToggleStateButtonLoading: value }); }, - [types.TOGGLE_BLOCKED_ISSUE_WARNING](state, value) { - Object.assign(state, { isToggleBlockedIssueWarning: value }); - }, - [types.SET_NOTES_FETCHED_STATE](state, value) { Object.assign(state, { isNotesFetched: value }); }, diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue index c45666e69eb..fb61c13983f 100644 --- a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue +++ b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue @@ -1,10 +1,13 @@ <script> import Tribute from 'tributejs'; +import { + GfmAutocompleteType, + tributeConfig, +} from 'ee_else_ce/vue_shared/components/gfm_autocomplete/utils'; import createFlash from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { __ } from '~/locale'; import SidebarMediator from '~/sidebar/sidebar_mediator'; -import { GfmAutocompleteType, tributeConfig } from '~/vue_shared/components/gfm_autocomplete/utils'; export default { errorMessage: __( diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js index b2e995d0f17..2581888b504 100644 --- a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js +++ b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js @@ -24,7 +24,7 @@ export const tributeConfig = { [GfmAutocompleteType.Issues]: { config: { trigger: '#', - lookup: value => value.iid + value.title, + lookup: value => `${value.iid}${value.title}`, menuItemTemplate: ({ original }) => `<small>${original.reference || original.iid}</small> ${escape(original.title)}`, selectTemplate: ({ original }) => original.reference || `#${original.iid}`, @@ -61,7 +61,7 @@ export const tributeConfig = { trigger: '@', fillAttr: 'username', lookup: value => - value.type === groupType ? last(value.name.split(' / ')) : value.name + value.username, + value.type === groupType ? last(value.name.split(' / ')) : `${value.name}${value.username}`, menuItemTemplate: ({ original }) => { const commonClasses = 'gl-avatar gl-avatar-s24 gl-flex-shrink-0'; const noAvatarClasses = `${commonClasses} gl-rounded-small @@ -115,7 +115,7 @@ export const tributeConfig = { [GfmAutocompleteType.MergeRequests]: { config: { trigger: '!', - lookup: value => value.iid + value.title, + lookup: value => `${value.iid}${value.title}`, menuItemTemplate: ({ original }) => `<small>${original.reference || original.iid}</small> ${escape(original.title)}`, selectTemplate: ({ original }) => original.reference || `!${original.iid}`, @@ -135,7 +135,7 @@ export const tributeConfig = { config: { trigger: '$', fillAttr: 'id', - lookup: value => value.id + value.title, + lookup: value => `${value.id}${value.title}`, menuItemTemplate: ({ original }) => `<small>${original.id}</small> ${escape(original.title)}`, }, }, diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue index 0d703545073..232a3054cd0 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/field.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue @@ -173,7 +173,7 @@ export default { members: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, issues: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, mergeRequests: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, - epics: this.enableAutocomplete, + epics: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, milestones: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, labels: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, snippets: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, diff --git a/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue b/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue index c12012d8419..ad6f6e0e2e3 100644 --- a/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue +++ b/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue @@ -88,7 +88,7 @@ export default { }; </script> <template> - <div class="issuable-note-warning"> + <div class="issuable-note-warning" data-testid="confidential-warning"> <gl-icon v-if="!isLockedAndConfidential" :name="warningIcon" :size="16" class="icon inline" /> <span v-if="isLockedAndConfidential" ref="lockedAndConfidential"> diff --git a/app/assets/stylesheets/page_bundles/alert_management_details.scss b/app/assets/stylesheets/page_bundles/alert_management_details.scss index beb80a14c5a..2eaf4517710 100644 --- a/app/assets/stylesheets/page_bundles/alert_management_details.scss +++ b/app/assets/stylesheets/page_bundles/alert_management_details.scss @@ -17,22 +17,19 @@ } } - .assignee-dropdown-item { - .dropdown-item { - @include gl-display-flex; - @include gl-align-items-center; - + .dropdown-item { + &:first-child { &::before { - top: 50% !important; + @include gl-pt-0; } + } - &.is-active { - &:last-child { - @include gl-border-b-gray-100; - @include gl-border-b-1; - @include gl-border-b-solid; - } - } + &::before { + @include gl-pt-8; + } + + .gl-new-dropdown-item-text-wrapper { + @include gl-py-0; } } diff --git a/app/controllers/concerns/snippets_actions.rb b/app/controllers/concerns/snippets_actions.rb index 0153ede2821..df7a574848f 100644 --- a/app/controllers/concerns/snippets_actions.rb +++ b/app/controllers/concerns/snippets_actions.rb @@ -9,11 +9,14 @@ module SnippetsActions include Gitlab::NoteableMetadata include Snippets::SendBlob include SnippetsSort + include RedisTracking included do skip_before_action :verify_authenticity_token, if: -> { action_name == 'show' && js_request? } + track_redis_hll_event :show, name: 'i_snippets_show', feature: :usage_data_i_snippets_show, feature_default_enabled: false + respond_to :html end diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb index 4adbd37608f..0d7ce966537 100644 --- a/app/models/container_repository.rb +++ b/app/models/container_repository.rb @@ -25,8 +25,7 @@ class ContainerRepository < ApplicationRecord .with_container_registry .select(:id) - ContainerRepository - .joins("INNER JOIN (#{project_scope.to_sql}) projects on projects.id=container_repositories.project_id") + joins("INNER JOIN (#{project_scope.to_sql}) projects on projects.id=container_repositories.project_id") end scope :for_project_id, ->(project_id) { where(project_id: project_id) } scope :search_by_name, ->(query) { fuzzy_search(query, [:name], use_minimum_char_limit: false) } |