diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-09 18:11:41 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-09 18:11:41 +0300 |
commit | d56569ff3e73ae1dbcf93d2530925c4ecb8fd185 (patch) | |
tree | f89e6dd59d8d807201a9dd3ca46b5eee0ea5f438 /app/assets | |
parent | 1faea1c6a0464e44dca4477fb31846938c2ad871 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
13 files changed, 329 insertions, 128 deletions
diff --git a/app/assets/javascripts/custom_emoji/components/delete_item.vue b/app/assets/javascripts/custom_emoji/components/delete_item.vue new file mode 100644 index 00000000000..9d13d40dc47 --- /dev/null +++ b/app/assets/javascripts/custom_emoji/components/delete_item.vue @@ -0,0 +1,90 @@ +<script> +import * as Sentry from '@sentry/browser'; +import { uniqueId } from 'lodash'; +import { GlButton, GlTooltipDirective, GlModal, GlModalDirective, GlSprintf } from '@gitlab/ui'; +import { createAlert } from '~/alert'; +import { __ } from '~/locale'; +import deleteCustomEmojiMutation from '../queries/delete_custom_emoji.mutation.graphql'; + +export default { + name: 'DeleteItem', + components: { + GlButton, + GlModal, + GlSprintf, + }, + directives: { + GlTooltip: GlTooltipDirective, + GlModal: GlModalDirective, + }, + props: { + emoji: { + type: Object, + required: true, + }, + }, + data() { + return { + isDeleting: false, + modalId: uniqueId('delete-custom-emoji-'), + }; + }, + methods: { + showModal() { + this.$refs['delete-modal'].show(); + }, + async onDelete() { + this.isDeleting = true; + + try { + await this.$apollo.mutate({ + mutation: deleteCustomEmojiMutation, + variables: { + id: this.emoji.id, + }, + update: (cache) => { + const cacheId = cache.identify(this.emoji); + cache.evict({ id: cacheId }); + }, + }); + } catch (e) { + createAlert(__('Failed to delete custom emoji. Please try again.')); + Sentry.captureException(e); + } + }, + }, + actionPrimary: { text: __('Delete'), attributes: { variant: 'danger' } }, + actionSecondary: { text: __('Cancel'), attributes: { variant: 'default' } }, +}; +</script> + +<template> + <div> + <gl-button + v-gl-tooltip + icon="remove" + :aria-label="__('Delete custom emoji')" + :title="__('Delete custom emoji')" + :loading="isDeleting" + data-testid="delete-button" + @click="showModal" + /> + <gl-modal + ref="delete-modal" + :title="__('Delete custom emoji')" + :action-primary="$options.actionPrimary" + :action-secondary="$options.actionSecondary" + :modal-id="modalId" + size="sm" + @primary="onDelete" + > + <gl-sprintf + :message="__('Are you sure you want to delete %{name}? This action cannot be undone.')" + > + <template #name + ><strong>{{ emoji.name }}</strong></template + > + </gl-sprintf> + </gl-modal> + </div> +</template> diff --git a/app/assets/javascripts/custom_emoji/components/list.vue b/app/assets/javascripts/custom_emoji/components/list.vue index 03ed2ffe2ec..72b28e8db4a 100644 --- a/app/assets/javascripts/custom_emoji/components/list.vue +++ b/app/assets/javascripts/custom_emoji/components/list.vue @@ -3,6 +3,7 @@ import { GlLoadingIcon, GlTableLite, GlTabs, GlTab, GlBadge, GlKeysetPagination } from '@gitlab/ui'; import { __ } from '~/locale'; import { formatDate } from '~/lib/utils/datetime/date_format_utility'; +import DeleteItem from './delete_item.vue'; export default { components: { @@ -12,6 +13,7 @@ export default { GlTab, GlBadge, GlKeysetPagination, + DeleteItem, }, props: { loading: { @@ -124,7 +126,13 @@ export default { data-unicode-version="custom" /> </template> - <template #cell(action)> </template> + <template #cell(action)="data"> + <delete-item + v-if="data.item.userPermissions.deleteCustomEmoji" + :key="data.item.name" + :emoji="data.item" + /> + </template> <template #cell(created_at)="data"> {{ formatDate(data.item.createdAt) }} </template> diff --git a/app/assets/javascripts/custom_emoji/queries/custom_emojis.query.graphql b/app/assets/javascripts/custom_emoji/queries/custom_emojis.query.graphql index 78e10ed93f8..a4189f80436 100644 --- a/app/assets/javascripts/custom_emoji/queries/custom_emojis.query.graphql +++ b/app/assets/javascripts/custom_emoji/queries/custom_emojis.query.graphql @@ -16,6 +16,9 @@ query getCustomEmojis($groupPath: ID!, $after: String = "", $before: String = "" name url createdAt + userPermissions { + deleteCustomEmoji + } } } } diff --git a/app/assets/javascripts/custom_emoji/queries/delete_custom_emoji.mutation.graphql b/app/assets/javascripts/custom_emoji/queries/delete_custom_emoji.mutation.graphql new file mode 100644 index 00000000000..37618bc2749 --- /dev/null +++ b/app/assets/javascripts/custom_emoji/queries/delete_custom_emoji.mutation.graphql @@ -0,0 +1,7 @@ +mutation deleteCustomEmoji($id: CustomEmojiID!) { + destroyCustomEmoji(input: { id: $id }) { + customEmoji { + id + } + } +} diff --git a/app/assets/javascripts/super_sidebar/components/brand_logo.vue b/app/assets/javascripts/super_sidebar/components/brand_logo.vue index 66381e4da4d..1589f4978e1 100644 --- a/app/assets/javascripts/super_sidebar/components/brand_logo.vue +++ b/app/assets/javascripts/super_sidebar/components/brand_logo.vue @@ -26,7 +26,7 @@ export default { <template> <a - v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.homepage" + v-gl-tooltip:super-sidebar.hover.noninteractive.bottom.ds500="$options.i18n.homepage" class="brand-logo" :href="rootPath" :title="$options.i18n.homepage" diff --git a/app/assets/javascripts/super_sidebar/components/create_menu.vue b/app/assets/javascripts/super_sidebar/components/create_menu.vue index 82f4fd18e80..3645606515f 100644 --- a/app/assets/javascripts/super_sidebar/components/create_menu.vue +++ b/app/assets/javascripts/super_sidebar/components/create_menu.vue @@ -95,6 +95,7 @@ export default { :target="`#${$options.toggleId}`" placement="bottom" container="#super-sidebar" + noninteractive > {{ $options.i18n.createNew }} </gl-tooltip> diff --git a/app/assets/javascripts/super_sidebar/components/nav_item.vue b/app/assets/javascripts/super_sidebar/components/nav_item.vue index 79d476ee74b..25d2b8a73ed 100644 --- a/app/assets/javascripts/super_sidebar/components/nav_item.vue +++ b/app/assets/javascripts/super_sidebar/components/nav_item.vue @@ -168,7 +168,7 @@ export default { </gl-badge> <gl-button v-if="isPinnable && !isPinned" - v-gl-tooltip.right.viewport="$options.i18n.pinItem" + v-gl-tooltip.noninteractive.ds500.right.viewport="$options.i18n.pinItem" size="small" category="tertiary" icon="thumbtack" @@ -177,7 +177,7 @@ export default { /> <gl-button v-else-if="isPinnable && isPinned" - v-gl-tooltip.right.viewport="$options.i18n.unpinItem" + v-gl-tooltip.noninteractive.ds500.right.viewport="$options.i18n.unpinItem" size="small" category="tertiary" :aria-label="$options.i18n.unpinItem" diff --git a/app/assets/javascripts/super_sidebar/components/super_sidebar_toggle.vue b/app/assets/javascripts/super_sidebar/components/super_sidebar_toggle.vue index 87762a62c0f..7d5e87805d5 100644 --- a/app/assets/javascripts/super_sidebar/components/super_sidebar_toggle.vue +++ b/app/assets/javascripts/super_sidebar/components/super_sidebar_toggle.vue @@ -74,7 +74,7 @@ export default { <template> <gl-button - v-gl-tooltip.hover="tooltip" + v-gl-tooltip.hover.noninteractive.ds500="tooltip" aria-controls="super-sidebar" :aria-expanded="ariaExpanded" :aria-label="$options.i18n.navigationSidebar" diff --git a/app/assets/javascripts/super_sidebar/components/user_bar.vue b/app/assets/javascripts/super_sidebar/components/user_bar.vue index 0188585df40..5bc8ad97cd5 100644 --- a/app/assets/javascripts/super_sidebar/components/user_bar.vue +++ b/app/assets/javascripts/super_sidebar/components/user_bar.vue @@ -130,7 +130,7 @@ export default { <gl-button id="super-sidebar-search" - v-gl-tooltip.bottom.hover.html="searchTooltip" + v-gl-tooltip.bottom.hover.noninteractive.ds500.html="searchTooltip" v-gl-modal="$options.SEARCH_MODAL_ID" data-testid="super-sidebar-search-button" icon="search" @@ -143,7 +143,7 @@ export default { <gl-button v-if="isImpersonating" - v-gl-tooltip + v-gl-tooltip.noninteractive.ds500.bottom :href="sidebarData.stop_impersonation_path" :title="$options.i18n.stopImpersonating" :aria-label="$options.i18n.stopImpersonating" @@ -159,7 +159,7 @@ export default { class="gl-display-flex gl-justify-content-space-between gl-px-3 gl-py-2 gl-gap-2" > <counter - v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.issues" + v-gl-tooltip:super-sidebar.hover.noninteractive.ds500.bottom="$options.i18n.issues" class="gl-flex-basis-third dashboard-shortcuts-issues" icon="issues" :count="userCounts.assigned_issues" @@ -177,7 +177,9 @@ export default { @hidden="mrMenuShown = false" > <counter - v-gl-tooltip:super-sidebar.hover.bottom="mrMenuShown ? '' : $options.i18n.mergeRequests" + v-gl-tooltip:super-sidebar.hover.noninteractive.ds500.bottom=" + mrMenuShown ? '' : $options.i18n.mergeRequests + " class="gl-w-full" icon="merge-request-open" :count="mergeRequestTotalCount" @@ -189,7 +191,7 @@ export default { /> </merge-request-menu> <counter - v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.todoList" + v-gl-tooltip:super-sidebar.hover.noninteractive.ds500.bottom="$options.i18n.todoList" class="gl-flex-basis-third shortcuts-todos js-todos-count" icon="todo-done" :count="userCounts.todos" diff --git a/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue b/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue new file mode 100644 index 00000000000..0a38dcb77f6 --- /dev/null +++ b/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue @@ -0,0 +1,196 @@ +<script> +import { GlLabel, GlLink, GlIcon, GlTooltipDirective } from '@gitlab/ui'; +import { __ } from '~/locale'; +import { isScopedLabel } from '~/lib/utils/common_utils'; +import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip.vue'; +import WorkItemLinkChildMetadata from 'ee_else_ce/work_items/components/shared/work_item_link_child_metadata.vue'; +import { + STATE_OPEN, + TASK_TYPE_NAME, + WIDGET_TYPE_PROGRESS, + WIDGET_TYPE_HIERARCHY, + WIDGET_TYPE_HEALTH_STATUS, + WIDGET_TYPE_MILESTONE, + WIDGET_TYPE_ASSIGNEES, + WIDGET_TYPE_LABELS, + WORK_ITEM_NAME_TO_ICON_MAP, +} from '../../constants'; +import WorkItemLinksMenu from './work_item_links_menu.vue'; + +export default { + i18n: { + confidential: __('Confidential'), + created: __('Created'), + closed: __('Closed'), + }, + components: { + GlLabel, + GlLink, + GlIcon, + RichTimestampTooltip, + WorkItemLinkChildMetadata, + WorkItemLinksMenu, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + childItem: { + type: Object, + required: true, + }, + canUpdate: { + type: Boolean, + required: true, + }, + parentWorkItemId: { + type: String, + required: true, + }, + workItemType: { + type: String, + required: false, + default: '', + }, + childPath: { + type: String, + required: true, + }, + }, + computed: { + labels() { + return this.metadataWidgets[WIDGET_TYPE_LABELS]?.labels?.nodes || []; + }, + metadataWidgets() { + return this.childItem.widgets?.reduce((metadataWidgets, widget) => { + // Skip Hierarchy widget as it is not part of metadata. + if (widget.type && widget.type !== WIDGET_TYPE_HIERARCHY) { + // eslint-disable-next-line no-param-reassign + metadataWidgets[widget.type] = widget; + } + return metadataWidgets; + }, {}); + }, + allowsScopedLabels() { + return this.metadataWidgets[WIDGET_TYPE_LABELS]?.allowsScopedLabels; + }, + isChildItemOpen() { + return this.childItem.state === STATE_OPEN; + }, + iconName() { + if (this.childItemType === TASK_TYPE_NAME) { + return this.isChildItemOpen ? 'issue-open-m' : 'issue-close'; + } + return WORK_ITEM_NAME_TO_ICON_MAP[this.childItemType]; + }, + childItemType() { + return this.childItem.workItemType.name; + }, + iconClass() { + if (this.childItemType === TASK_TYPE_NAME) { + return this.isChildItemOpen ? 'gl-text-green-500' : 'gl-text-blue-500'; + } + return ''; + }, + stateTimestamp() { + return this.isChildItemOpen ? this.childItem.createdAt : this.childItem.closedAt; + }, + stateTimestampTypeText() { + return this.isChildItemOpen ? this.$options.i18n.created : this.$options.i18n.closed; + }, + hasMetadata() { + if (this.metadataWidgets) { + return ( + Number.isInteger(this.metadataWidgets[WIDGET_TYPE_PROGRESS]?.progress) || + Boolean(this.metadataWidgets[WIDGET_TYPE_HEALTH_STATUS]?.healthStatus) || + Boolean(this.metadataWidgets[WIDGET_TYPE_MILESTONE]?.milestone) || + this.metadataWidgets[WIDGET_TYPE_ASSIGNEES]?.assignees?.nodes.length > 0 || + this.metadataWidgets[WIDGET_TYPE_LABELS]?.labels?.nodes.length > 0 + ); + } + return false; + }, + }, + methods: { + showScopedLabel(label) { + return isScopedLabel(label) && this.allowsScopedLabels; + }, + }, +}; +</script> + +<template> + <div + class="item-body work-item-link-child gl-relative gl-display-flex gl-flex-grow-1 gl-overflow-break-word gl-min-w-0 gl-pl-3 gl-pr-2 gl-py-2 gl-mx-n2 gl-rounded-base" + data-testid="links-child" + > + <div class="item-contents gl-display-flex gl-flex-grow-1 gl-flex-wrap gl-min-w-0"> + <div + class="gl-display-flex gl-flex-grow-1 gl-flex-wrap flex-xl-nowrap gl-align-items-center gl-justify-content-space-between gl-gap-3 gl-min-w-0" + > + <div class="item-title gl-display-flex gl-gap-3 gl-min-w-0"> + <span + :id="`stateIcon-${childItem.id}`" + class="gl-cursor-help" + data-testid="item-status-icon" + > + <gl-icon + class="gl-text-secondary" + :class="iconClass" + :name="iconName" + :aria-label="stateTimestampTypeText" + /> + </span> + <rich-timestamp-tooltip + :target="`stateIcon-${childItem.id}`" + :raw-timestamp="stateTimestamp" + :timestamp-type-text="stateTimestampTypeText" + /> + <span v-if="childItem.confidential"> + <gl-icon + v-gl-tooltip.top + name="eye-slash" + class="gl-text-orange-500" + data-testid="confidential-icon" + :aria-label="$options.i18n.confidential" + :title="$options.i18n.confidential" + /> + </span> + <gl-link + :href="childPath" + class="gl-text-truncate gl-text-black-normal! gl-font-weight-semibold" + data-testid="item-title" + @click="$emit('click', $event)" + @mouseover="$emit('mouseover')" + @mouseout="$emit('mouseout')" + > + {{ childItem.title }} + </gl-link> + </div> + <work-item-link-child-metadata + v-if="hasMetadata" + :metadata-widgets="metadataWidgets" + class="gl-ml-6 ml-xl-0" + /> + </div> + <div v-if="labels.length" class="gl-display-flex gl-flex-wrap gl-flex-basis-full gl-ml-6"> + <gl-label + v-for="label in labels" + :key="label.id" + :title="label.title" + :background-color="label.color" + :description="label.description" + :scoped="showScopedLabel(label)" + class="gl-my-2 gl-mr-2 gl-mb-auto gl-label-sm" + tooltip-placement="top" + /> + </div> + </div> + <div v-if="canUpdate" class="gl-ml-0 gl-sm-ml-auto! gl-display-inline-flex"> + <work-item-links-menu + data-testid="links-menu" + @removeChild="$emit('removeChild', childItem)" + /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child_metadata.vue b/app/assets/javascripts/work_items/components/shared/work_item_link_child_metadata.vue index ddeac2b92ae..ddeac2b92ae 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child_metadata.vue +++ b/app/assets/javascripts/work_items/components/shared/work_item_link_child_metadata.vue diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue b/app/assets/javascripts/work_items/components/shared/work_item_links_menu.vue index 53e8eedf060..53e8eedf060 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue +++ b/app/assets/javascripts/work_items/components/shared/work_item_links_menu.vue diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue index ec44a654e89..a9b0c2b98bf 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue @@ -1,39 +1,27 @@ <script> -import { GlButton, GlLabel, GlLink, GlIcon, GlTooltipDirective } from '@gitlab/ui'; +import { GlButton, GlTooltipDirective } from '@gitlab/ui'; import { cloneDeep } from 'lodash'; import * as Sentry from '@sentry/browser'; import { __, s__ } from '~/locale'; import { isScopedLabel } from '~/lib/utils/common_utils'; import { createAlert } from '~/alert'; -import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip.vue'; -import WorkItemLinkChildMetadata from 'ee_else_ce/work_items/components/work_item_links/work_item_link_child_metadata.vue'; import updateWorkItemMutation from '../../graphql/update_work_item.mutation.graphql'; import { STATE_OPEN, TASK_TYPE_NAME, WORK_ITEM_TYPE_VALUE_OBJECTIVE, - WIDGET_TYPE_PROGRESS, - WIDGET_TYPE_HEALTH_STATUS, - WIDGET_TYPE_MILESTONE, WIDGET_TYPE_HIERARCHY, - WIDGET_TYPE_ASSIGNEES, - WIDGET_TYPE_LABELS, WORK_ITEM_NAME_TO_ICON_MAP, } from '../../constants'; import getWorkItemTreeQuery from '../../graphql/work_item_tree.query.graphql'; -import WorkItemLinksMenu from './work_item_links_menu.vue'; +import WorkItemLinkChildContents from '../shared/work_item_link_child_contents.vue'; import WorkItemTreeChildren from './work_item_tree_children.vue'; export default { components: { - GlLabel, - GlLink, GlButton, - GlIcon, - RichTimestampTooltip, - WorkItemLinkChildMetadata, - WorkItemLinksMenu, WorkItemTreeChildren, + WorkItemLinkChildContents, }, directives: { GlTooltip: GlTooltipDirective, @@ -74,25 +62,9 @@ export default { }; }, computed: { - labels() { - return this.metadataWidgets[WIDGET_TYPE_LABELS]?.labels?.nodes || []; - }, - allowsScopedLabels() { - return this.metadataWidgets[WIDGET_TYPE_LABELS]?.allowsScopedLabels; - }, canHaveChildren() { return this.workItemType === WORK_ITEM_TYPE_VALUE_OBJECTIVE; }, - metadataWidgets() { - return this.childItem.widgets?.reduce((metadataWidgets, widget) => { - // Skip Hierarchy widget as it is not part of metadata. - if (widget.type && widget.type !== WIDGET_TYPE_HIERARCHY) { - // eslint-disable-next-line no-param-reassign - metadataWidgets[widget.type] = widget; - } - return metadataWidgets; - }, {}); - }, isItemOpen() { return this.childItem.state === STATE_OPEN; }, @@ -126,18 +98,6 @@ export default { chevronTooltip() { return this.isExpanded ? __('Collapse') : __('Expand'); }, - hasMetadata() { - if (this.metadataWidgets) { - return ( - Number.isInteger(this.metadataWidgets[WIDGET_TYPE_PROGRESS]?.progress) || - Boolean(this.metadataWidgets[WIDGET_TYPE_HEALTH_STATUS]?.healthStatus) || - Boolean(this.metadataWidgets[WIDGET_TYPE_MILESTONE]?.milestone) || - this.metadataWidgets[WIDGET_TYPE_ASSIGNEES]?.assignees?.nodes.length > 0 || - this.metadataWidgets[WIDGET_TYPE_LABELS]?.labels?.nodes.length > 0 - ); - } - return false; - }, }, watch: { childItem: { @@ -270,81 +230,15 @@ export default { data-testid="expand-child" @click="toggleItem" /> - <div - class="item-body work-item-link-child gl-relative gl-display-flex gl-flex-grow-1 gl-overflow-break-word gl-min-w-0 gl-pl-3 gl-pr-2 gl-py-2 gl-mx-n2 gl-rounded-base" - data-testid="links-child" - > - <div class="item-contents gl-display-flex gl-flex-grow-1 gl-flex-wrap gl-min-w-0"> - <div - class="gl-display-flex gl-flex-grow-1 gl-flex-wrap flex-xl-nowrap gl-align-items-center gl-justify-content-space-between gl-gap-3 gl-min-w-0" - > - <div class="item-title gl-display-flex gl-gap-3 gl-min-w-0"> - <span - :id="`stateIcon-${childItem.id}`" - class="gl-cursor-help" - data-testid="item-status-icon" - > - <gl-icon - class="gl-text-secondary" - :class="iconClass" - :name="iconName" - :aria-label="stateTimestampTypeText" - /> - </span> - <rich-timestamp-tooltip - :target="`stateIcon-${childItem.id}`" - :raw-timestamp="stateTimestamp" - :timestamp-type-text="stateTimestampTypeText" - /> - <span v-if="childItem.confidential"> - <gl-icon - v-gl-tooltip.top - name="eye-slash" - class="gl-text-orange-500" - data-testid="confidential-icon" - :aria-label="__('Confidential')" - :title="__('Confidential')" - /> - </span> - <gl-link - :href="childPath" - class="gl-text-truncate gl-text-black-normal! gl-font-weight-semibold" - data-testid="item-title" - @click="$emit('click', $event)" - @mouseover="$emit('mouseover')" - @mouseout="$emit('mouseout')" - > - {{ childItem.title }} - </gl-link> - </div> - <work-item-link-child-metadata - v-if="hasMetadata" - :metadata-widgets="metadataWidgets" - class="gl-ml-6 ml-xl-0" - /> - </div> - <div v-if="labels.length" class="gl-display-flex gl-flex-wrap gl-flex-basis-full gl-ml-6"> - <gl-label - v-for="label in labels" - :key="label.id" - :title="label.title" - :background-color="label.color" - :description="label.description" - :scoped="showScopedLabel(label)" - class="gl-my-2 gl-mr-2 gl-mb-auto gl-label-sm" - tooltip-placement="top" - /> - </div> - </div> - <div v-if="canUpdate" class="gl-ml-0 gl-sm-ml-auto! gl-display-inline-flex"> - <work-item-links-menu - :work-item-id="childItem.id" - :parent-work-item-id="issuableGid" - data-testid="links-menu" - @removeChild="$emit('removeChild', childItem)" - /> - </div> - </div> + <work-item-link-child-contents + :child-item="childItem" + :can-update="canUpdate" + :parent-work-item-id="issuableGid" + :work-item-type="workItemType" + :child-path="childPath" + @click="$emit('click', $event)" + @removeChild="$emit('removeChild', childItem)" + /> </div> <work-item-tree-children v-if="isExpanded" |