Skip to content
Snippets Groups Projects

Add support for viewing and creating objectives within an objective in a hierarchy tree

Merged Florie Guibert requested to merge poc/okr into master
All threads resolved!
13 files
+ 622
68
Compare changes
  • Side-by-side
  • Inline
Files
13
<script>
<script>
import { GlButton, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { GlButton, GlIcon, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
import { __ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip.vue';
import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip.vue';
import { STATE_OPEN } from '../../constants';
import { STATE_OPEN, WORK_ITEM_TYPE_VALUE_OBJECTIVE, WIDGET_TYPE_HIERARCHY } from '../../constants';
 
import getWorkItemTreeQuery from '../../graphql/work_item_tree.query.graphql';
import WorkItemLinksMenu from './work_item_links_menu.vue';
import WorkItemLinksMenu from './work_item_links_menu.vue';
 
import WorkItemTreeChildren from './work_item_tree_children.vue';
export default {
export default {
components: {
components: {
GlButton,
GlButton,
GlIcon,
GlIcon,
 
GlLoadingIcon,
RichTimestampTooltip,
RichTimestampTooltip,
WorkItemLinksMenu,
WorkItemLinksMenu,
 
WorkItemTreeChildren,
},
},
directives: {
directives: {
GlTooltip: GlTooltipDirective,
GlTooltip: GlTooltipDirective,
@@ -35,8 +39,23 @@ export default {
@@ -35,8 +39,23 @@ export default {
type: Object,
type: Object,
required: true,
required: true,
},
},
 
workItemType: {
 
type: String,
 
required: false,
 
default: '',
 
},
 
},
 
data() {
 
return {
 
isExpanded: false,
 
children: [],
 
isLoadingChildren: false,
 
};
},
},
computed: {
computed: {
 
canHaveChildren() {
 
return this.workItemType === WORK_ITEM_TYPE_VALUE_OBJECTIVE;
 
},
isItemOpen() {
isItemOpen() {
return this.childItem.state === STATE_OPEN;
return this.childItem.state === STATE_OPEN;
},
},
@@ -55,55 +74,116 @@ export default {
@@ -55,55 +74,116 @@ export default {
childPath() {
childPath() {
return `/${this.projectPath}/-/work_items/${getIdFromGraphQLId(this.childItem.id)}`;
return `/${this.projectPath}/-/work_items/${getIdFromGraphQLId(this.childItem.id)}`;
},
},
 
hasChildren() {
 
const widgetHierarchy = this.childItem?.widgets?.find(
 
(widget) => widget.type === WIDGET_TYPE_HIERARCHY,
 
);
 
return widgetHierarchy?.hasChildren;
 
},
 
chevronType() {
 
return this.isExpanded ? 'chevron-down' : 'chevron-right';
 
},
 
chevronTooltip() {
 
return this.isExpanded ? __('Collapse') : __('Expand');
 
},
 
},
 
methods: {
 
toggleItem() {
 
this.isExpanded = !this.isExpanded;
 
this.fetchChildren();
 
},
 
async fetchChildren() {
 
this.isLoadingChildren = true;
 
const { data } = await this.$apollo.query({
 
query: getWorkItemTreeQuery,
 
variables: {
 
id: this.childItem.id,
 
},
 
});
 
const widgetHierarchy = data?.workItem?.widgets.find(
 
(widget) => widget.type === WIDGET_TYPE_HIERARCHY,
 
);
 
this.children = widgetHierarchy.children.nodes;
 
this.isLoadingChildren = false;
 
},
},
},
};
};
</script>
</script>
<template>
<template>
<div
<div>
class="gl-relative gl-display-flex gl-overflow-break-word gl-min-w-0 gl-bg-white gl-mb-3 gl-py-3 gl-px-4 gl-border gl-border-gray-100 gl-rounded-base gl-line-height-32"
<div
data-testid="links-child"
class="gl-display-flex gl-align-items-center gl-mb-3"
>
:class="{ 'gl-ml-5': canHaveChildren && !hasChildren }"
<div class="gl-overflow-hidden gl-display-flex gl-align-items-center gl-flex-grow-1">
>
<span :id="`stateIcon-${childItem.id}`" class="gl-mr-3" data-testid="item-status-icon">
<gl-icon :name="iconName" :class="iconClass" :aria-label="stateTimestampTypeText" />
</span>
<rich-timestamp-tooltip
:target="`stateIcon-${childItem.id}`"
:raw-timestamp="stateTimestamp"
:timestamp-type-text="stateTimestampTypeText"
/>
<gl-icon
v-if="childItem.confidential"
v-gl-tooltip.top
name="eye-slash"
class="gl-mr-2 gl-text-orange-500"
data-testid="confidential-icon"
:aria-label="__('Confidential')"
:title="__('Confidential')"
/>
<gl-button
<gl-button
:href="childPath"
v-if="hasChildren && !isLoadingChildren"
category="tertiary"
v-gl-tooltip.viewport.hover
 
:title="chevronTooltip"
 
:aria-label="chevronTooltip"
 
:class="chevronType"
variant="link"
variant="link"
class="gl-text-truncate gl-max-w-80 gl-text-black-normal!"
class="gl-text-gray-900! gl-hover-text-blue-600! gl-hover-bg-gray-50!"
@click="$emit('click', $event)"
data-testid="expand-child"
@mouseover="$emit('mouseover')"
@click="toggleItem"
@mouseout="$emit('mouseout')"
>
>
{{ childItem.title }}
<gl-icon :name="chevronType" />
</gl-button>
</gl-button>
 
<gl-loading-icon v-if="isLoadingChildren" class="gl-mr-1" size="sm" />
 
<div
 
class="gl-relative gl-display-flex gl-flex-grow-1 gl-overflow-break-word gl-min-w-0 gl-bg-white gl-py-3 gl-px-4 gl-border gl-border-gray-100 gl-rounded-base gl-line-height-32"
 
data-testid="links-child"
 
>
 
<div class="gl-overflow-hidden gl-display-flex gl-align-items-center gl-flex-grow-1">
 
<span :id="`stateIcon-${childItem.id}`" class="gl-mr-3" data-testid="item-status-icon">
 
<gl-icon :name="iconName" :class="iconClass" :aria-label="stateTimestampTypeText" />
 
</span>
 
<rich-timestamp-tooltip
 
:target="`stateIcon-${childItem.id}`"
 
:raw-timestamp="stateTimestamp"
 
:timestamp-type-text="stateTimestampTypeText"
 
/>
 
<gl-icon
 
v-if="childItem.confidential"
 
v-gl-tooltip.top
 
name="eye-slash"
 
class="gl-mr-2 gl-text-orange-500"
 
data-testid="confidential-icon"
 
:aria-label="__('Confidential')"
 
:title="__('Confidential')"
 
/>
 
<gl-button
 
:href="childPath"
 
category="tertiary"
 
variant="link"
 
class="gl-text-truncate gl-max-w-80 gl-text-black-normal!"
 
@click="$emit('click', $event)"
 
@mouseover="$emit('mouseover')"
 
@mouseout="$emit('mouseout')"
 
>
 
{{ childItem.title }}
 
</gl-button>
 
</div>
 
<div
 
v-if="canUpdate"
 
class="gl-ml-0 gl-sm-ml-auto! gl-display-inline-flex gl-align-items-center"
 
>
 
<work-item-links-menu
 
:work-item-id="childItem.id"
 
:parent-work-item-id="issuableGid"
 
data-testid="links-menu"
 
@removeChild="$emit('remove', childItem.id)"
 
/>
 
</div>
 
</div>
</div>
</div>
<div
<work-item-tree-children
v-if="canUpdate"
v-if="isExpanded"
class="gl-ml-0 gl-sm-ml-auto! gl-display-inline-flex gl-align-items-center"
:project-path="projectPath"
>
:can-update="canUpdate"
<work-item-links-menu
:work-item-id="issuableGid"
:work-item-id="childItem.id"
:work-item-type="workItemType"
:parent-work-item-id="issuableGid"
:children="children"
data-testid="links-menu"
/>
@removeChild="$emit('remove', childItem.id)"
/>
</div>
</div>
</div>
</template>
</template>
Loading