diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-04-20 10:00:54 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-04-20 10:00:54 +0000 |
commit | 3cccd102ba543e02725d247893729e5c73b38295 (patch) | |
tree | f36a04ec38517f5deaaacb5acc7d949688d1e187 /app/assets/javascripts/work_items/components | |
parent | 205943281328046ef7b4528031b90fbda70c75ac (diff) | |
download | gitlab-ce-3cccd102ba543e02725d247893729e5c73b38295.tar.gz |
Add latest changes from gitlab-org/gitlab@14-10-stable-eev14.10.0-rc42
Diffstat (limited to 'app/assets/javascripts/work_items/components')
5 files changed, 291 insertions, 43 deletions
diff --git a/app/assets/javascripts/work_items/components/item_title.vue b/app/assets/javascripts/work_items/components/item_title.vue index 79840cc4f0f..232510b108d 100644 --- a/app/assets/javascripts/work_items/components/item_title.vue +++ b/app/assets/javascripts/work_items/components/item_title.vue @@ -2,12 +2,9 @@ import { escape } from 'lodash'; import { __ } from '~/locale'; -import { WI_TITLE_TRACK_LABEL } from '../constants'; - export default { - WI_TITLE_TRACK_LABEL, props: { - initialTitle: { + title: { type: String, required: false, default: '', @@ -23,11 +20,6 @@ export default { default: false, }, }, - data() { - return { - title: this.initialTitle, - }; - }, methods: { getSanitizedTitle(inputEl) { const { innerText } = inputEl; @@ -50,7 +42,6 @@ export default { <h2 class="gl-font-weight-normal gl-sm-font-weight-bold gl-my-5 gl-display-inline-block" :class="{ 'gl-cursor-not-allowed': disabled }" - data-testid="title" aria-labelledby="item-title" > <span @@ -59,7 +50,6 @@ export default { role="textbox" :aria-label="__('Title')" :data-placeholder="placeholder" - :data-track-label="$options.WI_TITLE_TRACK_LABEL" :contenteditable="!disabled" class="gl-pseudo-placeholder" @blur="handleBlur" diff --git a/app/assets/javascripts/work_items/components/work_item_actions.vue b/app/assets/javascripts/work_items/components/work_item_actions.vue new file mode 100644 index 00000000000..40b6fcdd204 --- /dev/null +++ b/app/assets/javascripts/work_items/components/work_item_actions.vue @@ -0,0 +1,93 @@ +<script> +import { GlDropdown, GlDropdownItem, GlModal, GlModalDirective } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import deleteWorkItemMutation from '../graphql/delete_work_item.mutation.graphql'; + +export default { + i18n: { + deleteWorkItem: s__('WorkItem|Delete work item'), + }, + components: { + GlDropdown, + GlDropdownItem, + GlModal, + }, + directives: { + GlModal: GlModalDirective, + }, + props: { + workItemId: { + type: String, + required: false, + default: null, + }, + canUpdate: { + type: Boolean, + required: false, + default: false, + }, + }, + emits: ['workItemDeleted', 'error'], + methods: { + deleteWorkItem() { + this.$apollo + .mutate({ + mutation: deleteWorkItemMutation, + variables: { + input: { + id: this.workItemId, + }, + }, + }) + .then(({ data: { workItemDelete, errors } }) => { + if (errors?.length) { + throw new Error(errors[0].message); + } + + if (workItemDelete?.errors.length) { + throw new Error(workItemDelete.errors[0]); + } + + this.$emit('workItemDeleted'); + }) + .catch((e) => { + this.$emit( + 'error', + e.message || + s__('WorkItem|Something went wrong when deleting the work item. Please try again.'), + ); + }); + }, + }, +}; +</script> + +<template> + <div v-if="canUpdate"> + <gl-dropdown + icon="ellipsis_v" + text-sr-only + :text="__('More actions')" + category="tertiary" + no-caret + right + > + <gl-dropdown-item v-gl-modal="'work-item-confirm-delete'">{{ + $options.i18n.deleteWorkItem + }}</gl-dropdown-item> + </gl-dropdown> + <gl-modal + modal-id="work-item-confirm-delete" + :title="$options.i18n.deleteWorkItem" + :ok-title="$options.i18n.deleteWorkItem" + ok-variant="danger" + @ok="deleteWorkItem" + > + {{ + s__( + 'WorkItem|Are you sure you want to delete the work item? This action cannot be reversed.', + ) + }} + </gl-modal> + </div> +</template> diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue new file mode 100644 index 00000000000..f2fb1e3ccbc --- /dev/null +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -0,0 +1,73 @@ +<script> +import { GlAlert } from '@gitlab/ui'; +import { i18n } from '../constants'; +import workItemQuery from '../graphql/work_item.query.graphql'; +import workItemTitleSubscription from '../graphql/work_item_title.subscription.graphql'; +import WorkItemTitle from './work_item_title.vue'; + +export default { + i18n, + components: { + GlAlert, + WorkItemTitle, + }, + props: { + workItemId: { + type: String, + required: false, + default: null, + }, + }, + data() { + return { + error: undefined, + workItem: {}, + }; + }, + apollo: { + workItem: { + query: workItemQuery, + variables() { + return { + id: this.workItemId, + }; + }, + skip() { + return !this.workItemId; + }, + error() { + this.error = this.$options.i18n.fetchError; + }, + subscribeToMore: { + document: workItemTitleSubscription, + variables() { + return { + issuableId: this.workItemId, + }; + }, + }, + }, + }, + computed: { + workItemType() { + return this.workItem.workItemType?.name; + }, + }, +}; +</script> + +<template> + <section> + <gl-alert v-if="error" variant="danger" @dismiss="error = undefined"> + {{ error }} + </gl-alert> + + <work-item-title + :loading="$apollo.queries.workItem.loading" + :work-item-id="workItem.id" + :work-item-title="workItem.title" + :work-item-type="workItemType" + @error="error = $event" + /> + </section> +</template> diff --git a/app/assets/javascripts/work_items/components/work_item_detail_modal.vue b/app/assets/javascripts/work_items/components/work_item_detail_modal.vue index 942677bb937..a79091fb8b2 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail_modal.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail_modal.vue @@ -1,15 +1,22 @@ <script> -import { GlModal } from '@gitlab/ui'; -import { s__ } from '~/locale'; -import workItemQuery from '../graphql/work_item.query.graphql'; -import ItemTitle from './item_title.vue'; +import { GlAlert, GlButton, GlModal } from '@gitlab/ui'; +import WorkItemActions from './work_item_actions.vue'; +import WorkItemDetail from './work_item_detail.vue'; export default { components: { + GlAlert, + GlButton, GlModal, - ItemTitle, + WorkItemDetail, + WorkItemActions, }, props: { + canUpdate: { + type: Boolean, + required: false, + default: false, + }, visible: { type: Boolean, required: true, @@ -20,43 +27,55 @@ export default { default: null, }, }, + emits: ['workItemDeleted', 'close'], data() { return { - workItem: {}, + error: undefined, }; }, - apollo: { - workItem: { - query: workItemQuery, - variables() { - return { - id: this.workItemId, - }; - }, - update(data) { - return data.workItem; - }, - skip() { - return !this.workItemId; - }, - error() { - this.$emit( - 'error', - s__('WorkItem|Something went wrong when fetching the work item. Please try again.'), - ); - }, + methods: { + handleWorkItemDeleted() { + this.$emit('workItemDeleted'); + this.closeModal(); }, - }, - computed: { - workItemTitle() { - return this.workItem?.title; + closeModal() { + this.error = ''; + this.$emit('close'); + }, + setErrorMessage(message) { + this.error = message; }, }, }; </script> <template> - <gl-modal hide-footer modal-id="work-item-detail-modal" :visible="visible" @hide="$emit('close')"> - <item-title class="gl-m-0!" :initial-title="workItemTitle" /> + <gl-modal hide-footer modal-id="work-item-detail-modal" :visible="visible" @hide="closeModal"> + <template #modal-header> + <div class="gl-w-full gl-display-flex gl-align-items-center gl-justify-content-end"> + <h2 class="modal-title gl-mr-auto">{{ s__('WorkItem|Work Item') }}</h2> + <work-item-actions + :work-item-id="workItemId" + :can-update="canUpdate" + @workItemDeleted="handleWorkItemDeleted" + @error="setErrorMessage" + /> + <gl-button category="tertiary" icon="close" :aria-label="__('Close')" @click="closeModal" /> + </div> + </template> + <gl-alert v-if="error" variant="danger" @dismiss="error = false"> + {{ error }} + </gl-alert> + + <work-item-detail :work-item-id="workItemId" /> </gl-modal> </template> + +<style> +/* hide the existing close button until we can do it + * with https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2710 + */ +#work-item-detail-modal .modal-header > .gl-button { + display: none; +} +</style> diff --git a/app/assets/javascripts/work_items/components/work_item_title.vue b/app/assets/javascripts/work_items/components/work_item_title.vue new file mode 100644 index 00000000000..88a825853cc --- /dev/null +++ b/app/assets/javascripts/work_items/components/work_item_title.vue @@ -0,0 +1,73 @@ +<script> +import { GlLoadingIcon } from '@gitlab/ui'; +import Tracking from '~/tracking'; +import { i18n } from '../constants'; +import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql'; +import ItemTitle from './item_title.vue'; + +export default { + components: { + GlLoadingIcon, + ItemTitle, + }, + mixins: [Tracking.mixin()], + props: { + loading: { + type: Boolean, + required: false, + default: false, + }, + workItemId: { + type: String, + required: false, + default: '', + }, + workItemTitle: { + type: String, + required: false, + default: '', + }, + workItemType: { + type: String, + required: false, + default: '', + }, + }, + computed: { + tracking() { + return { + category: 'workItems:show', + label: 'item_title', + property: `type_${this.workItemType}`, + }; + }, + }, + methods: { + async updateTitle(updatedTitle) { + if (updatedTitle === this.workItemTitle) { + return; + } + + try { + await this.$apollo.mutate({ + mutation: updateWorkItemMutation, + variables: { + input: { + id: this.workItemId, + title: updatedTitle, + }, + }, + }); + this.track('updated_title'); + } catch { + this.$emit('error', i18n.updateError); + } + }, + }, +}; +</script> + +<template> + <gl-loading-icon v-if="loading" class="gl-mt-3" size="md" /> + <item-title v-else :title="workItemTitle" @title-changed="updateTitle" /> +</template> |