Commit 31b7447c authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch '300235-vsa-explain-what-each-stage-represents-fe' into 'master'

Add popovers to horizontal path navigation in group-level VSA

See merge request gitlab-org/gitlab!57229
parents 3731b3ef 79a96630
<script> <script>
import { GlPath, GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; import {
GlPath,
GlPopover,
GlDeprecatedSkeletonLoading as GlSkeletonLoading,
GlSafeHtmlDirective as SafeHtml,
} from '@gitlab/ui';
export default { export default {
name: 'PathNavigation', name: 'PathNavigation',
components: { components: {
GlPath, GlPath,
GlSkeletonLoading, GlSkeletonLoading,
GlPopover,
},
directives: {
SafeHtml,
}, },
props: { props: {
loading: { loading: {
...@@ -23,9 +32,47 @@ export default { ...@@ -23,9 +32,47 @@ export default {
default: () => {}, default: () => {},
}, },
}, },
methods: {
showPopover({ startEventHtmlDescription, endEventHtmlDescription }) {
return startEventHtmlDescription || endEventHtmlDescription;
},
},
popoverOptions: {
triggers: 'hover',
placement: 'bottom',
},
}; };
</script> </script>
<template> <template>
<gl-skeleton-loading v-if="loading" :lines="2" class="h-auto pt-2 pb-1" /> <gl-skeleton-loading v-if="loading" :lines="2" class="h-auto pt-2 pb-1" />
<gl-path v-else :key="selectedStage.id" :items="stages" @selected="$emit('selected', $event)" /> <gl-path v-else :key="selectedStage.id" :items="stages" @selected="$emit('selected', $event)">
<template #default="{ pathItem, pathId }">
<gl-popover
v-if="showPopover(pathItem)"
v-bind="$options.popoverOptions"
:target="pathId"
data-testid="stage-item-popover"
>
<template #title>{{ pathItem.title }}</template>
<div class="gl-display-table">
<div v-if="pathItem.startEventHtmlDescription" class="gl-display-table-row">
<div class="gl-display-table-cell gl-pr-4 gl-pb-4">
{{ s__('ValueStreamEvent|Start') }}
</div>
<div
v-safe-html="pathItem.startEventHtmlDescription"
class="gl-display-table-cell gl-pb-4 stage-event-description"
></div>
</div>
<div v-if="pathItem.endEventHtmlDescription" class="gl-display-table-row">
<div class="gl-display-table-cell gl-pr-4">{{ s__('ValueStreamEvent|Stop') }}</div>
<div
v-safe-html="pathItem.endEventHtmlDescription"
class="gl-display-table-cell stage-event-description"
></div>
</div>
</div>
</gl-popover>
</template>
</gl-path>
</template> </template>
...@@ -38,3 +38,8 @@ ...@@ -38,3 +38,8 @@
0 0.25rem 0.75rem $gl-btn-active-background; 0 0.25rem 0.75rem $gl-btn-active-background;
} }
// Since backend wraps event description in a paragraph
// we need to remove common styles, i.e., spacing
.stage-event-description p {
margin: 0 !important;
}
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PathNavigation displays correctly loading is false matches the snapshot 1`] = `
<div
class="gl-path-nav"
data-testid="gl-path-nav"
style="--path-bg-color: white;"
>
<span
class="gl-path-fade gl-path-fade-left"
style="display: none;"
>
<button
aria-label="Scroll left"
class="gl-clear-icon-button"
>
<svg
aria-hidden="true"
class="gl-icon s32"
data-testid="chevron-left-icon"
>
<use
href="#chevron-left"
/>
</svg>
</button>
</span>
<ul
class="gl-path-nav-list"
>
<li
class="gl-path-nav-list-item"
id="path-6-item-0"
>
<button
class="gl-path-button gl-path-active-item-indigo"
>
<!---->
Issue
<!---->
</button>
<div
class="gl-popover"
data-testid="stage-item-popover"
>
<div
class="gl-display-table"
>
<div
class="gl-display-table-row"
>
<div
class="gl-display-table-cell gl-pr-4 gl-pb-4"
>
Start
</div>
<div
class="gl-display-table-cell gl-pb-4 stage-event-description"
>
<p
data-sourcepos="1:1-1:13"
dir="auto"
>
Issue created
</p>
</div>
</div>
<div
class="gl-display-table-row"
>
<div
class="gl-display-table-cell gl-pr-4"
>
Stop
</div>
<div
class="gl-display-table-cell stage-event-description"
>
<p
data-sourcepos="1:1-1:71"
dir="auto"
>
Issue first associated with a milestone or issue first added to a board
</p>
</div>
</div>
</div>
Issue
</div>
</li>
<li
class="gl-path-nav-list-item"
id="path-6-item-1"
>
<button
class="gl-path-button"
>
<!---->
Plan
<!---->
</button>
<div
class="gl-popover"
data-testid="stage-item-popover"
>
<div
class="gl-display-table"
>
<div
class="gl-display-table-row"
>
<div
class="gl-display-table-cell gl-pr-4 gl-pb-4"
>
Start
</div>
<div
class="gl-display-table-cell gl-pb-4 stage-event-description"
>
<p
data-sourcepos="1:1-1:71"
dir="auto"
>
Issue first associated with a milestone or issue first added to a board
</p>
</div>
</div>
<div
class="gl-display-table-row"
>
<div
class="gl-display-table-cell gl-pr-4"
>
Stop
</div>
<div
class="gl-display-table-cell stage-event-description"
>
<p
data-sourcepos="1:1-1:33"
dir="auto"
>
Issue first mentioned in a commit
</p>
</div>
</div>
</div>
Plan
</div>
</li>
<li
class="gl-path-nav-list-item"
id="path-6-item-2"
>
<button
class="gl-path-button"
>
<!---->
Code
<!---->
</button>
<div
class="gl-popover"
data-testid="stage-item-popover"
>
<div
class="gl-display-table"
>
<div
class="gl-display-table-row"
>
<div
class="gl-display-table-cell gl-pr-4 gl-pb-4"
>
Start
</div>
<div
class="gl-display-table-cell gl-pb-4 stage-event-description"
>
<p
data-sourcepos="1:1-1:33"
dir="auto"
>
Issue first mentioned in a commit
</p>
</div>
</div>
<div
class="gl-display-table-row"
>
<div
class="gl-display-table-cell gl-pr-4"
>
Stop
</div>
<div
class="gl-display-table-cell stage-event-description"
>
<p
data-sourcepos="1:1-1:21"
dir="auto"
>
Merge request created
</p>
</div>
</div>
</div>
Code
</div>
</li>
</ul>
<span
class="gl-path-fade gl-path-fade-right"
style="display: none;"
>
<button
aria-label="Scroll right"
class="gl-clear-icon-button"
>
<svg
aria-hidden="true"
class="gl-icon s32"
data-testid="chevron-right-icon"
>
<use
href="#chevron-right"
/>
</svg>
</button>
</span>
</div>
`;
...@@ -56,6 +56,42 @@ describe('PathNavigation', () => { ...@@ -56,6 +56,42 @@ describe('PathNavigation', () => {
it('hides the gl-skeleton-loading component', () => { it('hides the gl-skeleton-loading component', () => {
expect(wrapper.find(GlSkeletonLoading).exists()).toBe(false); expect(wrapper.find(GlSkeletonLoading).exists()).toBe(false);
}); });
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
describe('popovers', () => {
const modifiedStages = [
...transformedStagePathData.slice(0, 2),
{
...transformedStagePathData[2],
startEventHtmlDescription: null,
endEventHtmlDescription: null,
},
];
beforeEach(() => {
wrapper = createComponent({ stages: modifiedStages });
});
it('renders popovers only for stages with either a start event and/or and end event', () => {
expect(wrapper.findAll('[data-testid="stage-item-popover"]')).toHaveLength(2);
});
it('shows the sanitized start event description for the first stage item', () => {
const firsPpopover = wrapper.findAll('[data-testid="stage-item-popover"]').at(0);
const expectedStartEventDescription = 'Issue created';
expect(firsPpopover.text()).toContain(expectedStartEventDescription);
});
it('shows the sanitized end event description for the first stage item', () => {
const firsPpopover = wrapper.findAll('[data-testid="stage-item-popover"]').at(0);
const expectedStartEventDescription =
'Issue first associated with a milestone or issue first added to a board';
expect(firsPpopover.text()).toContain(expectedStartEventDescription);
});
});
}); });
describe('is true', () => { describe('is true', () => {
......
...@@ -33456,6 +33456,12 @@ msgstr "" ...@@ -33456,6 +33456,12 @@ msgstr ""
msgid "ValueStreamAnalytics|Median time from issue created to issue closed." msgid "ValueStreamAnalytics|Median time from issue created to issue closed."
msgstr "" msgstr ""
msgid "ValueStreamEvent|Start"
msgstr ""
msgid "ValueStreamEvent|Stop"
msgstr ""
msgid "ValueStream|The Default Value Stream cannot be deleted" msgid "ValueStream|The Default Value Stream cannot be deleted"
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment