Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-04-20 13:00:54 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-04-20 13:00:54 +0300
commit3cccd102ba543e02725d247893729e5c73b38295 (patch)
treef36a04ec38517f5deaaacb5acc7d949688d1e187 /app/assets/javascripts/work_items
parent205943281328046ef7b4528031b90fbda70c75ac (diff)
Add latest changes from gitlab-org/gitlab@14-10-stable-eev14.10.0-rc42
Diffstat (limited to 'app/assets/javascripts/work_items')
-rw-r--r--app/assets/javascripts/work_items/components/item_title.vue12
-rw-r--r--app/assets/javascripts/work_items/components/work_item_actions.vue93
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue73
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail_modal.vue83
-rw-r--r--app/assets/javascripts/work_items/components/work_item_title.vue73
-rw-r--r--app/assets/javascripts/work_items/constants.js9
-rw-r--r--app/assets/javascripts/work_items/graphql/create_work_item.mutation.graphql13
-rw-r--r--app/assets/javascripts/work_items/graphql/create_work_item_from_task.mutation.graphql9
-rw-r--r--app/assets/javascripts/work_items/graphql/delete_work_item.mutation.graphql5
-rw-r--r--app/assets/javascripts/work_items/graphql/provider.js32
-rw-r--r--app/assets/javascripts/work_items/graphql/resolvers.js29
-rw-r--r--app/assets/javascripts/work_items/graphql/typedefs.graphql56
-rw-r--r--app/assets/javascripts/work_items/graphql/update_work_item.mutation.graphql13
-rw-r--r--app/assets/javascripts/work_items/graphql/widget.fragment.graphql3
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item.fragment.graphql8
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item.query.graphql15
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item_title.subscription.graphql8
-rw-r--r--app/assets/javascripts/work_items/pages/create_work_item.vue135
-rw-r--r--app/assets/javascripts/work_items/pages/work_item_root.vue82
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>