diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-04-20 13:00:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-04-20 13:00:54 +0300 |
commit | 3cccd102ba543e02725d247893729e5c73b38295 (patch) | |
tree | f36a04ec38517f5deaaacb5acc7d949688d1e187 /app/assets/javascripts/work_items | |
parent | 205943281328046ef7b4528031b90fbda70c75ac (diff) |
Add latest changes from gitlab-org/gitlab@14-10-stable-eev14.10.0-rc42
Diffstat (limited to 'app/assets/javascripts/work_items')
19 files changed, 427 insertions, 324 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> diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js index 995c02a2c5b..d3bcaf0f95f 100644 --- a/app/assets/javascripts/work_items/constants.js +++ b/app/assets/javascripts/work_items/constants.js @@ -1,5 +1,6 @@ -export const widgetTypes = { - title: 'TITLE', -}; +import { s__ } from '~/locale'; -export const WI_TITLE_TRACK_LABEL = 'item_title'; +export const i18n = { + fetchError: s__('WorkItem|Something went wrong when fetching the work item. Please try again.'), + updateError: s__('WorkItem|Something went wrong while updating the work item. Please try again.'), +}; diff --git a/app/assets/javascripts/work_items/graphql/create_work_item.mutation.graphql b/app/assets/javascripts/work_items/graphql/create_work_item.mutation.graphql index 9312d1c582b..7f9aaf43068 100644 --- a/app/assets/javascripts/work_items/graphql/create_work_item.mutation.graphql +++ b/app/assets/javascripts/work_items/graphql/create_work_item.mutation.graphql @@ -1,18 +1,9 @@ -#import './widget.fragment.graphql' +#import "./work_item.fragment.graphql" mutation createWorkItem($input: WorkItemCreateInput!) { workItemCreate(input: $input) { workItem { - id - title - workItemType { - id - } - widgets @client { - nodes { - ...WidgetBase - } - } + ...WorkItem } } } diff --git a/app/assets/javascripts/work_items/graphql/create_work_item_from_task.mutation.graphql b/app/assets/javascripts/work_items/graphql/create_work_item_from_task.mutation.graphql new file mode 100644 index 00000000000..b25210f5c74 --- /dev/null +++ b/app/assets/javascripts/work_items/graphql/create_work_item_from_task.mutation.graphql @@ -0,0 +1,9 @@ +mutation workItemCreateFromTask($input: WorkItemCreateFromTaskInput!) { + workItemCreateFromTask(input: $input) { + workItem { + id + descriptionHtml + } + errors + } +} diff --git a/app/assets/javascripts/work_items/graphql/delete_work_item.mutation.graphql b/app/assets/javascripts/work_items/graphql/delete_work_item.mutation.graphql new file mode 100644 index 00000000000..c52c49ec5f6 --- /dev/null +++ b/app/assets/javascripts/work_items/graphql/delete_work_item.mutation.graphql @@ -0,0 +1,5 @@ +mutation deleteWorkItem($input: WorkItemDeleteInput!) { + workItemDelete(input: $input) { + errors + } +} diff --git a/app/assets/javascripts/work_items/graphql/provider.js b/app/assets/javascripts/work_items/graphql/provider.js index 28328a840cf..3c2955ce1e2 100644 --- a/app/assets/javascripts/work_items/graphql/provider.js +++ b/app/assets/javascripts/work_items/graphql/provider.js @@ -1,41 +1,11 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; -import workItemQuery from './work_item.query.graphql'; -import { resolvers } from './resolvers'; -import typeDefs from './typedefs.graphql'; export function createApolloProvider() { Vue.use(VueApollo); - const defaultClient = createDefaultClient(resolvers, { - typeDefs, - cacheConfig: { - possibleTypes: { - LocalWorkItemWidget: ['LocalTitleWidget'], - }, - }, - }); - - defaultClient.cache.writeQuery({ - query: workItemQuery, - variables: { - id: 'gid://gitlab/WorkItem/1', - }, - data: { - localWorkItem: { - __typename: 'LocalWorkItem', - id: 'gid://gitlab/WorkItem/1', - type: 'FEATURE', - // eslint-disable-next-line @gitlab/require-i18n-strings - title: 'Test Work Item', - widgets: { - __typename: 'LocalWorkItemWidgetConnection', - nodes: [], - }, - }, - }, - }); + const defaultClient = createDefaultClient(); return new VueApollo({ defaultClient, diff --git a/app/assets/javascripts/work_items/graphql/resolvers.js b/app/assets/javascripts/work_items/graphql/resolvers.js deleted file mode 100644 index fb74e27f840..00000000000 --- a/app/assets/javascripts/work_items/graphql/resolvers.js +++ /dev/null @@ -1,29 +0,0 @@ -import workItemQuery from './work_item.query.graphql'; - -export const resolvers = { - Mutation: { - localUpdateWorkItem(_, { input }, { cache }) { - const workItem = { - __typename: 'LocalWorkItem', - type: 'FEATURE', - id: input.id, - title: input.title, - widgets: { - __typename: 'LocalWorkItemWidgetConnection', - nodes: [], - }, - }; - - cache.writeQuery({ - query: workItemQuery, - variables: { id: input.id }, - data: { localWorkItem: workItem }, - }); - - return { - __typename: 'LocalUpdateWorkItemPayload', - workItem, - }; - }, - }, -}; diff --git a/app/assets/javascripts/work_items/graphql/typedefs.graphql b/app/assets/javascripts/work_items/graphql/typedefs.graphql deleted file mode 100644 index 9b4811203f5..00000000000 --- a/app/assets/javascripts/work_items/graphql/typedefs.graphql +++ /dev/null @@ -1,56 +0,0 @@ -enum LocalWorkItemType { - FEATURE -} - -enum LocalWidgetType { - TITLE -} - -interface LocalWorkItemWidget { - type: LocalWidgetType! -} - -# Replicating Relay connection type for client schema -type LocalWorkItemWidgetEdge { - cursor: String! - node: LocalWorkItemWidget -} - -type LocalWorkItemWidgetConnection { - edges: [LocalWorkItemWidgetEdge] - nodes: [LocalWorkItemWidget] - pageInfo: PageInfo! -} - -type LocalWorkItem { - id: ID! - type: LocalWorkItemType! - title: String! - widgets: [LocalWorkItemWidgetConnection] -} - -input LocalCreateWorkItemInput { - title: String! -} - -input LocalUpdateWorkItemInput { - id: ID! - title: String -} - -type LocalCreateWorkItemPayload { - workItem: LocalWorkItem! -} - -type LocalUpdateWorkItemPayload { - workItem: LocalWorkItem! -} - -extend type Query { - localWorkItem(id: ID!): LocalWorkItem! -} - -extend type Mutation { - localCreateWorkItem(input: LocalCreateWorkItemInput!): LocalCreateWorkItemPayload! - localUpdateWorkItem(input: LocalUpdateWorkItemInput!): LocalUpdateWorkItemPayload! -} diff --git a/app/assets/javascripts/work_items/graphql/update_work_item.mutation.graphql b/app/assets/javascripts/work_items/graphql/update_work_item.mutation.graphql index efb1ed8d6df..c0b6e856411 100644 --- a/app/assets/javascripts/work_items/graphql/update_work_item.mutation.graphql +++ b/app/assets/javascripts/work_items/graphql/update_work_item.mutation.graphql @@ -1,18 +1,9 @@ -#import './widget.fragment.graphql' +#import "./work_item.fragment.graphql" mutation workItemUpdate($input: WorkItemUpdateInput!) { workItemUpdate(input: $input) { workItem { - id - title - workItemType { - id - } - widgets @client { - nodes { - ...WidgetBase - } - } + ...WorkItem } } } diff --git a/app/assets/javascripts/work_items/graphql/widget.fragment.graphql b/app/assets/javascripts/work_items/graphql/widget.fragment.graphql deleted file mode 100644 index 154367dc0d8..00000000000 --- a/app/assets/javascripts/work_items/graphql/widget.fragment.graphql +++ /dev/null @@ -1,3 +0,0 @@ -fragment WidgetBase on LocalWorkItemWidget { - type -} diff --git a/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql b/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql new file mode 100644 index 00000000000..2707d6bb790 --- /dev/null +++ b/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql @@ -0,0 +1,8 @@ +fragment WorkItem on WorkItem { + id + title + workItemType { + id + name + } +} diff --git a/app/assets/javascripts/work_items/graphql/work_item.query.graphql b/app/assets/javascripts/work_items/graphql/work_item.query.graphql index b32cb4f28fb..1d3dae0649d 100644 --- a/app/assets/javascripts/work_items/graphql/work_item.query.graphql +++ b/app/assets/javascripts/work_items/graphql/work_item.query.graphql @@ -1,16 +1,7 @@ -#import './widget.fragment.graphql' +#import "./work_item.fragment.graphql" -query WorkItem($id: ID!) { +query workItem($id: ID!) { workItem(id: $id) { - id - title - workItemType { - id - } - widgets @client { - nodes { - ...WidgetBase - } - } + ...WorkItem } } diff --git a/app/assets/javascripts/work_items/graphql/work_item_title.subscription.graphql b/app/assets/javascripts/work_items/graphql/work_item_title.subscription.graphql new file mode 100644 index 00000000000..2ac01b79d6f --- /dev/null +++ b/app/assets/javascripts/work_items/graphql/work_item_title.subscription.graphql @@ -0,0 +1,8 @@ +subscription issuableTitleUpdated($issuableId: IssuableID!) { + issuableTitleUpdated(issuableId: $issuableId) { + ... on WorkItem { + id + title + } + } +} diff --git a/app/assets/javascripts/work_items/pages/create_work_item.vue b/app/assets/javascripts/work_items/pages/create_work_item.vue index cc90cedb110..a95da80ac95 100644 --- a/app/assets/javascripts/work_items/pages/create_work_item.vue +++ b/app/assets/javascripts/work_items/pages/create_work_item.vue @@ -1,21 +1,25 @@ <script> -import { GlButton, GlAlert, GlLoadingIcon, GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { GlButton, GlAlert, GlLoadingIcon, GlFormSelect } from '@gitlab/ui'; import { s__ } from '~/locale'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import workItemQuery from '../graphql/work_item.query.graphql'; import createWorkItemMutation from '../graphql/create_work_item.mutation.graphql'; +import createWorkItemFromTaskMutation from '../graphql/create_work_item_from_task.mutation.graphql'; import projectWorkItemTypesQuery from '../graphql/project_work_item_types.query.graphql'; import ItemTitle from '../components/item_title.vue'; export default { + createErrorText: s__('WorkItem|Something went wrong when creating a work item. Please try again'), + fetchTypesErrorText: s__( + 'WorkItem|Something went wrong when fetching work item types. Please try again', + ), components: { GlButton, GlAlert, GlLoadingIcon, - GlDropdown, - GlDropdownItem, ItemTitle, + GlFormSelect, }, inject: ['fullPath'], props: { @@ -29,6 +33,26 @@ export default { required: false, default: '', }, + issueGid: { + type: String, + required: false, + default: '', + }, + lockVersion: { + type: Number, + required: false, + default: null, + }, + lineNumberStart: { + type: String, + required: false, + default: null, + }, + lineNumberEnd: { + type: String, + required: false, + default: null, + }, }, data() { return { @@ -36,6 +60,7 @@ export default { error: null, workItemTypes: [], selectedWorkItemType: null, + loading: false, }; }, apollo: { @@ -47,12 +72,13 @@ export default { }; }, update(data) { - return data.workspace?.workItemTypes?.nodes; + return data.workspace?.workItemTypes?.nodes.map((node) => ({ + value: node.id, + text: node.name, + })); }, error() { - this.error = s__( - 'WorkItem|Something went wrong when fetching work item types. Please try again', - ); + this.error = this.$options.fetchTypesErrorText; }, }, }, @@ -60,9 +86,24 @@ export default { dropdownButtonText() { return this.selectedWorkItemType?.name || s__('WorkItem|Type'); }, + formOptions() { + return [{ value: null, text: s__('WorkItem|Select type') }, ...this.workItemTypes]; + }, + isButtonDisabled() { + return this.title.trim().length === 0 || !this.selectedWorkItemType; + }, }, methods: { async createWorkItem() { + this.loading = true; + if (this.isModal) { + await this.createWorkItemFromTask(); + } else { + await this.createStandaloneWorkItem(); + } + this.loading = false; + }, + async createStandaloneWorkItem() { try { const response = await this.$apollo.mutate({ mutation: createWorkItemMutation, @@ -70,7 +111,7 @@ export default { input: { title: this.title, projectPath: this.fullPath, - workItemTypeId: this.selectedWorkItemType?.id, + workItemTypeId: this.selectedWorkItemType, }, }, update(store, { data: { workItemCreate } }) { @@ -87,32 +128,43 @@ export default { id, title, workItemType, - widgets: { - __typename: 'LocalWorkItemWidgetConnection', - nodes: [], - }, }, }, }); }, }); - const { data: { workItemCreate: { - workItem: { id, type }, + workItem: { id }, }, }, } = response; - if (!this.isModal) { - this.$router.push({ name: 'workItem', params: { id: `${getIdFromGraphQLId(id)}` } }); - } else { - this.$emit('onCreate', { id, title: this.title, type }); - } + this.$router.push({ name: 'workItem', params: { id: `${getIdFromGraphQLId(id)}` } }); + } catch { + this.error = this.$options.createErrorText; + } + }, + async createWorkItemFromTask() { + try { + const { data } = await this.$apollo.mutate({ + mutation: createWorkItemFromTaskMutation, + variables: { + input: { + id: this.issueGid, + workItemData: { + lockVersion: this.lockVersion, + title: this.title, + lineNumberStart: Number(this.lineNumberStart), + lineNumberEnd: Number(this.lineNumberEnd), + workItemTypeId: this.selectedWorkItemType, + }, + }, + }, + }); + this.$emit('onCreate', data.workItemCreateFromTask.workItem.descriptionHtml); } catch { - this.error = s__( - 'WorkItem|Something went wrong when creating a work item. Please try again', - ); + this.error = this.$options.createErrorText; } }, handleTitleInput(title) { @@ -125,9 +177,6 @@ export default { } this.$emit('closeModal'); }, - selectWorkItemType(type) { - this.selectedWorkItemType = type; - }, }, }; </script> @@ -136,28 +185,19 @@ export default { <form @submit.prevent="createWorkItem"> <gl-alert v-if="error" variant="danger" @dismiss="error = null">{{ error }}</gl-alert> <div :class="{ 'gl-px-5': isModal }" data-testid="content"> - <item-title - :initial-title="title" - data-testid="title-input" - @title-input="handleTitleInput" - /> + <item-title :title="title" data-testid="title-input" @title-input="handleTitleInput" /> <div> - <gl-dropdown :text="dropdownButtonText"> - <gl-loading-icon - v-if="$apollo.queries.workItemTypes.loading" - size="md" - data-testid="loading-types" - /> - <template v-else> - <gl-dropdown-item - v-for="type in workItemTypes" - :key="type.id" - @click="selectWorkItemType(type)" - > - {{ type.name }} - </gl-dropdown-item> - </template> - </gl-dropdown> + <gl-loading-icon + v-if="$apollo.queries.workItemTypes.loading" + size="md" + data-testid="loading-types" + /> + <gl-form-select + v-else + v-model="selectedWorkItemType" + :options="formOptions" + class="gl-max-w-26" + /> </div> </div> <div @@ -166,8 +206,9 @@ export default { > <gl-button variant="confirm" - :disabled="title.length === 0" + :disabled="isButtonDisabled" :class="{ 'gl-mr-3': !isModal }" + :loading="loading" data-testid="create-button" type="submit" > diff --git a/app/assets/javascripts/work_items/pages/work_item_root.vue b/app/assets/javascripts/work_items/pages/work_item_root.vue index 32b6fc231a8..b8f2bcff25d 100644 --- a/app/assets/javascripts/work_items/pages/work_item_root.vue +++ b/app/assets/javascripts/work_items/pages/work_item_root.vue @@ -1,98 +1,26 @@ <script> -import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; +import { TYPE_WORK_ITEM } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; -import Tracking from '~/tracking'; -import workItemQuery from '../graphql/work_item.query.graphql'; -import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql'; -import { WI_TITLE_TRACK_LABEL } from '../constants'; - -import ItemTitle from '../components/item_title.vue'; - -const trackingMixin = Tracking.mixin(); +import WorkItemDetail from '../components/work_item_detail.vue'; export default { - titleUpdatedEvent: 'updated_title', components: { - ItemTitle, - GlAlert, - GlLoadingIcon, + WorkItemDetail, }, - mixins: [trackingMixin], props: { id: { type: String, required: true, }, }, - data() { - return { - workItem: {}, - error: false, - }; - }, - apollo: { - workItem: { - query: workItemQuery, - variables() { - return { - id: this.gid, - }; - }, - }, - }, computed: { - tracking() { - return { - category: 'workItems:show', - action: 'updated_title', - label: WI_TITLE_TRACK_LABEL, - property: '[type_work_item]', - }; - }, gid() { - return convertToGraphQLId('WorkItem', this.id); - }, - }, - methods: { - async updateWorkItem(updatedTitle) { - try { - await this.$apollo.mutate({ - mutation: updateWorkItemMutation, - variables: { - input: { - id: this.gid, - title: updatedTitle, - }, - }, - }); - this.track(); - } catch { - this.error = true; - } + return convertToGraphQLId(TYPE_WORK_ITEM, this.id); }, }, }; </script> <template> - <section> - <gl-alert v-if="error" variant="danger" @dismiss="error = false">{{ - __('Something went wrong while updating work item. Please try again') - }}</gl-alert> - <!-- Title widget placeholder --> - <div> - <gl-loading-icon - v-if="$apollo.queries.workItem.loading" - size="md" - data-testid="loading-types" - /> - <template v-else> - <item-title - :initial-title="workItem.title" - data-testid="title" - @title-changed="updateWorkItem" - /> - </template> - </div> - </section> + <work-item-detail :work-item-id="gid" /> </template> |