diff options
78 files changed, 1097 insertions, 368 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 3982254e492..8855008082f 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -3ee3de216e2e3d0fe4c6abe35481b41af0c68223 +d3bb9a8fe1d9ff265edf3920c348b2d5993ca0a8 @@ -514,7 +514,7 @@ gem 'gitaly', '~> 16.1.0-rc1' # KAS GRPC protocol definitions gem 'kas-grpc', '~> 0.1.0' -gem 'grpc', '~> 1.55.0' +gem 'grpc', '~> 1.42.0' gem 'google-protobuf', '~> 3.23', '>= 3.23.2' diff --git a/Gemfile.checksum b/Gemfile.checksum index 216acff381b..17e0167bb38 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -267,13 +267,12 @@ {"name":"graphql","version":"1.13.12","platform":"ruby","checksum":"1d82666cf201193a8d0cb54cea38576b820418db4869b549f61a35f3a2d97ac3"}, {"name":"graphql-client","version":"0.17.0","platform":"ruby","checksum":"5aaf02ce8f2dbc8e3ba05a7eaeb3ad9336762c4424c6093f4438fbb9490eeb5d"}, {"name":"graphql-docs","version":"2.1.0","platform":"ruby","checksum":"7eb82402f8fda455104b2b60364e9ada145d79d3121a8f915790d49da38bb576"}, -{"name":"grpc","version":"1.55.0","platform":"ruby","checksum":"529332f8e5e98f5b138afd5c4a9c7bdc9e247f4c10c84c1adbf1a114eba161ae"}, -{"name":"grpc","version":"1.55.0","platform":"x64-mingw-ucrt","checksum":"6b5c7b7358476469c5ecb46f35e1eff6983efc9395d9db8db0a2eb4207c82ffb"}, -{"name":"grpc","version":"1.55.0","platform":"x64-mingw32","checksum":"73755c256fc0fe5361a979cd609414ebdaa5862f5821fba20ea31110f1d87405"}, -{"name":"grpc","version":"1.55.0","platform":"x86-linux","checksum":"37c20569a17b1cff91155f193b0df41eb42fd0aed9051fa91ccca273a259e393"}, -{"name":"grpc","version":"1.55.0","platform":"x86-mingw32","checksum":"6b4144b5af8086b46b2e62b5fbda50fc19105a4efefafaca63e15b0384c42274"}, -{"name":"grpc","version":"1.55.0","platform":"x86_64-darwin","checksum":"d7f57eb84811d7ea2a9464ec88d9296a92801f643a4d7cf76cf4896edf12a25c"}, -{"name":"grpc","version":"1.55.0","platform":"x86_64-linux","checksum":"4ee73555759774db22ba23ff79c332cce7ae08b0ba4d4b33ab4747e83e0a8518"}, +{"name":"grpc","version":"1.42.0","platform":"ruby","checksum":"b3d2649e67c6a636544996843d9ec191699c54c1aca797dbfea4dff36c14584a"}, +{"name":"grpc","version":"1.42.0","platform":"x64-mingw32","checksum":"6aac1b6576134b0a83e000b1269f60d502eb24aee96c64e2658c3f24f8e32ac0"}, +{"name":"grpc","version":"1.42.0","platform":"x86-linux","checksum":"4aa50538aa929f1f3bcefb11c65ee1a1606b5aef838ea4d4e93c100b5f4263a5"}, +{"name":"grpc","version":"1.42.0","platform":"x86-mingw32","checksum":"eeb2a9381bea43fafe879b6ddaa011351a44d0894d48bdc965a07bcb67c6eb56"}, +{"name":"grpc","version":"1.42.0","platform":"x86_64-darwin","checksum":"20fa202d46d8a055628260622e98fb6439529fbac283f0552af620b909f78535"}, +{"name":"grpc","version":"1.42.0","platform":"x86_64-linux","checksum":"92e2ceb2aca335d5755163dd8030082091d5b0e63c117b1ca07051b66c53eb2e"}, {"name":"gssapi","version":"1.3.1","platform":"ruby","checksum":"c51cf30842ee39bd93ce7fc33e20405ff8a04cda9dec6092071b61258284aee1"}, {"name":"guard","version":"2.16.2","platform":"ruby","checksum":"71ba7abaddecc8be91ab77bbaf78f767246603652ebbc7b976fda497ebdc8fbb"}, {"name":"guard-compat","version":"1.2.1","platform":"ruby","checksum":"3ad21ab0070107f92edfd82610b5cdc2fb8e368851e72362ada9703443d646fe"}, diff --git a/Gemfile.lock b/Gemfile.lock index dfddd61fdc1..6868c807042 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -753,8 +753,8 @@ GEM graphql (~> 1.12) html-pipeline (~> 2.9) sass (~> 3.4) - grpc (1.55.0) - google-protobuf (~> 3.23) + grpc (1.42.0) + google-protobuf (~> 3.18) googleapis-common-protos-types (~> 1.0) gssapi (1.3.1) ffi (>= 1.0.1) @@ -1789,7 +1789,7 @@ DEPENDENCIES graphlyte (~> 1.0.0) graphql (~> 1.13.12) graphql-docs (~> 2.1.0) - grpc (~> 1.55.0) + grpc (~> 1.42.0) gssapi (~> 1.3.1) guard-rspec haml_lint (~> 0.40.0) diff --git a/app/assets/javascripts/feature_flags/components/form.vue b/app/assets/javascripts/feature_flags/components/form.vue index 8b79c661b12..35abcc3d561 100644 --- a/app/assets/javascripts/feature_flags/components/form.vue +++ b/app/assets/javascripts/feature_flags/components/form.vue @@ -157,16 +157,18 @@ export default { <template> <form class="feature-flags-form"> <fieldset> - <div class="row"> - <div class="form-group col-md-4"> - <label for="feature-flag-name" class="label-bold">{{ s__('FeatureFlags|Name') }} *</label> + <div class="gl-display-flex gl-flex-wrap gl-mx-n5"> + <div class="gl-mb-5 gl-px-5 gl-w-full col-md-4"> + <label for="feature-flag-name" class="gl-font-weight-bold" + >{{ s__('FeatureFlags|Name') }} *</label + > <input id="feature-flag-name" v-model="formName" class="form-control" /> </div> </div> - <div class="row"> - <div class="form-group col-md-4"> - <label for="feature-flag-description" class="label-bold"> + <div class="gl-display-flex gl-flex-wrap gl-mx-n5"> + <div class="gl-mb-5 gl-px-5 gl-w-full col-md-4"> + <label for="feature-flag-description" class="gl-font-weight-bold"> {{ s__('FeatureFlags|Description') }} </label> <textarea @@ -185,8 +187,8 @@ export default { :show-categorized-issues="false" /> - <div class="row"> - <div class="col-md-12"> + <div class="gl-display-flex gl-flex-wrap gl-mx-n5"> + <div class="gl-mb-5 gl-px-5 gl-w-full"> <h4>{{ s__('FeatureFlags|Strategies') }}</h4> <div class="gl-display-flex gl-align-items-baseline gl-justify-content-space-between"> <p class="gl-mr-5">{{ $options.translations.newHelpText }}</p> @@ -206,7 +208,7 @@ export default { @delete="deleteStrategy(strategy)" /> </div> - <div v-else class="gl-display-flex gl-justify-content-center gl-border-t gl-py-6 w-100"> + <div v-else class="gl-display-flex gl-justify-content-center gl-border-t gl-py-6 gl-w-full"> <span>{{ $options.translations.noStrategiesText }}</span> </div> </fieldset> diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index 4277e535d20..1e02703cbe7 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -145,12 +145,6 @@ MergeRequest.decreaseCounter = function (by = 1) { $el.text(addDelimiter(count)); }; -MergeRequest.hideCloseButton = function () { - const el = document.querySelector('.merge-request .js-issuable-actions'); - // Dropdown for mobile screen - el.querySelector('li.js-close-item').classList.add('hidden'); -}; - MergeRequest.toggleDraftStatus = function (title, isReady) { if (!window.gon?.features?.realtimeMrStatusChange) { eventHub.$emit('MRWidgetUpdateRequested'); diff --git a/app/assets/javascripts/mr_more_dropdown.js b/app/assets/javascripts/mr_more_dropdown.js new file mode 100644 index 00000000000..720619b72ae --- /dev/null +++ b/app/assets/javascripts/mr_more_dropdown.js @@ -0,0 +1,57 @@ +import Vue from 'vue'; +import MrMoreDropdown from '~/vue_shared/components/mr_more_dropdown.vue'; + +export const initMrMoreDropdown = () => { + const el = document.querySelector('.js-mr-more-dropdown'); + + if (!el) { + return false; + } + + const { + mergeRequest, + projectPath, + editUrl, + isCurrentUser, + isLoggedIn, + canUpdateMergeRequest, + open, + merged, + sourceProjectMissing, + clipboardText, + reportedUserId, + reportedFromUrl, + } = el.dataset; + + let mr; + + try { + mr = JSON.parse(mergeRequest); + } catch { + mr = {}; + } + + return new Vue({ + el, + provide: { + reportAbusePath: el.dataset.reportAbusePath, + }, + render: (createElement) => + createElement(MrMoreDropdown, { + props: { + mr, + projectPath, + editUrl, + isCurrentUser, + isLoggedIn: Boolean(isLoggedIn), + canUpdateMergeRequest, + open, + isMerged: merged, + sourceProjectMissing, + clipboardText, + reportedUserId: Number(reportedUserId), + reportedFromUrl, + }, + }), + }); +}; diff --git a/app/assets/javascripts/pages/projects/merge_requests/show/index.js b/app/assets/javascripts/pages/projects/merge_requests/show/index.js index 38cc4337047..67dc3782a24 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/show/index.js +++ b/app/assets/javascripts/pages/projects/merge_requests/show/index.js @@ -1,7 +1,9 @@ import mountNotesApp from 'ee_else_ce/mr_notes/mount_app'; import { initReportAbuse } from '~/projects/report_abuse'; +import { initMrMoreDropdown } from '~/mr_more_dropdown'; import { initMrPage } from '../page'; initMrPage(); mountNotesApp(); initReportAbuse(); +initMrMoreDropdown(); diff --git a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue index 06876546fa4..1d9233db361 100644 --- a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue +++ b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue @@ -1,9 +1,14 @@ <script> -import { GlIcon, GlTooltipDirective, GlOutsideDirective as Outside } from '@gitlab/ui'; +import { + GlIcon, + GlLoadingIcon, + GlDisclosureDropdownItem, + GlTooltipDirective, + GlOutsideDirective as Outside, +} from '@gitlab/ui'; import { mapGetters, mapActions } from 'vuex'; import { TYPE_ISSUE } from '~/issues/constants'; import { __, sprintf } from '~/locale'; -import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { createAlert } from '~/alert'; import toast from '~/vue_shared/plugins/global_toast'; @@ -15,17 +20,17 @@ export default { icon: 'lock', class: 'value', iconClass: 'is-active', - displayText: __('Locked'), }, unlocked: { class: ['no-value hide-collapsed'], icon: 'lock-open', iconClass: '', - displayText: __('Unlocked'), }, components: { EditForm, GlIcon, + GlLoadingIcon, + GlDisclosureDropdownItem, }, directives: { GlTooltip: GlTooltipDirective, @@ -39,8 +44,23 @@ export default { type: Boolean, }, }, + i18n: { + issue: __('issue'), + issueCapitalized: __('Issue'), + mergeRequest: __('merge request'), + mergeRequestCapitalized: __('Merge request'), + locked: __('Locked'), + unlocked: __('Unlocked'), + lockingMergeRequest: __('Locking %{issuableDisplayName}'), + unlockingMergeRequest: __('Unlocking %{issuableDisplayName}'), + lockMergeRequest: __('Lock %{issuableDisplayName}'), + unlockMergeRequest: __('Unlock %{issuableDisplayName}'), + lockedMessage: __('%{issuableDisplayName} locked.'), + unlockedMessage: __('%{issuableDisplayName} unlocked.'), + }, data() { return { + isLoading: false, isLockDialogOpen: false, }; }, @@ -49,18 +69,61 @@ export default { isMovedMrSidebar() { return this.glFeatures.movedMrSidebar; }, + isIssuable() { + return this.getNoteableData.targetType === TYPE_ISSUE; + }, issuableDisplayName() { - const isInIssuePage = this.getNoteableData.targetType === TYPE_ISSUE; - return isInIssuePage ? __('issue') : __('merge request'); + return this.isIssuable ? this.$options.i18n.issue : this.$options.i18n.mergeRequest; + }, + issuableDisplayNameCapitalized() { + return this.isIssuable + ? this.$options.i18n.issueCapitalized + : this.$options.i18n.mergeRequestCapitalized; }, isLocked() { return this.getNoteableData.discussion_locked; }, lockStatus() { - return this.isLocked ? this.$options.locked : this.$options.unlocked; + return this.isLocked ? this.$options.i18n.locked : this.$options.i18n.unlocked; }, tooltipLabel() { - return this.isLocked ? __('Locked') : __('Unlocked'); + return this.isLocked ? this.$options.i18n.locked : this.$options.i18n.unlocked; + }, + lockToggleInProgressText() { + return this.isLocked ? this.unlockingMergeRequestText : this.lockingMergeRequestText; + }, + lockToggleText() { + return this.isLocked ? this.unlockMergeRequestText : this.lockMergeRequestText; + }, + lockingMergeRequestText() { + return sprintf(this.$options.i18n.lockingMergeRequest, { + issuableDisplayName: this.issuableDisplayName, + }); + }, + unlockingMergeRequestText() { + return sprintf(this.$options.i18n.unlockingMergeRequest, { + issuableDisplayName: this.issuableDisplayName, + }); + }, + lockMergeRequestText() { + return sprintf(this.$options.i18n.lockMergeRequest, { + issuableDisplayName: this.issuableDisplayName, + }); + }, + unlockMergeRequestText() { + return sprintf(this.$options.i18n.unlockMergeRequest, { + issuableDisplayName: this.issuableDisplayName, + }); + }, + lockedMessageText() { + return sprintf(this.$options.i18n.lockedMessage, { + issuableDisplayName: this.issuableDisplayNameCapitalized, + }); + }, + unlockedMessageText() { + return sprintf(this.$options.i18n.unlockedMessage, { + issuableDisplayName: this.issuableDisplayNameCapitalized, + }); }, }, @@ -88,12 +151,7 @@ export default { }) .then(() => { if (this.isMovedMrSidebar) { - toast( - sprintf(__('%{issuableDisplayName} %{lockStatus}.'), { - issuableDisplayName: capitalizeFirstCharacter(this.issuableDisplayName), - lockStatus: this.isLocked ? __('locked') : __('unlocked'), - }), - ); + toast(this.isLocked ? this.lockedMessageText : this.unlockedMessageText); } }) .catch(() => { @@ -116,18 +174,35 @@ export default { </script> <template> - <li v-if="isMovedMrSidebar" class="gl-dropdown-item"> + <li v-if="isMovedMrSidebar && isIssuable" class="gl-dropdown-item"> <button type="button" class="dropdown-item" data-testid="issuable-lock" @click="toggleLocked"> <span class="gl-dropdown-item-text-wrapper"> - <template v-if="isLocked"> - {{ sprintf(__('Unlock %{issuableType}'), { issuableType: issuableDisplayName }) }} + <template v-if="isLoading"> + <gl-loading-icon inline size="sm" /> {{ lockToggleInProgressText }} </template> <template v-else> - {{ sprintf(__('Lock %{issuableType}'), { issuableType: issuableDisplayName }) }} + {{ lockToggleText }} </template> </span> </button> </li> + <gl-disclosure-dropdown-item v-else-if="isMovedMrSidebar"> + <button + type="button" + class="gl-new-dropdown-item-content" + data-testid="issuable-lock" + @click="toggleLocked" + > + <span class="gl-new-dropdown-item-text-wrapper"> + <template v-if="isLoading"> + <gl-loading-icon inline size="sm" /> {{ lockToggleInProgressText }} + </template> + <template v-else> + {{ lockToggleText }} + </template> + </span> + </button> + </gl-disclosure-dropdown-item> <div v-else class="block issuable-sidebar-item lock"> <div v-gl-tooltip.left.viewport="{ title: tooltipLabel }" @@ -139,7 +214,7 @@ export default { </div> <div class="hide-collapsed gl-line-height-20 gl-mb-2 gl-text-gray-900 gl-font-weight-bold"> - {{ sprintf(__('Lock %{issuableDisplayName}'), { issuableDisplayName: issuableDisplayName }) }} + {{ lockMergeRequestText }} <a v-if="isEditable" class="float-right lock-edit btn gl-text-gray-900! gl-ml-auto hide-collapsed btn-default btn-sm gl-button btn-default-tertiary gl-mr-n2" @@ -164,7 +239,7 @@ export default { /> <div data-testid="lock-status" class="sidebar-item-value" :class="lockStatus.class"> - {{ lockStatus.displayText }} + {{ lockStatus }} </div> </div> </div> diff --git a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue index f2b960ed02c..d6e1847aecb 100644 --- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue +++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue @@ -1,7 +1,14 @@ <script> -import { GlDropdownForm, GlIcon, GlLoadingIcon, GlToggle, GlTooltipDirective } from '@gitlab/ui'; +import { + GlDisclosureDropdownItem, + GlDropdownForm, + GlIcon, + GlLoadingIcon, + GlToggle, + GlTooltipDirective, +} from '@gitlab/ui'; import { createAlert } from '~/alert'; -import { TYPE_EPIC, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants'; +import { TYPE_ISSUE, TYPE_EPIC, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants'; import { isLoggedIn } from '~/lib/utils/common_utils'; import { __, sprintf } from '~/locale'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; @@ -22,6 +29,7 @@ export default { GlTooltip: GlTooltipDirective, }, components: { + GlDisclosureDropdownItem, GlDropdownForm, GlIcon, GlLoadingIcon, @@ -89,6 +97,9 @@ export default { isMovedMrSidebar() { return this.glFeatures.movedMrSidebar; }, + isIssuable() { + return this.issuableType === TYPE_ISSUE; + }, isLoading() { return this.$apollo.queries?.subscribed?.loading || this.loading; }, @@ -182,18 +193,32 @@ export default { </script> <template> - <gl-dropdown-form v-if="isMovedMrSidebar" class="gl-dropdown-item"> + <gl-dropdown-form v-if="isMovedMrSidebar && isIssuable" class="gl-dropdown-item"> <div class="gl-px-5 gl-pb-2 gl-pt-1"> <gl-toggle :value="subscribed" - :label="__('Notifications')" + :label="$options.i18n.notifications" class="merge-request-notification-toggle" label-position="left" - data-testid="notifications-toggle" + data-testid="notification-toggle" @change="toggleSubscribed" /> </div> </gl-dropdown-form> + <gl-disclosure-dropdown-item + v-else-if="isMovedMrSidebar" + data-testid="notification-toggle" + @action="toggleSubscribed" + > + <template #list-item> + <gl-toggle + :value="subscribed" + :label="__('Notifications')" + class="merge-request-notification-toggle" + label-position="left" + /> + </template> + </gl-disclosure-dropdown-item> <sidebar-editable-item v-else ref="editable" diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue index 17c51bc4e6e..9258bc39bcb 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue @@ -55,7 +55,6 @@ export default { // If state is merged we should update the widget and stop the polling eventHub.$emit('MRWidgetUpdateRequested'); eventHub.$emit('FetchActionsContent'); - MergeRequest.hideCloseButton(); MergeRequest.decreaseCounter(); stopPolling(); diff --git a/app/assets/javascripts/vue_shared/components/mr_more_dropdown.vue b/app/assets/javascripts/vue_shared/components/mr_more_dropdown.vue new file mode 100644 index 00000000000..064458cfc1f --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/mr_more_dropdown.vue @@ -0,0 +1,361 @@ +<script> +import { + GlLoadingIcon, + GlButton, + GlIcon, + GlDisclosureDropdown, + GlDisclosureDropdownItem, + GlDisclosureDropdownGroup, + GlTooltipDirective, +} from '@gitlab/ui'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import { apolloProvider } from '~/graphql_shared/issuable_client'; +import { __, s__ } from '~/locale'; +import api from '~/api'; +import axios from '~/lib/utils/axios_utils'; +import { createAlert } from '~/alert'; +import MergeRequest from '~/merge_request'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue'; +import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue'; +import NewHeaderActionsPopover from '~/issues/show/components/new_header_actions_popover.vue'; +import { TYPE_MERGE_REQUEST } from '~/issues/constants'; + +Vue.use(VueApollo); + +export default { + apolloProvider, + i18n: { + edit: __('Edit'), + copyReferenceText: __('Copy reference'), + errorMessage: __('Something went wrong. Please try again.'), + issuableName: __('merge request'), + reportAbuse: __('Report abuse'), + markAsReady: __('Mark as ready'), + markAsDraft: __('Mark as draft'), + close: __('Close %{issuableType}'), + closing: __('Closing %{issuableType}...'), + reopen: __('Reopen %{issuableType}'), + reopening: __('Reopening %{issuableType}...'), + lock: __('Lock %{issuableType}'), + mergeRequestActions: __('Merge request actions'), + }, + components: { + GlLoadingIcon, + GlButton, + GlIcon, + GlDisclosureDropdown, + GlDisclosureDropdownItem, + GlDisclosureDropdownGroup, + SidebarSubscriptionsWidget, + AbuseCategorySelector, + NewHeaderActionsPopover, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + mixins: [glFeatureFlagMixin()], + inject: { + reportAbusePath: { + default: '', + }, + }, + props: { + mr: { + type: Object, + required: true, + }, + projectPath: { + type: String, + default: '', + required: false, + }, + editUrl: { + type: String, + default: '', + required: false, + }, + isCurrentUser: { + type: Boolean, + default: false, + required: true, + }, + isLoggedIn: { + type: Boolean, + defauilt: false, + required: false, + }, + canUpdateMergeRequest: { + type: Boolean, + default: false, + required: false, + }, + open: { + type: Boolean, + default: false, + required: false, + }, + isMerged: { + type: Boolean, + default: false, + required: false, + }, + sourceProjectMissing: { + type: Boolean, + default: false, + required: false, + }, + clipboardText: { + type: String, + default: '', + required: false, + }, + reportedUserId: { + type: Number, + default: 0, + required: false, + }, + reportedFromUrl: { + type: String, + default: '', + required: false, + }, + }, + data() { + return { + isOpen: this.open, + draft: this.mr.draft, + issuableType: TYPE_MERGE_REQUEST, + fullPath: this.projectPath, + isLoading: false, + isLoadingDraft: false, + isLoadingClipboard: false, + isReportAbuseDrawerOpen: false, + }; + }, + computed: { + isMovedMrSidebar() { + return this.glFeatures.movedMrSidebar; + }, + draftLabel() { + return this.draft ? this.$options.i18n.markAsReady : this.$options.i18n.markAsDraft; + }, + draftState() { + return this.draft ? 'ready' : 'draft'; + }, + editItem() { + return { + text: this.$options.i18n.edit, + href: this.editUrl, + }; + }, + }, + methods: { + draftAction() { + this.isLoadingDraft = true; + + axios + .put(`?merge_request[wip_event]=${this.draftState}`, null, { + params: { format: 'json' }, + }) + .then(({ data }) => { + MergeRequest.toggleDraftStatus(data.title, this.draft); + }) + .catch(() => { + createAlert({ + message: this.$options.i18n.errorMessage, + }); + }) + .finally(() => { + this.draft = !this.draft; + this.isLoadingDraft = false; + this.closeActionsDropdown(); + }); + }, + stateAction(state) { + this.isLoading = true; + + api + .updateMergeRequest(this.mr.target_project_id, this.mr.iid, { state_event: state }) + .then(() => { + window.location.reload(); + }) + .catch(() => { + createAlert({ + message: this.$options.i18n.errorMessage, + }); + }) + .finally(() => { + this.isOpen = !this.isOpen; + this.isLoading = false; + this.closeActionsDropdown(); + }); + }, + copyClipboardAction() { + this.$toast.show(s__('MergeRequests|Reference copied')); + this.closeActionsDropdown(); + }, + reportAbuseAction(isOpen) { + if (isOpen) { + this.closeActionsDropdown(); + } + + this.isReportAbuseDrawerOpen = isOpen; + }, + closeActionsDropdown() { + this.$refs.mrMoreActionsDropdown.close(); + }, + showReopenMergeRequestOption() { + return !this.sourceProjectMissing && !this.isOpen; + }, + }, +}; +</script> + +<template> + <div + class="gl-display-flex gl-justify-content-end gl-w-full gl-relative" + data-testid="merge-request-actions" + > + <gl-disclosure-dropdown + id="new-actions-header-dropdown" + ref="mrMoreActionsDropdown" + data-testid="dropdown-toggle" + placement="right" + :auto-close="false" + > + <template #toggle> + <div class="gl-min-h-7 gl-mb-2 gl-md-mb-0!" :aria-label="$options.i18n.mergeRequestActions"> + <gl-button + class="gl-md-display-none! gl-new-dropdown-toggle gl-absolute gl-top-0 gl-left-0 gl-w-full" + category="secondary" + > + <span class="">{{ $options.i18n.mergeRequestActions }}</span> + <gl-icon class="dropdown-chevron" name="chevron-down" /> + </gl-button> + <gl-button + class="gl-display-none gl-md-display-flex! gl-new-dropdown-toggle gl-new-dropdown-icon-only gl-new-dropdown-toggle-no-caret gl-ml-3" + category="tertiary" + icon="ellipsis_v" + /> + </div> + </template> + <gl-disclosure-dropdown-group v-if="isLoggedIn && isMovedMrSidebar"> + <sidebar-subscriptions-widget + :iid="String(mr.iid)" + :full-path="fullPath" + :issuable-type="issuableType" + data-testid="notification-toggle" + /> + </gl-disclosure-dropdown-group> + + <gl-disclosure-dropdown-group + bordered + :class="{ 'gl-mt-0! gl-pt-0! gl-border-t-0!': !(isLoggedIn && isMovedMrSidebar) }" + > + <gl-disclosure-dropdown-item + v-if="canUpdateMergeRequest" + class="gl-md-display-none!" + data-testid="edit-merge-request" + :item="editItem" + /> + + <gl-disclosure-dropdown-item + v-if="isOpen && canUpdateMergeRequest" + data-testid="ready-and-draft-action" + @action="draftAction" + > + <template #list-item> + <gl-loading-icon v-if="isLoadingDraft" inline size="sm" /> + {{ draftLabel }} + </template> + </gl-disclosure-dropdown-item> + + <gl-disclosure-dropdown-item + v-if="isOpen && canUpdateMergeRequest" + data-testid="close-merge-request" + @action="stateAction('close')" + > + <template #list-item> + <template v-if="isLoading"> + <gl-loading-icon inline size="sm" /> + {{ + sprintf($options.i18n.closing, { + issuableType: $options.i18n.issuableName, + }) + }} + </template> + <template v-else> + {{ sprintf($options.i18n.close, { issuableType: $options.i18n.issuableName }) }} + </template> + </template> + </gl-disclosure-dropdown-item> + + <gl-disclosure-dropdown-item + v-else-if="!isMerged && showReopenMergeRequestOption && canUpdateMergeRequest" + data-testid="reopen-merge-request" + @action="stateAction('reopen')" + > + <template #list-item> + <template v-if="isLoading"> + <gl-loading-icon inline size="sm" /> + {{ + sprintf($options.i18n.reopening, { + issuableType: $options.i18n.issuableName, + }) + }} + </template> + <template v-else> + {{ sprintf($options.i18n.reopen, { issuableType: $options.i18n.issuableName }) }} + </template> + </template> + </gl-disclosure-dropdown-item> + + <gl-disclosure-dropdown-item v-if="isMovedMrSidebar" class="js-sidebar-lock-root"> + <template #list-item> + {{ sprintf($options.i18n.lock, { issuableType: $options.i18n.issuableName }) }} + </template> + </gl-disclosure-dropdown-item> + + <gl-disclosure-dropdown-item + v-if="isMovedMrSidebar" + class="js-copy-reference" + :data-clipboard-text="clipboardText" + data-testid="copy-reference" + @action="copyClipboardAction" + > + <template #list-item> + {{ $options.i18n.copyReferenceText }} + </template> + </gl-disclosure-dropdown-item> + </gl-disclosure-dropdown-group> + + <gl-disclosure-dropdown-group + v-if="!isCurrentUser" + bordered + :class="{ 'gl-mt-0! gl-pt-0! gl-border-t-0!': !canUpdateMergeRequest }" + > + <gl-disclosure-dropdown-item + class="js-report-abuse-dropdown-item" + data-testid="report-abuse-option" + @action="reportAbuseAction(true)" + > + <template #list-item> + {{ $options.i18n.reportAbuse }} + </template> + </gl-disclosure-dropdown-item> + </gl-disclosure-dropdown-group> + </gl-disclosure-dropdown> + + <new-header-actions-popover v-if="isMovedMrSidebar" :issue-type="issuableType" /> + + <abuse-category-selector + v-if="!isCurrentUser && isReportAbuseDrawerOpen" + :reported-user-id="reportedUserId" + :reported-from-url="reportedFromUrl" + :show-drawer="isReportAbuseDrawerOpen" + @close-drawer="reportAbuseAction(false)" + /> + </div> +</template> diff --git a/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml b/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml index 9bfa0e7a309..a3536ead240 100644 --- a/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml +++ b/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml @@ -1,53 +1,15 @@ -- display_issuable_type = issuable_display_type(@merge_request) - -.btn-group.gl-md-ml-3.gl-display-flex.dropdown.gl-dropdown.gl-md-w-auto.gl-w-full - %span.js-sidebar-header-popover - = button_tag type: 'button', id: "new-actions-header-dropdown", class: "btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle btn-default-tertiary dropdown-icon-only dropdown-toggle-no-caret gl-display-none! gl-md-display-inline-flex!", title: _('Merge request actions'), 'aria-label': _('Merge request actions'), data: { toggle: 'dropdown', testid: 'merge-request-actions' } do - = sprite_icon "ellipsis_v", size: 16, css_class: "dropdown-icon gl-icon" - = button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md btn-block gl-button gl-dropdown-toggle gl-md-display-none!", data: { 'toggle' => 'dropdown' } do - %span.gl-dropdown-button-text= _('Merge request actions') - = sprite_icon "chevron-down", size: 16, css_class: "dropdown-icon gl-icon" - .dropdown-menu.dropdown-menu-right - .gl-dropdown-inner - .gl-dropdown-contents - %ul - - if current_user && moved_mr_sidebar_enabled? - %li.gl-dropdown-item.js-sidebar-subscriptions-widget-root - %li.gl-dropdown-divider - %hr.dropdown-divider - - if can?(current_user, :update_merge_request, @merge_request) - %li.gl-dropdown-item{ class: "gl-md-display-none!" } - = link_to edit_project_merge_request_path(@project, @merge_request), class: 'dropdown-item' do - .gl-dropdown-item-text-wrapper - = _('Edit') - - if @merge_request.open? - %li.gl-dropdown-item - = link_to toggle_draft_merge_request_path(@merge_request), method: :put, class: 'dropdown-item js-draft-toggle-button' do - .gl-dropdown-item-text-wrapper - = @merge_request.draft? ? _('Mark as ready') : _('Mark as draft') - %li.gl-dropdown-item.js-close-item - = link_to close_issuable_path(@merge_request), method: :put, class: 'dropdown-item' do - .gl-dropdown-item-text-wrapper - = _('Close') - = display_issuable_type - - elsif !@merge_request.source_project_missing? && @merge_request.closed? - %li.gl-dropdown-item - = link_to reopen_issuable_path(@merge_request), method: :put, class: 'dropdown-item' do - .gl-dropdown-item-text-wrapper - = _('Reopen') - = display_issuable_type - - if moved_mr_sidebar_enabled? - %li.gl-dropdown-item.js-sidebar-lock-root - %li.gl-dropdown-item - %button.dropdown-item.js-copy-reference{ type: "button", data: { 'clipboard-text': @merge_request.to_reference(full: true) } } - .gl-dropdown-item-text-wrapper - = _('Copy reference') - - - unless current_controller?('conflicts') - - unless issuable_author_is_current_user(@merge_request) - - if moved_mr_sidebar_enabled? - %li.gl-dropdown-divider - %hr.dropdown-divider - .js-report-abuse-dropdown-item{ data: { report_abuse_path: add_category_abuse_reports_path, reported_user_id: @merge_request.author.id, reported_from_url: merge_request_url(@merge_request) } } - -#js-report-abuse-drawer +.js-mr-more-dropdown{ data: { + merge_request: @merge_request.to_json, + project_path: @project.full_path, + edit_url: edit_project_merge_request_path(@project, @merge_request), + is_current_user: issuable_author_is_current_user(@merge_request), + is_logged_in: current_user, + can_update_merge_request: can?(current_user, :update_merge_request, @merge_request), + open: @merge_request.open?, + merged: @merge_request.merged?, + source_project_missing: @merge_request.source_project_missing?, + clipboard_text: @merge_request.to_reference(full: true), + report_abuse_path: add_category_abuse_reports_path, + reported_user_id: @merge_request.author.id, + reported_from_url: merge_request_url(@merge_request), +} } diff --git a/config/metrics/counts_28d/20210216180308_personal_snippets.yml b/config/metrics/counts_28d/20210216180308_personal_snippets.yml index 99893caa053..bcdc8f20e23 100644 --- a/config/metrics/counts_28d/20210216180308_personal_snippets.yml +++ b/config/metrics/counts_28d/20210216180308_personal_snippets.yml @@ -9,6 +9,7 @@ value_type: number status: active time_frame: 28d data_source: database +instrumentation_class: CountPersonalSnippetsMetric distribution: - ce - ee diff --git a/config/metrics/counts_28d/20210216180310_project_snippets.yml b/config/metrics/counts_28d/20210216180310_project_snippets.yml index e7c66f90a3d..bdf7375e569 100644 --- a/config/metrics/counts_28d/20210216180310_project_snippets.yml +++ b/config/metrics/counts_28d/20210216180310_project_snippets.yml @@ -8,6 +8,7 @@ product_group: source_code value_type: number status: active time_frame: 28d +instrumentation_class: CountProjectSnippetsMetric data_source: database distribution: - ce diff --git a/config/metrics/counts_28d/20210216180312_snippets.yml b/config/metrics/counts_28d/20210216180312_snippets.yml index e9a091c507b..7592ab4b461 100644 --- a/config/metrics/counts_28d/20210216180312_snippets.yml +++ b/config/metrics/counts_28d/20210216180312_snippets.yml @@ -9,6 +9,7 @@ value_type: number status: active time_frame: 28d data_source: database +instrumentation_class: CountSnippetsMetric distribution: - ce - ee diff --git a/config/metrics/counts_all/20210216180239_personal_snippets.yml b/config/metrics/counts_all/20210216180239_personal_snippets.yml index 4a031b6a7b4..872913c85bc 100644 --- a/config/metrics/counts_all/20210216180239_personal_snippets.yml +++ b/config/metrics/counts_all/20210216180239_personal_snippets.yml @@ -9,6 +9,7 @@ value_type: number status: active time_frame: all data_source: database +instrumentation_class: CountPersonalSnippetsMetric distribution: - ce - ee diff --git a/config/metrics/counts_all/20210216180241_project_snippets.yml b/config/metrics/counts_all/20210216180241_project_snippets.yml index cd35e388a4e..89adcbdf877 100644 --- a/config/metrics/counts_all/20210216180241_project_snippets.yml +++ b/config/metrics/counts_all/20210216180241_project_snippets.yml @@ -9,6 +9,7 @@ value_type: number status: active time_frame: all data_source: database +instrumentation_class: CountProjectSnippetsMetric distribution: - ce - ee diff --git a/config/metrics/counts_all/20210216180306_snippets.yml b/config/metrics/counts_all/20210216180306_snippets.yml index 88b7ae413d8..f2baffe86dc 100644 --- a/config/metrics/counts_all/20210216180306_snippets.yml +++ b/config/metrics/counts_all/20210216180306_snippets.yml @@ -8,6 +8,7 @@ product_group: source_code value_type: number status: active time_frame: all +instrumentation_class: CountSnippetsMetric data_source: database distribution: - ce diff --git a/doc/administration/auth/ldap/ldap-troubleshooting.md b/doc/administration/auth/ldap/ldap-troubleshooting.md index fe4430fd235..9fb3888b995 100644 --- a/doc/administration/auth/ldap/ldap-troubleshooting.md +++ b/doc/administration/auth/ldap/ldap-troubleshooting.md @@ -167,7 +167,8 @@ may see the following message: `Access denied for your LDAP account`. We have a workaround, based on toggling the access level of affected users: -1. As an administrator, on the top bar, select **Main menu > Admin**. +1. As an administrator, on the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Overview > Users**. 1. Select the name of the affected user. 1. In the upper-right corner, select **Edit**. @@ -224,7 +225,8 @@ field contains no data: To resolve this: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, go to **Settings > General**. 1. Expand both of the following: - **Account and limit**. @@ -367,7 +369,8 @@ things to debug the situation. - Ensure the correct [LDAP group link is added to the GitLab group](ldap_synchronization.md#add-group-links). - Check that the user has an LDAP identity: 1. Sign in to GitLab as an administrator user. - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Overview > Users**. 1. Search for the user. 1. Open the user by selecting their name. Do not select **Edit**. diff --git a/doc/administration/auth/ldap/ldap_synchronization.md b/doc/administration/auth/ldap/ldap_synchronization.md index cc788d6d4c8..e4b43feacc2 100644 --- a/doc/administration/auth/ldap/ldap_synchronization.md +++ b/doc/administration/auth/ldap/ldap_synchronization.md @@ -501,7 +501,8 @@ When global group memberships lock is enabled: To enable global group memberships lock: 1. [Configure LDAP](index.md#configure-ldap). -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > General**. 1. Expand the **Visibility and access controls** section. 1. Ensure the **Lock memberships to LDAP synchronization** checkbox is selected. @@ -513,7 +514,8 @@ By default, group members with the Owner role can manage [LDAP group synchroniza GitLab administrators can remove this permission from group Owners: 1. [Configure LDAP](index.md#configure-ldap). -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > General**. 1. Expand **Visibility and access controls**. 1. Ensure the **Allow group owners to manage LDAP-related settings** checkbox is not checked. diff --git a/doc/administration/geo/disaster_recovery/background_verification.md b/doc/administration/geo/disaster_recovery/background_verification.md index ea4523c66e6..6d7240a9f92 100644 --- a/doc/administration/geo/disaster_recovery/background_verification.md +++ b/doc/administration/geo/disaster_recovery/background_verification.md @@ -49,7 +49,8 @@ Feature.enable('geo_repository_verification') On the **primary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Sites**. 1. Expand **Verification information** tab for that site to view automatic checksumming status for repositories and wikis. Successes are shown in green, pending work @@ -59,7 +60,8 @@ On the **primary** site: On the **secondary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Sites**. 1. Expand **Verification information** tab for that site to view automatic checksumming status for repositories and wikis. Successes are shown in green, pending work @@ -87,7 +89,8 @@ increase load and vice versa. On the **primary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Sites**. 1. Select **Edit** for the **primary** site to customize the minimum re-verification interval: @@ -135,7 +138,8 @@ sudo gitlab-rake geo:verification:wiki:reset If the **primary** and **secondary** sites have a checksum verification mismatch, the cause may not be apparent. To find the cause of a checksum mismatch: 1. On the **primary** site: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Overview > Projects**. 1. Find the project that you want to check the checksum differences and select its name. diff --git a/doc/administration/geo/disaster_recovery/planned_failover.md b/doc/administration/geo/disaster_recovery/planned_failover.md index a52bdc759a2..13e0938fa59 100644 --- a/doc/administration/geo/disaster_recovery/planned_failover.md +++ b/doc/administration/geo/disaster_recovery/planned_failover.md @@ -149,7 +149,8 @@ ensure these processes are close to 100% as possible during active use. On the **secondary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Sites**. Replicated objects (shown in green) should be close to 100%, and there should be no failures (shown in red). If a large proportion of @@ -177,7 +178,8 @@ This [content was moved to another location](background_verification.md). On the **primary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Messages**. 1. Add a message notifying users on the maintenance window. You can check under **Geo > Sites** to estimate how long it @@ -190,7 +192,8 @@ To ensure that all data is replicated to a secondary site, updates (write reques be disabled on the **primary** site: 1. Enable [maintenance mode](../../maintenance_mode/index.md) on the **primary** site. -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. 1. On the Sidekiq dashboard, select **Cron**. 1. Select `Disable All` to disable non-Geo periodic background jobs. @@ -206,7 +209,8 @@ GitLab 13.9 through GitLab 14.3 are affected by a bug in which the Geo secondary 1. If you are manually replicating any data not managed by Geo, trigger the final replication process now. 1. On the **primary** site: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. 1. On the Sidekiq dashboard, select **Queues**, and wait for all queues except those with `geo` in the name to drop to 0. @@ -221,7 +225,8 @@ GitLab 13.9 through GitLab 14.3 are affected by a bug in which the Geo secondary - The Geo log cursor is up to date (0 events behind). 1. On the **secondary** site: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. 1. On the Sidekiq dashboard, select **Queues**, and wait for all the `geo` queues to drop to 0 queued and 0 running jobs. diff --git a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md index 4cd332d6250..9ec9e791f59 100644 --- a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md +++ b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md @@ -68,7 +68,8 @@ GitLab 13.9 through GitLab 14.3 are affected by a bug in which the Geo secondary On the **secondary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Sites** to see its status. Replicated objects (shown in green) should be close to 100%, and there should be no failures (shown in red). If a large proportion of @@ -133,7 +134,8 @@ follow these steps to avoid unnecessary data loss: connection. 1. On the **primary** site: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. 1. On the Sidekiq dashboard, select **Cron**. 1. Select `Disable All` to disable any non-Geo periodic background jobs. @@ -151,7 +153,8 @@ follow these steps to avoid unnecessary data loss: [data not managed by Geo](../../replication/datatypes.md#limitations-on-replicationverification), trigger the final replication process now. 1. On the **primary** site: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. 1. On the Sidekiq dashboard, select **Queues**, and wait for all queues except those with `geo` in the name to drop to 0. @@ -166,7 +169,8 @@ follow these steps to avoid unnecessary data loss: - The Geo log cursor is up to date (0 events behind). 1. On the **secondary** site: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. 1. On the Sidekiq dashboard, select **Queues**, and wait for all the `geo` queues to drop to 0 queued and 0 running jobs. diff --git a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md index ecece40f85a..7f94d6e4c1a 100644 --- a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md +++ b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md @@ -118,7 +118,8 @@ follow these steps to avoid unnecessary data loss: connection. 1. On the **primary** site: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. 1. On the Sidekiq dashboard, select **Cron**. 1. Select `Disable All` to disable any non-Geo periodic background jobs. @@ -136,7 +137,8 @@ follow these steps to avoid unnecessary data loss: [data not managed by Geo](../../replication/datatypes.md#limitations-on-replicationverification), trigger the final replication process now. 1. On the **primary** site: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. 1. On the Sidekiq dashboard, select **Queues**, and wait for all queues except those with `geo` in the name to drop to 0. @@ -151,7 +153,8 @@ follow these steps to avoid unnecessary data loss: - The Geo log cursor is up to date (0 events behind). 1. On the **secondary** site: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. 1. On the Sidekiq dashboard, select **Queues**, and wait for all the `geo` queues to drop to 0 queued and 0 running jobs. diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md index e29ebb1bb64..ae2cc262160 100644 --- a/doc/administration/geo/index.md +++ b/doc/administration/geo/index.md @@ -160,7 +160,9 @@ public URL of the primary site is used. To update the internal URL of the primary Geo site: -1. On the top bar, select **Main menu > Admin > Geo > Sites**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. +1. On the left sidebar, select **Geo > Sites**. 1. Select **Edit** on the primary site. 1. Change the **Internal URL**, then select **Save changes**. diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md index 5aee9bc5b83..0eba666979e 100644 --- a/doc/administration/geo/replication/configuration.md +++ b/doc/administration/geo/replication/configuration.md @@ -202,7 +202,8 @@ keys must be manually replicated to the **secondary** site. ``` 1. Navigate to the Primary Node GitLab Instance: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Sites**. 1. Select **Add site**. ![Add secondary site](img/adding_a_secondary_v15_8.png) @@ -311,7 +312,8 @@ method to be enabled. This is enabled by default, but if converting an existing On the **primary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > General**. 1. Expand **Visibility and access controls**. 1. If using Git over SSH, then: @@ -324,7 +326,8 @@ On the **primary** site: You can sign in to the **secondary** site with the same credentials you used with the **primary** site. After you sign in: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Sites**. 1. Verify that it's correctly identified as a **secondary** Geo site, and that Geo is enabled. diff --git a/doc/administration/geo/replication/container_registry.md b/doc/administration/geo/replication/container_registry.md index 1c1d9074a04..6dde611a20d 100644 --- a/doc/administration/geo/replication/container_registry.md +++ b/doc/administration/geo/replication/container_registry.md @@ -166,7 +166,8 @@ For each application and Sidekiq node on the **secondary** site: To verify Container Registry replication is working, on the **secondary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Nodes**. The initial replication, or "backfill", is probably still in progress. diff --git a/doc/administration/geo/replication/disable_geo.md b/doc/administration/geo/replication/disable_geo.md index abd6fd941af..bedcca7e311 100644 --- a/doc/administration/geo/replication/disable_geo.md +++ b/doc/administration/geo/replication/disable_geo.md @@ -36,7 +36,8 @@ to do that. To remove the **primary** site: 1. [Remove all secondary Geo sites](remove_geo_site.md) -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Nodes**. 1. Select **Remove** for the **primary** node. 1. Confirm by selecting **Remove** when the prompt appears. diff --git a/doc/administration/geo/replication/object_storage.md b/doc/administration/geo/replication/object_storage.md index b39acf2466d..86db8186a13 100644 --- a/doc/administration/geo/replication/object_storage.md +++ b/doc/administration/geo/replication/object_storage.md @@ -41,7 +41,8 @@ whether they are stored on the local file system or in object storage. To enable GitLab replication: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Nodes**. 1. Select **Edit** on the **secondary** site. 1. In the **Synchronization Settings** section, find the **Allow this secondary node to replicate content on Object Storage** diff --git a/doc/administration/geo/replication/remove_geo_site.md b/doc/administration/geo/replication/remove_geo_site.md index 9d92652daf4..de0ad3fe2fb 100644 --- a/doc/administration/geo/replication/remove_geo_site.md +++ b/doc/administration/geo/replication/remove_geo_site.md @@ -9,7 +9,8 @@ type: howto **Secondary** sites can be removed from the Geo cluster using the Geo administration page of the **primary** site. To remove a **secondary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Nodes**. 1. For the **secondary** site you want to remove, select **Remove**. 1. Confirm by selecting **Remove** when the prompt appears. diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md index 1766b1bef8b..f326a6940d5 100644 --- a/doc/administration/geo/replication/troubleshooting.md +++ b/doc/administration/geo/replication/troubleshooting.md @@ -27,7 +27,8 @@ Before attempting more advanced troubleshooting: On the **primary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Sites**. We perform the following health checks on each **secondary** site @@ -854,8 +855,11 @@ to start again from scratch, there are a few steps that can help you: ### Design repository failures on mirrored projects and project imports -On the top bar, under **Main menu > Admin > Geo > Sites**, -if the Design repositories progress bar shows +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. +1. On the left sidebar, select **Geo > Sites**. + +If the Design repositories progress bar shows `Synced` and `Failed` greater than 100%, and negative `Queued`, the instance is likely affected by [a bug in GitLab 13.2 and 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/241668). @@ -1190,7 +1194,8 @@ site's URL matches its external URL. On the **primary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Sites**. 1. Find the affected **secondary** site and select **Edit**. 1. Ensure the **URL** field matches the value found in `/etc/gitlab/gitlab.rb` @@ -1396,8 +1401,9 @@ If you have updated the value of `external_url` in `/etc/gitlab/gitlab.rb` for t In this case, make sure to update the changed URL on all your sites: -1. On the top bar, select **Main menu > Admin**. -1. On the left sidebar, select **Admin > Geo > Sites**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. +1. On the left sidebar, select **Geo > Sites**. 1. Change the URL and save the change. ## Fixing non-PostgreSQL replication failures diff --git a/doc/administration/geo/replication/tuning.md b/doc/administration/geo/replication/tuning.md index 4dc3ba93d66..9e1638643cb 100644 --- a/doc/administration/geo/replication/tuning.md +++ b/doc/administration/geo/replication/tuning.md @@ -14,7 +14,8 @@ in the background. On the **primary** site: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Geo > Sites**. 1. Select **Edit** of the secondary site you want to tune. 1. Under **Tuning settings**, there are several variables that can be tuned to diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md index 02c1c933a06..d5c01d4e1c1 100644 --- a/doc/administration/gitaly/praefect.md +++ b/doc/administration/gitaly/praefect.md @@ -1335,7 +1335,8 @@ Particular attention should be shown to: 1. Check that the Praefect storage is configured to store new repositories: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Settings > Repository**. 1. Expand the **Repository storage** section. diff --git a/doc/administration/gitaly/troubleshooting.md b/doc/administration/gitaly/troubleshooting.md index f95d7f44e3c..d383ebfe3e8 100644 --- a/doc/administration/gitaly/troubleshooting.md +++ b/doc/administration/gitaly/troubleshooting.md @@ -20,7 +20,8 @@ and our advice on [parsing the `gitaly/current` file](../logs/log_parsing.md#par When using standalone Gitaly servers, you must make sure they are the same version as GitLab to ensure full compatibility: -1. On the top bar, select **Main menu > Admin** on your GitLab instance. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Overview > Gitaly Servers**. 1. Confirm all Gitaly servers indicate that they are up to date. diff --git a/doc/administration/integration/diagrams_net.md b/doc/administration/integration/diagrams_net.md index fe5e730a064..a4e8528fb25 100644 --- a/doc/administration/integration/diagrams_net.md +++ b/doc/administration/integration/diagrams_net.md @@ -43,7 +43,8 @@ For more information, see [Run your own diagrams.net server with Docker](https:/ ## Enable Diagrams.net integration 1. Sign in to GitLab as an [Administrator](../../user/permissions.md) user. -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > General**. 1. Expand **Diagrams.net**. 1. Select the **Enable Diagrams.net** checkbox. diff --git a/doc/administration/integration/kroki.md b/doc/administration/integration/kroki.md index f90458200b3..0356212d6dd 100644 --- a/doc/administration/integration/kroki.md +++ b/doc/administration/integration/kroki.md @@ -61,7 +61,8 @@ read the [Kroki installation](https://docs.kroki.io/kroki/setup/install/#_images You need to enable Kroki integration from Settings under Admin Area. To do that, sign in with an administrator account and follow these steps: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. Go to **Settings > General**. 1. Expand the **Kroki** section. 1. Select **Enable Kroki** checkbox. diff --git a/doc/administration/integration/mailgun.md b/doc/administration/integration/mailgun.md index 218b2888033..87428d27c66 100644 --- a/doc/administration/integration/mailgun.md +++ b/doc/administration/integration/mailgun.md @@ -43,7 +43,8 @@ After configuring your Mailgun domain for the webhook endpoints, you're ready to enable the Mailgun integration: 1. Sign in to GitLab as an [Administrator](../../user/permissions.md) user. -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, go to **Settings > General** and expand the **Mailgun** section. 1. Select the **Enable Mailgun** checkbox. 1. Enter the Mailgun HTTP webhook signing key as described in diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md index 0e625590262..bb72d7070be 100644 --- a/doc/administration/integration/plantuml.md +++ b/doc/administration/integration/plantuml.md @@ -308,7 +308,8 @@ stop; After configuring your local PlantUML server, you're ready to enable the PlantUML integration: 1. Sign in to GitLab as an [Administrator](../../user/permissions.md) user. -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, go to **Settings > General** and expand the **PlantUML** section. 1. Select the **Enable PlantUML** checkbox. 1. Set the PlantUML instance as `https://gitlab.example.com/-/plantuml/`, diff --git a/doc/administration/integration/terminal.md b/doc/administration/integration/terminal.md index df9bb6b6e17..bea389a8f0a 100644 --- a/doc/administration/integration/terminal.md +++ b/doc/administration/integration/terminal.md @@ -114,7 +114,7 @@ they receive a `Connection failed` message. By default, terminal sessions do not expire. To limit the terminal session lifetime in your GitLab instance: -1. On the top bar, select **Main menu > Admin**. -1. Select - [**Settings > Web terminal**](../../user/admin_area/settings/index.md#general). +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. +1. Select [**Settings > Web terminal**](../../user/admin_area/settings/index.md#general). 1. Set a `max session time`. diff --git a/doc/administration/maintenance_mode/index.md b/doc/administration/maintenance_mode/index.md index 8347015a8a3..3bbebe7ecce 100644 --- a/doc/administration/maintenance_mode/index.md +++ b/doc/administration/maintenance_mode/index.md @@ -21,7 +21,8 @@ Maintenance Mode allows most external actions that do not change internal state. Enable Maintenance Mode as an administrator in one of these ways: - **Web UI**: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Settings > General**. 1. Expand **Maintenance Mode**, and toggle **Enable Maintenance Mode**. You can optionally add a message for the banner as well. @@ -45,7 +46,8 @@ Enable Maintenance Mode as an administrator in one of these ways: Disable Maintenance Mode in one of three ways: - **Web UI**: - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Settings > General**. 1. Expand **Maintenance Mode**, and toggle **Enable Maintenance Mode**. You can optionally add a message for the banner as well. @@ -173,7 +175,8 @@ you should disable all cron jobs except for those related to Geo. To monitor queues and disable jobs: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. ### Incident management diff --git a/doc/administration/monitoring/performance/gitlab_configuration.md b/doc/administration/monitoring/performance/gitlab_configuration.md index cb5852a7dac..0d2037f3a92 100644 --- a/doc/administration/monitoring/performance/gitlab_configuration.md +++ b/doc/administration/monitoring/performance/gitlab_configuration.md @@ -9,7 +9,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w GitLab Performance Monitoring is disabled by default. To enable it and change any of its settings: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > Metrics and profiling** (`/admin/application_settings/metrics_and_profiling`). 1. Add the necessary configuration changes. diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md index 4045e06fbff..b448ac461c8 100644 --- a/doc/administration/monitoring/performance/grafana_configuration.md +++ b/doc/administration/monitoring/performance/grafana_configuration.md @@ -86,7 +86,8 @@ repository. After setting up Grafana, you can enable a link to access it from the GitLab sidebar: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > Metrics and profiling** and expand **Metrics - Grafana**. 1. Select the **Add a link to Grafana** checkbox. diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md index fc6318922f1..3fdd4c24177 100644 --- a/doc/administration/monitoring/performance/performance_bar.md +++ b/doc/administration/monitoring/performance/performance_bar.md @@ -108,7 +108,8 @@ The performance bar is disabled by default for non-administrators. To enable it for a given group: 1. Sign in as a user with administrator access. -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > Metrics and profiling** (`admin/application_settings/metrics_and_profiling`), and expand **Profiling - Performance bar**. diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md index 26b9fac8b79..5d6827b79ee 100644 --- a/doc/administration/monitoring/prometheus/gitlab_metrics.md +++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md @@ -9,7 +9,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w To enable the GitLab Prometheus metrics: 1. Log in to GitLab as a user with administrator access. -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > Metrics and profiling**. 1. Find the **Metrics - Prometheus** section, and select **Enable GitLab Prometheus metrics endpoint**. 1. [Restart GitLab](../../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect. diff --git a/doc/administration/operations/fast_ssh_key_lookup.md b/doc/administration/operations/fast_ssh_key_lookup.md index 1e887d8bd67..d54d286c19d 100644 --- a/doc/administration/operations/fast_ssh_key_lookup.md +++ b/doc/administration/operations/fast_ssh_key_lookup.md @@ -121,7 +121,8 @@ users as long as a large file exists. To disable writes to the `authorized_keys` file: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > Network**. 1. Expand **Performance optimization**. 1. Clear the **Use authorized_keys file to authenticate SSH keys** checkbox. @@ -140,7 +141,8 @@ This overview is brief. Refer to the above instructions for more context. 1. [Rebuild the `authorized_keys` file](../raketasks/maintenance.md#rebuild-authorized_keys-file). 1. Enable writes to the `authorized_keys` file. - 1. On the top bar, select **Main menu > Admin**. + 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). + 1. Select **Admin Area**. 1. On the left sidebar, select **Settings > Network**. 1. Expand **Performance optimization**. 1. Select the **Use authorized_keys file to authenticate SSH keys** checkbox. diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md index 53ae7046292..e3867a25846 100644 --- a/doc/administration/packages/container_registry.md +++ b/doc/administration/packages/container_registry.md @@ -325,7 +325,8 @@ the Container Registry by themselves, follow the steps below. In GitLab, tokens for the Container Registry expire every five minutes. To increase the token duration: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > CI/CD**. 1. Expand **Container Registry**. 1. For the **Authorization token duration (minutes)**, update the value. diff --git a/doc/administration/pages/source.md b/doc/administration/pages/source.md index b36b87f3b1d..2ee9dd653f0 100644 --- a/doc/administration/pages/source.md +++ b/doc/administration/pages/source.md @@ -483,7 +483,8 @@ The default for the maximum size of unpacked archives per project is 100 MB. To change this value: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Settings > Preferences**. 1. Expand **Pages**. 1. Update the value for **Maximum size of pages (MB)**. diff --git a/doc/administration/pages/troubleshooting.md b/doc/administration/pages/troubleshooting.md index 27322c2a537..e829943f270 100644 --- a/doc/administration/pages/troubleshooting.md +++ b/doc/administration/pages/troubleshooting.md @@ -170,7 +170,8 @@ Upgrading to an [officially supported operating system](https://about.gitlab.com This problem comes from the permissions of the GitLab Pages OAuth application. To fix it: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Applications > GitLab Pages**. 1. Edit the application. 1. Under **Scopes**, ensure that the `api` scope is selected. diff --git a/doc/administration/raketasks/storage.md b/doc/administration/raketasks/storage.md index d740aaa9c96..3664a79bf43 100644 --- a/doc/administration/raketasks/storage.md +++ b/doc/administration/raketasks/storage.md @@ -109,7 +109,8 @@ sudo gitlab-rake gitlab:storage:migrate_to_hashed ID_FROM=50 ID_TO=100 To monitor the progress in GitLab: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. 1. Watch how long the `hashed_storage:hashed_storage_project_migrate` queue takes to finish. After it reaches zero, you can confirm every project diff --git a/doc/administration/sidekiq/extra_sidekiq_processes.md b/doc/administration/sidekiq/extra_sidekiq_processes.md index 7959d1a5ce7..31e713bbf06 100644 --- a/doc/administration/sidekiq/extra_sidekiq_processes.md +++ b/doc/administration/sidekiq/extra_sidekiq_processes.md @@ -48,7 +48,8 @@ to all available queues: To view the Sidekiq processes in GitLab: -1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Background Jobs**. ## Concurrency diff --git a/doc/user/clusters/agent/vulnerabilities.md b/doc/user/clusters/agent/vulnerabilities.md index cb12b23bcfb..74676e31d22 100644 --- a/doc/user/clusters/agent/vulnerabilities.md +++ b/doc/user/clusters/agent/vulnerabilities.md @@ -15,11 +15,11 @@ You can also configure your agent so the vulnerabilities are displayed with othe ## Enable operational container scanning You can use operational container scanning to scan container images in your cluster for security vulnerabilities. You -can enable the scanner to run on a cadence as configured via the agent, or setup scan execution policies within a +can enable the scanner to run on a cadence as configured via the `agent config`, or setup `scan execution policies` within a project that houses the agent. NOTE: -In GitLab 15.0 and later, you do not need to install Starboard operator in the Kubernetes cluster. +If both `agent config` and `scan execution policies` are configured, the configuration from `scan execution policy` takes precedence. ### Enable via agent configuration @@ -56,7 +56,7 @@ container_scanning: - kube-system ``` -## Enable via scan execution policies +### Enable via scan execution policies To enable scanning of all images within your Kubernetes cluster via scan execution policies, we can use the [scan execution policy editor](../../application_security/policies/scan-execution-policies.md#scan-execution-policy-editor) @@ -96,6 +96,35 @@ The CRON expression is evaluated in [UTC](https://www.timeanddate.com/worldclock You can view the complete schema within the [scan execution policy documentation](../../application_security/policies/scan-execution-policies.md#scan-execution-policies-schema). +## Configure scanner resource requirements + +By default the scanner pod's default resource requirements are: + +```yaml +requests: + cpu: 100m + memory: 100Mi +limits: + cpu: 500m + memory: 500Mi +``` + +You can customize it with a `resource_requirements` field. + +```yaml +container_scanning: + resource_requirements: + requests: + cpu: 200m + memory: 200Mi + limits: + cpu: 700m + memory: 700Mi +``` + +NOTE: +Resource requirements can only be set up using the agent configuration. If you enabled `Operational Container Scanning` through `scan execution policies`, you would need to define the resource requirements within the agent configuration file. + ## View cluster vulnerabilities To view vulnerability information in GitLab: diff --git a/doc/user/project/integrations/telegram.md b/doc/user/project/integrations/telegram.md index d2e402d0bd0..fabea52629d 100644 --- a/doc/user/project/integrations/telegram.md +++ b/doc/user/project/integrations/telegram.md @@ -31,6 +31,8 @@ To configure the bot in Telegram: 1. Add the bot as an administrator to a new or existing channel. 1. Assign the bot `Post Messages` rights to receive events. 1. Create an identifier for the channel. + - For public channels, enter a public link and copy the channel identifier (for example, `https:/t.me/MY_IDENTIFIER`). + - For private channels, use the [`getUpdates`](https://telegram-bot-sdk.readme.io/reference/getupdates) method with your API token and copy the channel identifier. ## Set up the Telegram integration in GitLab @@ -47,8 +49,7 @@ After you invite the bot to a Telegram channel, you can configure GitLab to send 1. In **Enable integration**, select the **Active** checkbox. 1. In **New token**, [paste the token value from the Telegram bot](#create-a-telegram-bot). 1. In the **Trigger** section, select the checkboxes for the GitLab events you want to receive in Telegram. -1. In **Channel identifier**, [paste the channel identifier from the Telegram channel](#configure-the-telegram-bot). - - To get a private channel ID, use the [`getUpdates`](https://core.telegram.org/bots/api#getupdates) method. +1. In **Channel identifier**, [paste the Telegram channel identifier](#configure-the-telegram-bot). 1. Optional. Select **Test settings**. 1. Select **Save changes**. diff --git a/lib/gitlab/error_tracking/processor/grpc_error_processor.rb b/lib/gitlab/error_tracking/processor/grpc_error_processor.rb index c141398bee0..ab0df39e512 100644 --- a/lib/gitlab/error_tracking/processor/grpc_error_processor.rb +++ b/lib/gitlab/error_tracking/processor/grpc_error_processor.rb @@ -6,8 +6,7 @@ module Gitlab module GrpcErrorProcessor extend Gitlab::ErrorTracking::Processor::Concerns::ProcessesExceptions - # Braces added by gRPC Ruby code: https://github.com/grpc/grpc/blob/0e38b075ffff72ab2ad5326e3f60ba6dcc234f46/src/ruby/lib/grpc/errors.rb#L46 - DEBUG_ERROR_STRING_REGEX = RE2('(.*) debug_error_string:\{(.*)\}') + DEBUG_ERROR_STRING_REGEX = RE2('(.*) debug_error_string:(.*)') class << self def call(event) diff --git a/lib/gitlab/usage/metrics/instrumentations/count_personal_snippets_metric.rb b/lib/gitlab/usage/metrics/instrumentations/count_personal_snippets_metric.rb new file mode 100644 index 00000000000..9a34c535676 --- /dev/null +++ b/lib/gitlab/usage/metrics/instrumentations/count_personal_snippets_metric.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Gitlab + module Usage + module Metrics + module Instrumentations + class CountPersonalSnippetsMetric < DatabaseMetric + operation :count + + relation do + PersonalSnippet + end + end + end + end + end +end diff --git a/lib/gitlab/usage/metrics/instrumentations/count_project_snippets_metric.rb b/lib/gitlab/usage/metrics/instrumentations/count_project_snippets_metric.rb new file mode 100644 index 00000000000..af25a32592c --- /dev/null +++ b/lib/gitlab/usage/metrics/instrumentations/count_project_snippets_metric.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Gitlab + module Usage + module Metrics + module Instrumentations + class CountProjectSnippetsMetric < DatabaseMetric + operation :count + + relation do + ProjectSnippet + end + end + end + end + end +end diff --git a/lib/gitlab/usage/metrics/instrumentations/count_snippets_metric.rb b/lib/gitlab/usage/metrics/instrumentations/count_snippets_metric.rb new file mode 100644 index 00000000000..342ba802fd8 --- /dev/null +++ b/lib/gitlab/usage/metrics/instrumentations/count_snippets_metric.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Gitlab + module Usage + module Metrics + module Instrumentations + class CountSnippetsMetric < DatabaseMetric + operation :count + # Relation and operation are not used, but are included to satisfy expectations + # of other metric generation logic. + relation { Snippet } + + def value + count(project_snippet_relation) + count(personal_snippet_relation) + end + + def project_snippet_relation + ProjectSnippet.where(time_constraints) + end + + def personal_snippet_relation + PersonalSnippet.where(time_constraints) + end + + def to_sql + project_snippet_relation_sql = Gitlab::Usage::Metrics::Query.for(:count, project_snippet_relation) + personal_snippet_relation_sql = Gitlab::Usage::Metrics::Query.for(:count, personal_snippet_relation) + + "SELECT (#{project_snippet_relation_sql}) + (#{personal_snippet_relation_sql})" + end + end + end + end + end +end diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index ae6e111da62..3c810be04c8 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -122,8 +122,6 @@ module Gitlab protected_branches_except_default: count(ProtectedBranch.where.not(name: ['main', 'master', Gitlab::CurrentSettings.default_branch_name])), releases: count(Release), remote_mirrors: count(RemoteMirror), - personal_snippets: count(PersonalSnippet), - project_snippets: count(ProjectSnippet), suggestions: count(Suggestion), terraform_reports: count(::Ci::JobArtifact.of_report_type(:terraform)), terraform_states: count(::Terraform::State), @@ -137,9 +135,7 @@ module Gitlab integrations_usage, user_preferences_usage, service_desk_counts - ).tap do |data| - data[:snippets] = add(data[:personal_snippets], data[:project_snippets]) - end + ) } end # rubocop: enable Metrics/AbcSize @@ -154,12 +150,8 @@ module Gitlab # rubocop: enable UsageData/LargeTable: projects: count(Project.where(monthly_time_range_db_params), start: minimum_id(Project), finish: maximum_id(Project)), packages: count(::Packages::Package.where(monthly_time_range_db_params)), - personal_snippets: count(PersonalSnippet.where(monthly_time_range_db_params)), - project_snippets: count(ProjectSnippet.where(monthly_time_range_db_params)), projects_with_alerts_created: distinct_count(::AlertManagement::Alert.where(monthly_time_range_db_params), :project_id) - }.tap do |data| - data[:snippets] = add(data[:personal_snippets], data[:project_snippets]) - end + } } end # rubocop: enable CodeReuse/ActiveRecord diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 95c704dc06c..69a59255ae1 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -778,7 +778,10 @@ msgstr "" msgid "%{integrations_link_start}Integrations%{link_end} enable you to make third-party applications part of your GitLab workflow. If the available integrations don't meet your needs, consider using a %{webhooks_link_start}webhook%{link_end}." msgstr "" -msgid "%{issuableDisplayName} %{lockStatus}." +msgid "%{issuableDisplayName} locked." +msgstr "" + +msgid "%{issuableDisplayName} unlocked." msgstr "" msgid "%{issuableType} will be removed! Are you sure?" @@ -10009,6 +10012,9 @@ msgstr "" msgid "Close" msgstr "" +msgid "Close %{issuableType}" +msgstr "" + msgid "Close %{issueType}" msgstr "" @@ -10066,6 +10072,9 @@ msgstr "" msgid "Closes this issue. Marks as related to, and a duplicate of, %{duplicate_reference}." msgstr "" +msgid "Closing %{issuableType}..." +msgstr "" + msgid "Cloud Run" msgstr "" @@ -27391,6 +27400,9 @@ msgstr "" msgid "Locked the discussion." msgstr "" +msgid "Locking %{issuableDisplayName}" +msgstr "" + msgid "Locks the discussion." msgstr "" @@ -38334,6 +38346,9 @@ msgstr "" msgid "Reopen" msgstr "" +msgid "Reopen %{issuableType}" +msgstr "" + msgid "Reopen %{issueType}" msgstr "" @@ -38358,6 +38373,9 @@ msgstr "" msgid "Reopened this %{quick_action_target}." msgstr "" +msgid "Reopening %{issuableType}..." +msgstr "" + msgid "Reopening..." msgstr "" @@ -48681,7 +48699,7 @@ msgstr "" msgid "Unlock" msgstr "" -msgid "Unlock %{issuableType}" +msgid "Unlock %{issuableDisplayName}" msgstr "" msgid "Unlock account" @@ -48702,6 +48720,9 @@ msgstr "" msgid "Unlocked the discussion." msgstr "" +msgid "Unlocking %{issuableDisplayName}" +msgstr "" + msgid "Unlocks the discussion." msgstr "" @@ -54414,9 +54435,6 @@ msgstr "" msgid "loading" msgstr "" -msgid "locked" -msgstr "" - msgid "locked by %{path_lock_user_name} %{created_at}" msgstr "" @@ -55333,9 +55351,6 @@ msgstr "" msgid "unicode domains should use IDNA encoding" msgstr "" -msgid "unlocked" -msgstr "" - msgid "updated" msgstr "" diff --git a/spec/features/merge_request/close_reopen_report_toggle_spec.rb b/spec/features/merge_request/close_reopen_report_toggle_spec.rb index 9b8e50a31e3..07d9ddde910 100644 --- a/spec/features/merge_request/close_reopen_report_toggle_spec.rb +++ b/spec/features/merge_request/close_reopen_report_toggle_spec.rb @@ -15,6 +15,7 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle', feature_category: :code_r before do project.add_maintainer(user) login_as user + stub_feature_flags(moved_mr_sidebar: false) end context 'when user has permission to update', :js do @@ -24,15 +25,16 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle', feature_category: :code_r context 'close/reopen/report toggle' do it 'opens a dropdown when toggle is clicked' do - find('[data-testid="merge-request-actions"]').click + find('#new-actions-header-dropdown button').click - expect(container).to have_link("Close merge request") - expect(container).to have_button('Report abuse to administrator') + expect(container).to have_button("Close merge request") + expect(container).to have_button('Report abuse') end it 'links to Report Abuse' do - find('[data-testid="merge-request-actions"]').click - click_button 'Report abuse to administrator' + find('#new-actions-header-dropdown button').click + + click_button 'Report abuse' expect(page).to have_content('Report abuse to administrator') end @@ -42,13 +44,13 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle', feature_category: :code_r let(:issuable) { create(:merge_request, :opened, source_project: project) } it 'shows the `Edit` and `Mark as draft` buttons' do - find('[data-testid="merge-request-actions"]').click + find('#new-actions-header-dropdown button').click expect(container).to have_link('Edit') - expect(container).to have_link('Mark as draft') - expect(container).to have_link('Close merge request') - expect(container).to have_button('Report abuse to administrator') - expect(container).not_to have_link('Reopen merge request') + expect(container).to have_button('Mark as draft') + expect(container).to have_button('Close merge request') + expect(container).to have_button('Report abuse') + expect(container).not_to have_button('Reopen merge request') end end @@ -56,24 +58,24 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle', feature_category: :code_r let(:issuable) { create(:merge_request, :closed, source_project: project) } it 'shows both the `Edit` and `Reopen` button' do - find('[data-testid="merge-request-actions"]').click + find('#new-actions-header-dropdown button').click expect(container).to have_link('Edit') - expect(container).to have_button('Report abuse to administrator') - expect(container).to have_link('Reopen merge request') - expect(container).not_to have_link('Close merge request') + expect(container).to have_button('Report abuse') + expect(container).to have_button('Reopen merge request') + expect(container).not_to have_button('Close merge request') end context 'when the merge request author is the current user' do let(:issuable) { create(:merge_request, :closed, source_project: project, author: user) } it 'shows both the `Edit` and `Reopen` button' do - find('[data-testid="merge-request-actions"]').click + find('#new-actions-header-dropdown button').click expect(container).to have_link('Edit') - expect(container).to have_link('Reopen merge request') - expect(container).not_to have_link('Close merge request') - expect(container).not_to have_button('Report abuse to administrator') + expect(container).to have_button('Reopen merge request') + expect(container).not_to have_button('Close merge request') + expect(container).not_to have_button('Report abuse') end end end @@ -83,7 +85,7 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle', feature_category: :code_r it 'shows only the `Edit` button' do expect(container).to have_link(exact_text: 'Edit') - expect(container).not_to have_button('Report abuse to administrator') + expect(container).not_to have_button('Report abuse') expect(container).not_to have_button('Close merge request') expect(container).not_to have_button('Reopen merge request') end @@ -93,7 +95,7 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle', feature_category: :code_r it 'shows only the `Edit` button' do expect(container).to have_link(exact_text: 'Edit') - expect(container).not_to have_button('Report abuse to administrator') + expect(container).not_to have_button('Report abuse') expect(container).not_to have_button('Close merge request') expect(container).not_to have_button('Reopen merge request') end @@ -112,9 +114,9 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle', feature_category: :code_r end it 'only shows a `Report abuse` button' do - find('[data-testid="merge-request-actions"]').click + find('#new-actions-header-dropdown button').click - expect(container).to have_button('Report abuse to administrator') + expect(container).to have_button('Report abuse') expect(container).not_to have_button('Close merge request') expect(container).not_to have_button('Reopen merge request') expect(container).not_to have_link(exact_text: 'Edit') diff --git a/spec/features/merge_request/merge_request_discussion_lock_spec.rb b/spec/features/merge_request/merge_request_discussion_lock_spec.rb index 11ec2a86b43..782c4af58ac 100644 --- a/spec/features/merge_request/merge_request_discussion_lock_spec.rb +++ b/spec/features/merge_request/merge_request_discussion_lock_spec.rb @@ -90,7 +90,7 @@ RSpec.describe 'Merge Request Discussion Lock', :js, feature_category: :code_rev end it 'the user can lock the merge_request' do - find('[data-testid="merge-request-actions"]').click + find('#new-actions-header-dropdown button').click expect(page).to have_content('Lock merge request') end @@ -103,7 +103,7 @@ RSpec.describe 'Merge Request Discussion Lock', :js, feature_category: :code_rev end it 'the user can unlock the merge_request' do - find('[data-testid="merge-request-actions"]').click + find('#new-actions-header-dropdown button').click expect(page).to have_content('Unlock merge request') end diff --git a/spec/features/merge_request/user_manages_subscription_spec.rb b/spec/features/merge_request/user_manages_subscription_spec.rb index 3bcc8255ab7..84387965989 100644 --- a/spec/features/merge_request/user_manages_subscription_spec.rb +++ b/spec/features/merge_request/user_manages_subscription_spec.rb @@ -45,15 +45,15 @@ RSpec.describe 'User manages subscription', :js, feature_category: :code_review_ it 'toggles subscription' do wait_for_requests - find('[data-testid="merge-request-actions"]').click + find('#new-actions-header-dropdown button').click expect(page).to have_selector('.gl-toggle:not(.is-checked)') - find('[data-testid="notifications-toggle"] .gl-toggle').click + find('[data-testid="notification-toggle"] .gl-toggle').click wait_for_requests expect(page).to have_selector('.gl-toggle.is-checked') - find('[data-testid="notifications-toggle"] .gl-toggle').click + find('[data-testid="notification-toggle"] .gl-toggle').click wait_for_requests diff --git a/spec/features/merge_request/user_marks_merge_request_as_draft_spec.rb b/spec/features/merge_request/user_marks_merge_request_as_draft_spec.rb index 8cbc2b975e4..70962890bc5 100644 --- a/spec/features/merge_request/user_marks_merge_request_as_draft_spec.rb +++ b/spec/features/merge_request/user_marks_merge_request_as_draft_spec.rb @@ -16,15 +16,15 @@ RSpec.describe 'Merge request > User marks merge request as draft', :js, feature end it 'toggles draft status' do - find('[data-testid="merge-request-actions"]').click - click_link 'Mark as draft' + find('#new-actions-header-dropdown button').click + click_button 'Mark as draft' expect(page).to have_content("Draft: #{merge_request.title}") - find('[data-testid="merge-request-actions"]').click + find('#new-actions-header-dropdown button').click page.within('.detail-page-header-actions') do - click_link 'Mark as ready' + click_button 'Mark as ready' end expect(page).to have_content(merge_request.title) diff --git a/spec/frontend/merge_request_spec.js b/spec/frontend/merge_request_spec.js index 6f80f8e6aab..a119ca8272e 100644 --- a/spec/frontend/merge_request_spec.js +++ b/spec/frontend/merge_request_spec.js @@ -1,7 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import $ from 'jquery'; import htmlMergeRequestWithTaskList from 'test_fixtures/merge_requests/merge_request_with_task_list.html'; -import htmlMergeRequestOfCurrentUser from 'test_fixtures/merge_requests/merge_request_of_current_user.html'; import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; import { TEST_HOST } from 'spec/test_constants'; import waitForPromises from 'helpers/wait_for_promises'; @@ -110,20 +109,4 @@ describe('MergeRequest', () => { }); }); }); - - describe('hideCloseButton', () => { - describe('merge request of current_user', () => { - beforeEach(() => { - setHTMLFixture(htmlMergeRequestOfCurrentUser); - test.el = document.querySelector('.js-issuable-actions'); - MergeRequest.hideCloseButton(); - }); - - it('hides the close button', () => { - const smallCloseItem = test.el.querySelector('.js-close-item'); - - expect(smallCloseItem).toHaveClass('hidden'); - }); - }); - }); }); diff --git a/spec/frontend/sidebar/components/lock/issuable_lock_form_spec.js b/spec/frontend/sidebar/components/lock/issuable_lock_form_spec.js index 5e766e9a41c..47f68e1fe83 100644 --- a/spec/frontend/sidebar/components/lock/issuable_lock_form_spec.js +++ b/spec/frontend/sidebar/components/lock/issuable_lock_form_spec.js @@ -7,6 +7,7 @@ import createStore from '~/notes/stores'; import EditForm from '~/sidebar/components/lock/edit_form.vue'; import IssuableLockForm from '~/sidebar/components/lock/issuable_lock_form.vue'; import toast from '~/vue_shared/plugins/global_toast'; +import waitForPromises from 'helpers/wait_for_promises'; import { ISSUABLE_TYPE_ISSUE, ISSUABLE_TYPE_MR } from './constants'; jest.mock('~/vue_shared/plugins/global_toast'); @@ -27,6 +28,7 @@ describe('IssuableLockForm', () => { const findLockStatus = () => wrapper.find('[data-testid="lock-status"]'); const findEditLink = () => wrapper.find('[data-testid="edit-link"]'); const findEditForm = () => wrapper.findComponent(EditForm); + const findLockButton = () => wrapper.find('[data-testid="issuable-lock"]'); const findSidebarLockStatusTooltip = () => getBinding(findSidebarCollapseIcon().element, 'gl-tooltip'); const findIssuableLockClickable = () => wrapper.find('[data-testid="issuable-lock"]'); @@ -172,7 +174,9 @@ describe('IssuableLockForm', () => { createComponent({ movedMrSidebar: true }); - await wrapper.find('.dropdown-item').trigger('click'); + await findLockButton().trigger('click'); + + await waitForPromises(); expect(toast).toHaveBeenCalledWith(message); }); @@ -187,7 +191,7 @@ describe('IssuableLockForm', () => { }); describe('when the flag is on', () => { - it('does not show the non editable lock status', () => { + it('shows the non editable lock status', () => { createComponent({ movedMrSidebar: true }); expect(findIssuableLockClickable().exists()).toBe(true); }); diff --git a/spec/frontend/sidebar/components/subscriptions/sidebar_subscriptions_widget_spec.js b/spec/frontend/sidebar/components/subscriptions/sidebar_subscriptions_widget_spec.js index 7275557e7f2..39b80c1d886 100644 --- a/spec/frontend/sidebar/components/subscriptions/sidebar_subscriptions_widget_spec.js +++ b/spec/frontend/sidebar/components/subscriptions/sidebar_subscriptions_widget_spec.js @@ -1,4 +1,4 @@ -import { GlIcon, GlToggle } from '@gitlab/ui'; +import { GlDisclosureDropdownItem, GlIcon, GlToggle } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; @@ -28,6 +28,7 @@ describe('Sidebar Subscriptions Widget', () => { const findEditableItem = () => wrapper.findComponent(SidebarEditableItem); const findToggle = () => wrapper.findComponent(GlToggle); const findIcon = () => wrapper.findComponent(GlIcon); + const findDropdownToggleItem = () => wrapper.findComponent(GlDisclosureDropdownItem); const createComponent = ({ subscriptionsQueryHandler = jest.fn().mockResolvedValue(issueSubscriptionsResponse()), @@ -155,7 +156,7 @@ describe('Sidebar Subscriptions Widget', () => { }); await waitForPromises(); - await wrapper.find('[data-testid="notifications-toggle"]').vm.$emit('change'); + await findDropdownToggleItem().vm.$emit('action'); await waitForPromises(); diff --git a/spec/frontend/vue_shared/components/mr_more_dropdown_spec.js b/spec/frontend/vue_shared/components/mr_more_dropdown_spec.js new file mode 100644 index 00000000000..41639725f66 --- /dev/null +++ b/spec/frontend/vue_shared/components/mr_more_dropdown_spec.js @@ -0,0 +1,137 @@ +import { shallowMount } from '@vue/test-utils'; +import MRMoreActionsDropdown from '~/vue_shared/components/mr_more_dropdown.vue'; + +describe('MR More actions sidebar', () => { + let wrapper; + + const findNotificationToggle = () => wrapper.find('[data-testid="notification-toggle"]'); + const findEditMergeRequestOption = () => wrapper.find('[data-testid="edit-merge-request"]'); + const findMarkAsReadyAndDraftOption = () => + wrapper.find('[data-testid="ready-and-draft-action"]'); + const findCopyReferenceButton = () => wrapper.find('[data-testid="copy-reference"]'); + const findReopenMergeRequestOption = () => wrapper.find('[data-testid="reopen-merge-request"]'); + const findReportAbuseOption = () => wrapper.find('[data-testid="report-abuse-option"]'); + + const createComponent = ({ + movedMrSidebarFlag = false, + isCurrentUser = true, + isLoggedIn = true, + open = false, + canUpdateMergeRequest = false, + } = {}) => { + wrapper = shallowMount(MRMoreActionsDropdown, { + propsData: { + mr: { + iid: 1, + }, + isCurrentUser, + isLoggedIn, + open, + canUpdateMergeRequest, + }, + provide: { + glFeatures: { movedMrSidebar: movedMrSidebarFlag }, + }, + }); + }; + + describe('Notifications toggle', () => { + it.each` + movedMrSidebarFlag | isLoggedIn | showNotificationToggle + ${false} | ${false} | ${false} + ${false} | ${true} | ${false} + ${true} | ${false} | ${false} + ${true} | ${true} | ${true} + `( + "when the movedMrSidebar flag is '$movedMrSidebarFlag' and is isLoggedIn as '$isLoggedIn'", + ({ movedMrSidebarFlag, isLoggedIn, showNotificationToggle }) => { + createComponent({ + isLoggedIn, + movedMrSidebarFlag, + }); + + expect(findNotificationToggle().exists()).toBe(showNotificationToggle); + }, + ); + }); + + describe('Edit/Draft/Reopen MR', () => { + it('should not have the edit option when `canUpdateMergeRequest` is false', () => { + createComponent(); + + expect(findEditMergeRequestOption().exists()).toBe(false); + }); + + it('should have the edit option when `canUpdateMergeRequest` is true', () => { + createComponent({ + canUpdateMergeRequest: true, + }); + + expect(findEditMergeRequestOption().exists()).toBe(true); + }); + + it('should not have the ready and draft option when the the MR is open and `canUpdateMergeRequest` is false', () => { + createComponent({ + open: true, + canUpdateMergeRequest: false, + }); + + expect(findMarkAsReadyAndDraftOption().exists()).toBe(false); + }); + + it('should have the ready and draft option when the the MR is open and `canUpdateMergeRequest` is true', () => { + createComponent({ + open: true, + canUpdateMergeRequest: true, + }); + + expect(findMarkAsReadyAndDraftOption().exists()).toBe(true); + }); + + it('should have the reopen option when the the MR is closed and `canUpdateMergeRequest` is true', () => { + createComponent({ + open: false, + canUpdateMergeRequest: true, + }); + + expect(findReopenMergeRequestOption().exists()).toBe(true); + }); + + it('should not have the reopen option when the the MR is closed and `canUpdateMergeRequest` is false', () => { + createComponent({ + open: false, + canUpdateMergeRequest: false, + }); + + expect(findReopenMergeRequestOption().exists()).toBe(false); + }); + }); + + describe('Copy reference', () => { + it('should not be visible by default', () => { + createComponent(); + + expect(findCopyReferenceButton().exists()).toBe(false); + }); + + it('should be visible when the movedMrSidebarFlag is on', () => { + createComponent({ movedMrSidebarFlag: true }); + + expect(findCopyReferenceButton().exists()).toBe(true); + }); + }); + + describe('Report abuse action', () => { + it('should not have the option by default', () => { + createComponent(); + + expect(findReportAbuseOption().exists()).toBe(false); + }); + + it('should have the option when not the current user', () => { + createComponent({ isCurrentUser: false }); + + expect(findReportAbuseOption().exists()).toBe(true); + }); + }); +}); diff --git a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js index 9b6f5ae3e38..a27877e7ba8 100644 --- a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js +++ b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js @@ -94,16 +94,15 @@ describe('AlertManagementEmptyState', () => { const ItemsTable = () => wrapper.find('.gl-table'); const ErrorAlert = () => wrapper.findComponent(GlAlert); const Pagination = () => wrapper.findComponent(GlPagination); - const Tabs = () => wrapper.findComponent(GlTabs); const ActionButton = () => wrapper.find('.header-actions > button'); - const Filters = () => wrapper.findComponent(FilteredSearchBar); + const findFilteredSearchBar = () => wrapper.findComponent(FilteredSearchBar); const findPagination = () => wrapper.findComponent(GlPagination); const findStatusFilterTabs = () => wrapper.findAllComponents(GlTab); const findStatusTabs = () => wrapper.findComponent(GlTabs); const findStatusFilterBadge = () => wrapper.findAllComponents(GlBadge); const handleFilterItems = (filters) => { - Filters().vm.$emit('onFilter', filters); + findFilteredSearchBar().vm.$emit('onFilter', filters); return nextTick(); }; @@ -140,7 +139,7 @@ describe('AlertManagementEmptyState', () => { }, }); - expect(Tabs().exists()).toBe(true); + expect(findStatusTabs().exists()).toBe(true); }); it('renders the header action buttons if present', () => { @@ -176,7 +175,7 @@ describe('AlertManagementEmptyState', () => { props: { filterSearchTokens: [TOKEN_TYPE_ASSIGNEE] }, }); - expect(Filters().exists()).toBe(true); + expect(findFilteredSearchBar().exists()).toBe(true); }); }); @@ -291,8 +290,9 @@ describe('AlertManagementEmptyState', () => { }); it('renders the search component for incidents', () => { - expect(Filters().props('searchInputPlaceholder')).toBe('Search or filter results…'); - expect(Filters().props('tokens')).toEqual([ + const filteredSearchBar = findFilteredSearchBar(); + expect(filteredSearchBar.props('searchInputPlaceholder')).toBe('Search or filter results…'); + expect(filteredSearchBar.props('tokens')).toEqual([ { type: TOKEN_TYPE_AUTHOR, icon: 'user', @@ -316,14 +316,14 @@ describe('AlertManagementEmptyState', () => { fetchUsers: expect.any(Function), }, ]); - expect(Filters().props('recentSearchesStorageKey')).toBe('items'); + expect(filteredSearchBar.props('recentSearchesStorageKey')).toBe('items'); }); it('returns correctly applied filter search values', async () => { const searchTerm = 'foo'; await handleFilterItems([{ type: 'filtered-search-term', value: { data: searchTerm } }]); await nextTick(); - expect(Filters().props('initialFilterValue')).toEqual([searchTerm]); + expect(findFilteredSearchBar().props('initialFilterValue')).toEqual([searchTerm]); }); it('updates props tied to getIncidents GraphQL query', async () => { @@ -337,7 +337,7 @@ describe('AlertManagementEmptyState', () => { value: { data: assigneeUsername }, }, searchTerm, - ] = Filters().props('initialFilterValue'); + ] = findFilteredSearchBar().props('initialFilterValue'); expect(authorUsername).toBe('root'); expect(assigneeUsername).toEqual('root2'); @@ -346,7 +346,7 @@ describe('AlertManagementEmptyState', () => { it('updates props `searchTerm` and `authorUsername` with empty values when passed filters param is empty', async () => { await handleFilterItems([]); - expect(Filters().props('initialFilterValue')).toEqual([]); + expect(findFilteredSearchBar().props('initialFilterValue')).toEqual([]); }); }); }); diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_personal_snippets_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_personal_snippets_metric_spec.rb new file mode 100644 index 00000000000..cfd2fcabae6 --- /dev/null +++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_personal_snippets_metric_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountPersonalSnippetsMetric, feature_category: :service_ping do + before_all do + create(:personal_snippet, created_at: 5.days.ago) + create(:personal_snippet, created_at: 1.year.ago) + end + + context 'with a time_frame of 28 days' do + let(:expected_value) { 1 } + + it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', data_source: 'database' } + end + + context 'with a timeframe of all' do + let(:expected_value) { 2 } + + it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' } + end +end diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_project_snippets_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_project_snippets_metric_spec.rb new file mode 100644 index 00000000000..a82726ccf44 --- /dev/null +++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_project_snippets_metric_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountProjectSnippetsMetric, feature_category: :service_ping do + before_all do + create(:project_snippet, created_at: 5.days.ago) + create(:project_snippet, created_at: 1.year.ago) + end + + context 'with a time_frame of 28 days' do + let(:expected_value) { 1 } + + it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', data_source: 'database' } + end + + context 'with a timeframe of all' do + let(:expected_value) { 2 } + + it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' } + end +end diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_snippets_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_snippets_metric_spec.rb new file mode 100644 index 00000000000..daacea83833 --- /dev/null +++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_snippets_metric_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountSnippetsMetric, feature_category: :service_ping do + before_all do + create(:personal_snippet, created_at: 5.days.ago) + create(:personal_snippet, created_at: 1.year.ago) + + create(:project_snippet, created_at: 1.year.ago) + create(:project_snippet, created_at: 5.days.ago) + end + + context 'with a time_frame of 28 days' do + let(:expected_value) { 2 } + + it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', data_source: 'database' } + end + + context 'with a timeframe of all' do + let(:expected_value) { 4 } + + it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' } + end +end diff --git a/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb b/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb index 271e9595703..5002ee7599f 100644 --- a/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb +++ b/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb @@ -68,6 +68,10 @@ RSpec.describe Gitlab::Usage::Metrics::NamesSuggestions::Generator, feature_cate end context 'for add metrics' do + before do + pending 'https://gitlab.com/gitlab-org/gitlab/-/issues/414887' + end + it_behaves_like 'name suggestion' do # corresponding metric is collected with add(data[:personal_snippets], data[:project_snippets]) let(:key_path) { 'counts.snippets' } diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 72147721b4e..ae3635fb5b1 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -574,9 +574,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic expect(count_data[:successful_deployments]).to eq(2) expect(count_data[:failed_deployments]).to eq(2) expect(count_data[:feature_flags]).to eq(1) - expect(count_data[:snippets]).to eq(6) - expect(count_data[:personal_snippets]).to eq(2) - expect(count_data[:project_snippets]).to eq(4) expect(count_data[:projects_creating_incidents]).to eq(2) expect(count_data[:projects_with_packages]).to eq(2) @@ -636,8 +633,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic deployment_options = { created_at: n.days.ago, project: env.project, environment: env } create(:deployment, :failed, deployment_options) create(:deployment, :success, deployment_options) - create(:project_snippet, project: project, created_at: n.days.ago) - create(:personal_snippet, created_at: n.days.ago) create(:alert_management_alert, project: project, created_at: n.days.ago) end @@ -654,9 +649,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic expect(counts_monthly[:deployments]).to eq(2) expect(counts_monthly[:successful_deployments]).to eq(1) expect(counts_monthly[:failed_deployments]).to eq(1) - expect(counts_monthly[:snippets]).to eq(2) - expect(counts_monthly[:personal_snippets]).to eq(1) - expect(counts_monthly[:project_snippets]).to eq(1) expect(counts_monthly[:projects_with_alerts_created]).to eq(1) expect(counts_monthly[:projects]).to eq(1) expect(counts_monthly[:packages]).to eq(1) diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb index a1c25338312..050a2780af4 100644 --- a/spec/support/helpers/usage_data_helpers.rb +++ b/spec/support/helpers/usage_data_helpers.rb @@ -70,9 +70,6 @@ module UsageDataHelpers protected_branches_except_default releases remote_mirrors - snippets - personal_snippets - project_snippets suggestions terraform_reports terraform_states diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index 96cdf5adec8..354d175d825 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -9923,7 +9923,6 @@ - './spec/views/projects/merge_requests/_commits.html.haml_spec.rb' - './spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb' - './spec/views/projects/merge_requests/edit.html.haml_spec.rb' -- './spec/views/projects/merge_requests/show.html.haml_spec.rb' - './spec/views/projects/milestones/index.html.haml_spec.rb' - './spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb' - './spec/views/projects/pages_domains/show.html.haml_spec.rb' diff --git a/spec/support/shared_contexts/issuable/merge_request_shared_context.rb b/spec/support/shared_contexts/issuable/merge_request_shared_context.rb deleted file mode 100644 index 35c1511c96a..00000000000 --- a/spec/support/shared_contexts/issuable/merge_request_shared_context.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -RSpec.shared_context 'merge request show action' do - include Features::MergeRequestHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, :public, :repository) } - let_it_be(:merge_request) { create(:merge_request, :opened, source_project: project, author: user) } - let_it_be(:note) { create(:note_on_merge_request, project: project, noteable: merge_request) } - - before do - allow(view).to receive(:experiment_enabled?).and_return(false) - allow(view).to receive(:current_user).and_return(user) - allow(view).to receive(:can_admin_project_member?) - assign(:project, project) - assign(:merge_request, merge_request) - assign(:note, note) - assign(:noteable, merge_request) - assign(:number_of_pipelines, 0) - assign(:issuable_sidebar, serialize_issuable_sidebar(user, project, merge_request)) - - preload_view_requirements(merge_request, note) - end -end diff --git a/spec/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml_spec.rb b/spec/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml_spec.rb deleted file mode 100644 index 99339e956cc..00000000000 --- a/spec/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'projects/merge_requests/_close_reopen_draft_report_toggle.html.haml' do - let_it_be(:merge_request) { create(:merge_request, state: :merged) } - - before do - assign(:merge_request, merge_request) - assign(:project, merge_request.target_project) - - allow(view).to receive(:moved_mr_sidebar_enabled?).and_return(true) - end - - describe 'notifcations toggle' do - context 'when mr merged and logged in' do - it 'is present' do - allow(view).to receive(:current_user).and_return(merge_request.author) - - render - - expect(rendered).to have_css('li', class: 'js-sidebar-subscriptions-widget-root') - end - end - - context 'when mr merged and not logged in' do - it 'is not present' do - render - - expect(rendered).not_to have_css('li', class: 'js-sidebar-subscriptions-widget-root') - end - end - end -end diff --git a/spec/views/projects/merge_requests/show.html.haml_spec.rb b/spec/views/projects/merge_requests/show.html.haml_spec.rb deleted file mode 100644 index 86a4b25f746..00000000000 --- a/spec/views/projects/merge_requests/show.html.haml_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'projects/merge_requests/show.html.haml', :aggregate_failures do - using RSpec::Parameterized::TableSyntax - - include_context 'merge request show action' - - before do - merge_request.reload - end - - context 'when the merge request is open' do - it 'shows the "Mark as draft" button' do - render - - expect(rendered).to have_css('a', visible: true, text: 'Mark as draft') - expect(rendered).to have_css('a', visible: true, text: 'Close') - end - end - - context 'when the merge request is closed' do - before do - merge_request.close! - end - - it 'shows the "Reopen" button' do - render - - expect(rendered).not_to have_css('a', visible: true, text: 'Mark as draft') - expect(rendered).to have_css('a', visible: true, text: 'Reopen') - end - - context 'when source project does not exist' do - it 'does not show the "Reopen" button' do - allow(merge_request).to receive(:source_project).and_return(nil) - - render - - expect(rendered).not_to have_css('a', visible: false, text: 'Reopen') - end - end - end -end |