diff options
Diffstat (limited to 'app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue')
-rw-r--r-- | app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue | 80 |
1 files changed, 77 insertions, 3 deletions
diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue index 3d8a2cd847c..6c615109bb8 100644 --- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue +++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue @@ -9,6 +9,8 @@ import { GlLoadingIcon, GlIcon, GlTooltipDirective, + GlPopover, + GlButton, } from '@gitlab/ui'; import { kebabCase, snakeCase } from 'lodash'; import createFlash from '~/flash'; @@ -17,6 +19,7 @@ import { IssuableType } from '~/issues/constants'; import { timeFor } from '~/lib/utils/datetime_utility'; import { __ } from '~/locale'; import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { dropdowni18nText, Tracking, @@ -47,7 +50,10 @@ export default { GlSearchBoxByType, GlIcon, GlLoadingIcon, + GlPopover, + GlButton, }, + mixins: [glFeatureFlagMixin()], inject: { isClassicSidebar: { default: false, @@ -66,6 +72,7 @@ export default { }, }, }, + props: { issuableAttribute: { type: String, @@ -111,6 +118,10 @@ export default { }; }, update(data) { + if (this.glFeatures?.epicWidgetEditConfirmation && this.isEpic) { + this.hasCurrentAttribute = data?.workspace?.issuable.hasEpic; + } + return data?.workspace?.issuable.attribute; }, error(error) { @@ -179,6 +190,8 @@ export default { updating: false, selectedTitle: null, currentAttribute: null, + hasCurrentAttribute: false, + editConfirmation: false, attributesList: [], tracking: { event: Tracking.editEvent, @@ -228,6 +241,15 @@ export default { snake: snakeCase(this.issuableAttribute), }; }, + shouldShowConfirmationPopover() { + if (!this.glFeatures?.epicWidgetEditConfirmation) { + return false; + } + + return this.isEpic && this.currentAttribute === null && this.hasCurrentAttribute + ? !this.editConfirmation + : false; + }, }, methods: { updateAttribute(attributeId) { @@ -299,6 +321,17 @@ export default { setFocus() { this.$refs.search.focusInput(); }, + handlePopoverClose() { + this.$refs.popover.$emit('close'); + }, + handlePopoverConfirm(cb) { + this.editConfirmation = true; + this.handlePopoverClose(); + setTimeout(cb, 0); + }, + handleEditConfirmation() { + this.$refs.popover.$emit('open'); + }, }, }; </script> @@ -308,10 +341,13 @@ export default { ref="editable" :title="attributeTypeTitle" :data-testid="`${formatIssuableAttribute.kebab}-edit`" + :button-id="`${formatIssuableAttribute.kebab}-edit`" :tracking="tracking" + :should-show-confirmation-popover="shouldShowConfirmationPopover" :loading="updating || loading" @open="handleOpen" @close="handleClose" + @edit-confirm="handleEditConfirmation" > <template #collapsed> <slot name="value-collapsed" :current-attribute="currentAttribute"> @@ -332,6 +368,10 @@ export default { :class="isClassicSidebar ? 'hide-collapsed' : 'gl-mt-3'" > <span v-if="updating">{{ selectedTitle }}</span> + <template v-else-if="!currentAttribute && hasCurrentAttribute"> + <gl-icon name="warning" class="gl-text-orange-500" /> + <span class="gl-text-gray-500">{{ i18n.noPermissionToView }}</span> + </template> <span v-else-if="!currentAttribute" class="gl-text-gray-500"> {{ $options.i18n.none }} </span> @@ -344,6 +384,7 @@ export default { > <gl-link v-gl-tooltip="tooltipText" + class="gl-reset-color gl-hover-text-blue-800" :href="attributeUrl" :data-qa-selector="`${formatIssuableAttribute.snake}_link`" > @@ -353,7 +394,40 @@ export default { </slot> </div> </template> - <template #default> + <template v-if="shouldShowConfirmationPopover" #default="{ toggle }"> + <gl-popover + ref="popover" + :target="`${formatIssuableAttribute.kebab}-edit`" + placement="bottomleft" + boundary="viewport" + triggers="click" + > + <div class="gl-mb-4 gl-font-base"> + {{ i18n.editConfirmation }} + </div> + <div class="gl-display-flex gl-align-items-center"> + <gl-button + size="small" + variant="confirm" + category="primary" + data-testid="confirm-edit-cta" + @click.prevent="() => handlePopoverConfirm(toggle)" + >{{ i18n.editConfirmationCta }}</gl-button + > + <gl-button + class="gl-ml-auto" + size="small" + name="cancel" + variant="default" + category="primary" + data-testid="confirm-edit-cancel" + @click.prevent="handlePopoverClose" + >{{ i18n.editConfirmationCancel }}</gl-button + > + </div> + </gl-popover> + </template> + <template v-else #default> <gl-dropdown ref="newDropdown" lazy @@ -368,7 +442,7 @@ export default { <gl-search-box-by-type ref="search" v-model="searchTerm" /> <gl-dropdown-item :data-testid="`no-${formatIssuableAttribute.kebab}-item`" - :is-check-item="true" + is-check-item :is-checked="isAttributeChecked($options.noAttributeId)" @click="updateAttribute($options.noAttributeId)" > @@ -395,7 +469,7 @@ export default { <gl-dropdown-item v-for="attrItem in attributesList" :key="attrItem.id" - :is-check-item="true" + is-check-item :is-checked="isAttributeChecked(attrItem.id)" :data-testid="`${formatIssuableAttribute.kebab}-items`" @click="updateAttribute(attrItem.id)" |