Commit 04b848f9 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo Committed by Brandon Labuschagne

Move path navigation outside filters

Moves the path navigation above the filters
for VSA to match the designs
parent b8b97284
...@@ -92,8 +92,14 @@ export default { ...@@ -92,8 +92,14 @@ export default {
shouldDisplayTypeOfWorkCharts() { shouldDisplayTypeOfWorkCharts() {
return !this.hasNoAccessError; return !this.hasNoAccessError;
}, },
selectedStageReady() {
return !this.hasNoAccessError && this.selectedStage;
},
shouldDisplayPathNavigation() { shouldDisplayPathNavigation() {
return this.featureFlags.hasPathNavigation && !this.hasNoAccessError && this.selectedStage; return this.featureFlags.hasPathNavigation && !this.hasNoAccessError;
},
shouldDisplayVerticalNavigation() {
return !this.featureFlags.hasPathNavigation && this.selectedStageReady;
}, },
shouldDisplayCreateMultipleValueStreams() { shouldDisplayCreateMultipleValueStreams() {
return Boolean(!this.shouldRenderEmptyState && !this.isLoadingValueStreams); return Boolean(!this.shouldRenderEmptyState && !this.isLoadingValueStreams);
...@@ -189,17 +195,21 @@ export default { ...@@ -189,17 +195,21 @@ export default {
:svg-path="emptyStateSvgPath" :svg-path="emptyStateSvgPath"
/> />
<div v-if="!shouldRenderEmptyState" class="gl-max-w-full"> <div v-if="!shouldRenderEmptyState" class="gl-max-w-full">
<div class="gl-mt-3 gl-py-2 gl-px-3 bg-gray-light border-top border-bottom">
<div v-if="shouldDisplayPathNavigation" class="gl-w-full gl-pb-2">
<path-navigation <path-navigation
v-if="shouldDisplayPathNavigation"
:key="`path_navigation_key_${pathNavigationData.length}`" :key="`path_navigation_key_${pathNavigationData.length}`"
class="js-path-navigation" class="js-path-navigation gl-w-full gl-pb-2"
:loading="isLoading" :loading="isLoading"
:stages="pathNavigationData" :stages="pathNavigationData"
:selected-stage="selectedStage" :selected-stage="selectedStage"
@selected="onStageSelect" @selected="onStageSelect"
/> />
</div> <div class="gl-mt-3 gl-py-2 gl-px-3 bg-gray-light border-top border-bottom">
<filter-bar
v-if="shouldDisplayFilters"
class="js-filter-bar filtered-search-box gl-display-flex gl-mb-2 gl-mr-3 gl-border-none"
:group-path="currentGroupPath"
/>
<div <div
v-if="shouldDisplayFilters" v-if="shouldDisplayFilters"
class="gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-justify-content-space-between" class="gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-justify-content-space-between"
...@@ -223,11 +233,6 @@ export default { ...@@ -223,11 +233,6 @@ export default {
@change="setDateRange" @change="setDateRange"
/> />
</div> </div>
<filter-bar
v-if="shouldDisplayFilters"
class="js-filter-bar filtered-search-box gl-display-flex gl-mt-3 gl-mr-3 gl-border-none"
:group-path="currentGroupPath"
/>
</div> </div>
</div> </div>
<div v-if="!shouldRenderEmptyState" class="cycle-analytics gl-mt-0"> <div v-if="!shouldRenderEmptyState" class="cycle-analytics gl-mt-0">
...@@ -255,8 +260,9 @@ export default { ...@@ -255,8 +260,9 @@ export default {
:current-stage-events="currentStageEvents" :current-stage-events="currentStageEvents"
:no-data-svg-path="noDataSvgPath" :no-data-svg-path="noDataSvgPath"
:empty-state-message="selectedStageError" :empty-state-message="selectedStageError"
:has-path-navigation="featureFlags.hasPathNavigation"
> >
<template #nav> <template v-if="shouldDisplayVerticalNavigation" #nav>
<stage-table-nav <stage-table-nav
:current-stage="selectedStage" :current-stage="selectedStage"
:stages="activeStages" :stages="activeStages"
......
<script> <script>
import { GlPath, GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; import { GlPath, GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
import { PATH_BACKGROUND_COLOR } from '../constants';
export default { export default {
name: 'PathNavigation', name: 'PathNavigation',
...@@ -24,16 +23,9 @@ export default { ...@@ -24,16 +23,9 @@ export default {
default: () => {}, default: () => {},
}, },
}, },
backgroundColor: PATH_BACKGROUND_COLOR,
}; };
</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 <gl-path v-else :key="selectedStage.id" :items="stages" @selected="$emit('selected', $event)" />
v-else
:key="selectedStage.id"
:items="stages"
:background-color="$options.backgroundColor"
@selected="$emit('selected', $event)"
/>
</template> </template>
...@@ -55,6 +55,11 @@ export default { ...@@ -55,6 +55,11 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
hasPathNavigation: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
return { return {
...@@ -73,7 +78,8 @@ export default { ...@@ -73,7 +78,8 @@ export default {
return currentStageEvents.length && !isLoading && !isEmptyStage; return currentStageEvents.length && !isLoading && !isEmptyStage;
}, },
stageHeaders() { stageHeaders() {
return [ const verticalNavHeaders = !this.hasPathNavigation
? [
{ {
title: s__('ProjectLifecycle|Stage'), title: s__('ProjectLifecycle|Stage'),
description: __('The phase of the development lifecycle.'), description: __('The phase of the development lifecycle.'),
...@@ -86,16 +92,24 @@ export default { ...@@ -86,16 +92,24 @@ export default {
), ),
classes: 'median-header', classes: 'median-header',
}, },
]
: [];
return [
...verticalNavHeaders,
{ {
title: this.stageName, title: this.stageName,
description: __('The collection of events added to the data gathered for that stage.'), description: __('The collection of events added to the data gathered for that stage.'),
classes: 'event-header pl-3', classes: !this.hasPathNavigation
? 'event-header pl-3'
: 'event-header gl-align-items-flex-start! gl-w-half!',
displayHeader: !this.customStageFormActive, displayHeader: !this.customStageFormActive,
}, },
{ {
title: __('Time'), title: __('Time'),
description: __('The time taken by each data entry gathered by that stage.'), description: __('The time taken by each data entry gathered by that stage.'),
classes: 'total-time-header pr-5 text-right', classes: !this.hasPathNavigation
? 'total-time-header pr-5 text-right'
: 'total-time-header gl-align-items-flex-end! gl-text-right! gl-w-half!',
displayHeader: !this.customStageFormActive, displayHeader: !this.customStageFormActive,
}, },
]; ];
...@@ -124,7 +138,11 @@ export default { ...@@ -124,7 +138,11 @@ export default {
<div v-else class="card stage-panel"> <div v-else class="card stage-panel">
<div class="card-header gl-border-b-0"> <div class="card-header gl-border-b-0">
<nav class="col-headers"> <nav class="col-headers">
<ul> <ul
:class="{
'gl-display-flex! gl-justify-content-space-between! gl-flex-direction-row! gl-px-5!': hasPathNavigation,
}"
>
<stage-table-header <stage-table-header
v-for="({ title, description, classes, displayHeader = true }, i) in stageHeaders" v-for="({ title, description, classes, displayHeader = true }, i) in stageHeaders"
v-show="displayHeader" v-show="displayHeader"
...@@ -137,10 +155,14 @@ export default { ...@@ -137,10 +155,14 @@ export default {
</nav> </nav>
</div> </div>
<div class="stage-panel-body"> <div class="stage-panel-body">
<nav ref="stageNav" class="stage-nav gl-pl-2"> <nav v-if="!hasPathNavigation" ref="stageNav" class="stage-nav gl-pl-2">
<slot name="nav"></slot> <slot name="nav"></slot>
</nav> </nav>
<div class="section stage-events overflow-auto" :style="{ height: stageEventsHeight }"> <div
class="section stage-events overflow-auto"
:class="{ 'w-100': hasPathNavigation }"
:style="{ height: stageEventsHeight }"
>
<slot name="content"> <slot name="content">
<gl-loading-icon v-if="isLoadingStage" class="gl-mt-4" size="md" /> <gl-loading-icon v-if="isLoadingStage" class="gl-mt-4" size="md" />
<template v-else> <template v-else>
......
import { gray10 } from '@gitlab/ui/scss_to_js/scss_variables';
import { __ } from '~/locale'; import { __ } from '~/locale';
export const PROJECTS_PER_PAGE = 50; export const PROJECTS_PER_PAGE = 50;
...@@ -33,7 +32,6 @@ export const DEFAULT_STAGE_NAMES = [...Object.keys(EMPTY_STAGE_TEXT)]; ...@@ -33,7 +32,6 @@ export const DEFAULT_STAGE_NAMES = [...Object.keys(EMPTY_STAGE_TEXT)];
export const TASKS_BY_TYPE_SUBJECT_ISSUE = 'Issue'; export const TASKS_BY_TYPE_SUBJECT_ISSUE = 'Issue';
export const TASKS_BY_TYPE_SUBJECT_MERGE_REQUEST = 'MergeRequest'; export const TASKS_BY_TYPE_SUBJECT_MERGE_REQUEST = 'MergeRequest';
export const TASKS_BY_TYPE_MAX_LABELS = 15; export const TASKS_BY_TYPE_MAX_LABELS = 15;
export const PATH_BACKGROUND_COLOR = gray10;
export const TASKS_BY_TYPE_SUBJECT_FILTER_OPTIONS = { export const TASKS_BY_TYPE_SUBJECT_FILTER_OPTIONS = {
[TASKS_BY_TYPE_SUBJECT_ISSUE]: __('Issues'), [TASKS_BY_TYPE_SUBJECT_ISSUE]: __('Issues'),
......
...@@ -54,6 +54,7 @@ RSpec.describe 'Value stream analytics charts', :js do ...@@ -54,6 +54,7 @@ RSpec.describe 'Value stream analytics charts', :js do
end end
before do before do
stub_feature_flags(value_stream_analytics_path_navigation: false)
select_group(group) select_group(group)
end end
......
...@@ -85,6 +85,7 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do ...@@ -85,6 +85,7 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do
context 'Manual ordering' do context 'Manual ordering' do
before do before do
stub_feature_flags(value_stream_analytics_path_navigation: false)
select_group(group) select_group(group)
end end
...@@ -153,25 +154,6 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do ...@@ -153,25 +154,6 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do
end end
end end
context 'Add a stage button' do
before do
select_group(group)
end
it 'displays the custom stage form when clicked' do
expect(page).not_to have_text(s_('CustomCycleAnalytics|New stage'))
expect(page).to have_selector(add_stage_button, visible: true)
expect(page).to have_text(s_('CustomCycleAnalytics|Add a stage'))
expect(page).not_to have_selector("#{add_stage_button}.active")
page.find(add_stage_button).click
expect(page).to have_selector("#{add_stage_button}.active")
expect(page).to have_text(s_('CustomCycleAnalytics|New stage'))
end
end
shared_examples 'submits custom stage form successfully' do |stage_name| shared_examples 'submits custom stage form successfully' do |stage_name|
it 'custom stage is saved with confirmation message' do it 'custom stage is saved with confirmation message' do
fill_in name_field, with: stage_name fill_in name_field, with: stage_name
...@@ -309,6 +291,11 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do ...@@ -309,6 +291,11 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do
end end
end end
context 'With the path navigation feature flag disabled' do
before do
stub_feature_flags(value_stream_analytics_path_navigation: false)
end
context 'with a group' do context 'with a group' do
context 'selected' do context 'selected' do
before do before do
...@@ -359,7 +346,26 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do ...@@ -359,7 +346,26 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do
end end
end end
context 'Stage table' do context 'Add a stage button' do
before do
stub_feature_flags(value_stream_analytics_path_navigation: false)
select_group(group)
end
it 'displays the custom stage form when clicked' do
expect(page).not_to have_text(s_('CustomCycleAnalytics|New stage'))
expect(page).to have_selector(add_stage_button, visible: true)
expect(page).to have_text(s_('CustomCycleAnalytics|Add a stage'))
expect(page).not_to have_selector("#{add_stage_button}.active")
page.find(add_stage_button).click
expect(page).to have_selector("#{add_stage_button}.active")
expect(page).to have_text(s_('CustomCycleAnalytics|New stage'))
end
end
context 'default stages' do context 'default stages' do
def open_recover_stage_dropdown def open_recover_stage_dropdown
find(add_stage_button).click find(add_stage_button).click
...@@ -371,6 +377,7 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do ...@@ -371,6 +377,7 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do
end end
before do before do
stub_feature_flags(value_stream_analytics_path_navigation: false)
select_group(group) select_group(group)
toggle_more_options(first_default_stage) toggle_more_options(first_default_stage)
...@@ -422,6 +429,7 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do ...@@ -422,6 +429,7 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do
context 'custom stages' do context 'custom stages' do
before do before do
stub_feature_flags(value_stream_analytics_path_navigation: false)
create_custom_stage create_custom_stage
select_group(group) select_group(group)
...@@ -478,6 +486,8 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do ...@@ -478,6 +486,8 @@ RSpec.describe 'Customizable Group Value Stream Analytics', :js do
context 'hidden stage' do context 'hidden stage' do
before do before do
stub_feature_flags(value_stream_analytics_path_navigation: false)
select_group(group)
toggle_more_options(first_default_stage) toggle_more_options(first_default_stage)
click_button(_('Hide stage')) click_button(_('Hide stage'))
......
...@@ -29,7 +29,9 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -29,7 +29,9 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
def select_stage(name) def select_stage(name)
string_id = "CycleAnalyticsStage|#{name}" string_id = "CycleAnalyticsStage|#{name}"
page.find('.stage-nav .stage-nav-item .stage-name', text: s_(string_id), match: :prefer_exact).click within '[data-testid="gl-path-nav"]' do
page.find('li', text: s_(string_id), match: :prefer_exact).click
end
wait_for_requests wait_for_requests
end end
...@@ -121,32 +123,19 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -121,32 +123,19 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
shared_examples 'group value stream analytics' do shared_examples 'group value stream analytics' do
context 'stage panel' do context 'stage panel' do
it 'displays the stage table headers' do it 'displays the stage table headers' do
expect(page).to have_selector('.stage-header', visible: true)
expect(page).to have_selector('.median-header', visible: true)
expect(page).to have_selector('.event-header', visible: true) expect(page).to have_selector('.event-header', visible: true)
expect(page).to have_selector('.total-time-header', visible: true) expect(page).to have_selector('.total-time-header', visible: true)
end end
end end
context 'stage nav' do context 'vertical navigation' do
it 'displays the list of stages' do it 'does not show the vertical stage navigation' do
expect(page).to have_selector(stage_nav_selector, visible: true) expect(page).not_to have_selector(stage_nav_selector)
end
it 'displays the default list of stages' do
stage_nav = page.find(stage_nav_selector)
%w[Issue Plan Code Test Review Staging].each do |item|
string_id = "CycleAnalytics|#{item}"
expect(stage_nav).to have_content(s_(string_id))
end
end end
end end
context 'path nav' do context 'navigation' do
before do before do
stub_feature_flags(value_stream_analytics_path_navigation: true)
select_group(selected_group) select_group(selected_group)
end end
...@@ -190,9 +179,35 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -190,9 +179,35 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
select_group(group) select_group(group)
end end
it 'shows the path navigation' do it 'does not show the path navigation' do
expect(page).not_to have_selector(path_nav_selector) expect(page).not_to have_selector(path_nav_selector)
end end
it 'shows the vertical stage navigation' do
expect(page).to have_selector(stage_nav_selector, visible: true)
end
it 'displays the default list of stages' do
stage_nav = page.find(stage_nav_selector)
%w[Issue Plan Code Test Review Staging].each do |item|
string_id = "CycleAnalytics|#{item}"
expect(stage_nav).to have_content(s_(string_id))
end
end
it 'each stage will have median values', :sidekiq_might_not_need_inline do
stage_medians = page.all('.stage-nav .stage-median').collect(&:text)
expect(stage_medians).to eq(["Not enough data"] * 6)
end
it 'displays the stage table headers' do
expect(page).to have_selector('.stage-header', visible: true)
expect(page).to have_selector('.median-header', visible: true)
expect(page).to have_selector('.event-header', visible: true)
expect(page).to have_selector('.total-time-header', visible: true)
end
end end
context 'without valid query parameters set' do context 'without valid query parameters set' do
...@@ -306,12 +321,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -306,12 +321,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
{ title: 'Test', description: 'Total test time for all commits/merges', events_count: 0, median: 'Not enough data' } { title: 'Test', description: 'Total test time for all commits/merges', events_count: 0, median: 'Not enough data' }
] ]
it 'each stage will have median values', :sidekiq_might_not_need_inline do
stage_medians = page.all('.stage-nav .stage-median').collect(&:text)
expect(stage_medians).to eq(["5 days", "Not enough data", "about 5 hours", "Not enough data", "about 1 hour", "about 1 hour"])
end
it 'each stage will display the events description when selected', :sidekiq_might_not_need_inline do it 'each stage will display the events description when selected', :sidekiq_might_not_need_inline do
stages_without_data.each do |stage| stages_without_data.each do |stage|
select_stage(stage[:title]) select_stage(stage[:title])
...@@ -341,7 +350,7 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -341,7 +350,7 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
[].concat(stages_without_data, stages_with_data).each do |stage| [].concat(stages_without_data, stages_with_data).each do |stage|
select_stage(stage[:title]) select_stage(stage[:title])
expect(page.find('.stage-nav .active .stage-name').text).to eq(stage[:title]) expect(page.find('.js-path-navigation .gl-path-active-item-indigo').text).to eq(stage[:title])
end end
end end
...@@ -363,12 +372,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -363,12 +372,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
wait_for_stages_to_load wait_for_stages_to_load
end end
it 'will filter the stage median values' do
stage_medians = page.all('.stage-nav .stage-median').collect(&:text)
expect(stage_medians).to eq([_("Not enough data")] * 6)
end
it 'will filter the data' do it 'will filter the data' do
expect(page.find('[data-testid="vsa-stage-table"]')).to have_text(_("We don't have enough data to show this stage.")) expect(page.find('[data-testid="vsa-stage-table"]')).to have_text(_("We don't have enough data to show this stage."))
......
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