diff options
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/mr_more_dropdown.vue')
-rw-r--r-- | app/assets/javascripts/vue_shared/components/mr_more_dropdown.vue | 361 |
1 files changed, 361 insertions, 0 deletions
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> |