Commit 1684737b authored by Sarah Groff Hennigh-Palermo's avatar Sarah Groff Hennigh-Palermo Committed by Andrew Fontaine

Pipeline Graph: Update Conditions for Showing Switcher

parent e728550b
...@@ -13,5 +13,6 @@ export const GRAPHQL = 'graphql'; ...@@ -13,5 +13,6 @@ export const GRAPHQL = 'graphql';
export const STAGE_VIEW = 'stage'; export const STAGE_VIEW = 'stage';
export const LAYER_VIEW = 'layer'; export const LAYER_VIEW = 'layer';
export const VIEW_TYPE_KEY = 'pipeline_graph_view_type';
export const IID_FAILURE = 'missing_iid'; export const IID_FAILURE = 'missing_iid';
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql'; import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
import { __ } from '~/locale'; import { __ } from '~/locale';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '../../constants'; import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '../../constants';
import { reportToSentry } from '../../utils'; import { reportToSentry } from '../../utils';
import { listByLayers } from '../parsing_utils'; import { listByLayers } from '../parsing_utils';
import { IID_FAILURE, LAYER_VIEW, STAGE_VIEW } from './constants'; import { IID_FAILURE, LAYER_VIEW, STAGE_VIEW, VIEW_TYPE_KEY } from './constants';
import PipelineGraph from './graph_component.vue'; import PipelineGraph from './graph_component.vue';
import GraphViewSelector from './graph_view_selector.vue'; import GraphViewSelector from './graph_view_selector.vue';
import { import {
...@@ -22,6 +23,7 @@ export default { ...@@ -22,6 +23,7 @@ export default {
GlAlert, GlAlert,
GlLoadingIcon, GlLoadingIcon,
GraphViewSelector, GraphViewSelector,
LocalStorageSync,
PipelineGraph, PipelineGraph,
}, },
mixins: [glFeatureFlagMixin()], mixins: [glFeatureFlagMixin()],
...@@ -143,7 +145,7 @@ export default { ...@@ -143,7 +145,7 @@ export default {
return this.$apollo.queries.pipeline.loading && !this.pipeline; return this.$apollo.queries.pipeline.loading && !this.pipeline;
}, },
showGraphViewSelector() { showGraphViewSelector() {
return Boolean(this.glFeatures.pipelineGraphLayersView && this.pipeline); return Boolean(this.glFeatures.pipelineGraphLayersView && this.pipeline?.usesNeeds);
}, },
}, },
mounted() { mounted() {
...@@ -184,6 +186,7 @@ export default { ...@@ -184,6 +186,7 @@ export default {
this.currentViewType = type; this.currentViewType = type;
}, },
}, },
viewTypeKey: VIEW_TYPE_KEY,
}; };
</script> </script>
<template> <template>
...@@ -191,11 +194,17 @@ export default { ...@@ -191,11 +194,17 @@ export default {
<gl-alert v-if="showAlert" :variant="alert.variant" @dismiss="hideAlert"> <gl-alert v-if="showAlert" :variant="alert.variant" @dismiss="hideAlert">
{{ alert.text }} {{ alert.text }}
</gl-alert> </gl-alert>
<local-storage-sync
:storage-key="$options.viewTypeKey"
:value="currentViewType"
@input="updateViewType"
>
<graph-view-selector <graph-view-selector
v-if="showGraphViewSelector" v-if="showGraphViewSelector"
:type="currentViewType" :type="currentViewType"
@updateViewType="updateViewType" @updateViewType="updateViewType"
/> />
</local-storage-sync>
<gl-loading-icon v-if="showLoadingIcon" class="gl-mx-auto gl-my-4" size="lg" /> <gl-loading-icon v-if="showLoadingIcon" class="gl-mx-auto gl-my-4" size="lg" />
<pipeline-graph <pipeline-graph
v-if="pipeline" v-if="pipeline"
......
...@@ -57,7 +57,7 @@ export default { ...@@ -57,7 +57,7 @@ export default {
<template> <template>
<div class="gl-display-flex gl-align-items-center gl-my-4"> <div class="gl-display-flex gl-align-items-center gl-my-4">
<span>{{ $options.i18n.labelText }}</span> <span>{{ $options.i18n.labelText }}</span>
<gl-dropdown class="gl-ml-4"> <gl-dropdown data-testid="pipeline-view-selector" class="gl-ml-4">
<template #button-content> <template #button-content>
<gl-sprintf :message="currentDropdownText"> <gl-sprintf :message="currentDropdownText">
<template #code="{ content }"> <template #code="{ content }">
......
...@@ -27,6 +27,7 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) { ...@@ -27,6 +27,7 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) {
__typename __typename
id id
iid iid
usesNeeds
downstream { downstream {
__typename __typename
nodes { nodes {
......
...@@ -2,9 +2,15 @@ import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; ...@@ -2,9 +2,15 @@ import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount } from '@vue/test-utils';
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql'; import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
import { IID_FAILURE, LAYER_VIEW, STAGE_VIEW } from '~/pipelines/components/graph/constants'; import {
IID_FAILURE,
LAYER_VIEW,
STAGE_VIEW,
VIEW_TYPE_KEY,
} from '~/pipelines/components/graph/constants';
import PipelineGraph from '~/pipelines/components/graph/graph_component.vue'; import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
import PipelineGraphWrapper from '~/pipelines/components/graph/graph_component_wrapper.vue'; import PipelineGraphWrapper from '~/pipelines/components/graph/graph_component_wrapper.vue';
import GraphViewSelector from '~/pipelines/components/graph/graph_view_selector.vue'; import GraphViewSelector from '~/pipelines/components/graph/graph_view_selector.vue';
...@@ -21,6 +27,7 @@ const defaultProvide = { ...@@ -21,6 +27,7 @@ const defaultProvide = {
describe('Pipeline graph wrapper', () => { describe('Pipeline graph wrapper', () => {
Vue.use(VueApollo); Vue.use(VueApollo);
useLocalStorageSpy();
let wrapper; let wrapper;
const getAlert = () => wrapper.find(GlAlert); const getAlert = () => wrapper.find(GlAlert);
...@@ -216,7 +223,7 @@ describe('Pipeline graph wrapper', () => { ...@@ -216,7 +223,7 @@ describe('Pipeline graph wrapper', () => {
}); });
describe('view dropdown', () => { describe('view dropdown', () => {
describe('when feature flag is off', () => { describe('when pipelineGraphLayersView feature flag is off', () => {
beforeEach(async () => { beforeEach(async () => {
createComponentWithApollo(); createComponentWithApollo();
jest.runOnlyPendingTimers(); jest.runOnlyPendingTimers();
...@@ -228,7 +235,7 @@ describe('Pipeline graph wrapper', () => { ...@@ -228,7 +235,7 @@ describe('Pipeline graph wrapper', () => {
}); });
}); });
describe('when feature flag is on', () => { describe('when pipelineGraphLayersView feature flag is on', () => {
let layersFn; let layersFn;
beforeEach(async () => { beforeEach(async () => {
layersFn = jest.spyOn(parsingUtils, 'listByLayers'); layersFn = jest.spyOn(parsingUtils, 'listByLayers');
...@@ -245,7 +252,7 @@ describe('Pipeline graph wrapper', () => { ...@@ -245,7 +252,7 @@ describe('Pipeline graph wrapper', () => {
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
}); });
it('appears', () => { it('appears when pipeline uses needs', () => {
expect(getViewSelector().exists()).toBe(true); expect(getViewSelector().exists()).toBe(true);
}); });
...@@ -259,6 +266,11 @@ describe('Pipeline graph wrapper', () => { ...@@ -259,6 +266,11 @@ describe('Pipeline graph wrapper', () => {
expect(getStageColumnTitle().text()).toBe(''); expect(getStageColumnTitle().text()).toBe('');
}); });
it('saves the view type to local storage', async () => {
await getViewSelector().vm.$emit('updateViewType', LAYER_VIEW);
expect(localStorage.setItem.mock.calls).toEqual([[VIEW_TYPE_KEY, LAYER_VIEW]]);
});
it('calls listByLayers only once no matter how many times view is switched', async () => { it('calls listByLayers only once no matter how many times view is switched', async () => {
expect(layersFn).not.toHaveBeenCalled(); expect(layersFn).not.toHaveBeenCalled();
await getViewSelector().vm.$emit('updateViewType', LAYER_VIEW); await getViewSelector().vm.$emit('updateViewType', LAYER_VIEW);
...@@ -269,5 +281,53 @@ describe('Pipeline graph wrapper', () => { ...@@ -269,5 +281,53 @@ describe('Pipeline graph wrapper', () => {
expect(layersFn).toHaveBeenCalledTimes(1); expect(layersFn).toHaveBeenCalledTimes(1);
}); });
}); });
describe('when feature flag is on and local storage is set', () => {
beforeEach(async () => {
localStorage.setItem(VIEW_TYPE_KEY, LAYER_VIEW);
createComponentWithApollo({
provide: {
glFeatures: {
pipelineGraphLayersView: true,
},
},
mountFn: mount,
});
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
});
it('reads the view type from localStorage when available', () => {
expect(wrapper.find('[data-testid="pipeline-view-selector"] code').text()).toContain(
'needs:',
);
});
});
describe('when feature flag is on but pipeline does not use needs', () => {
beforeEach(async () => {
const nonNeedsResponse = { ...mockPipelineResponse };
nonNeedsResponse.data.project.pipeline.usesNeeds = false;
createComponentWithApollo({
provide: {
glFeatures: {
pipelineGraphLayersView: true,
},
},
mountFn: mount,
getPipelineDetailsHandler: jest.fn().mockResolvedValue(nonNeedsResponse),
});
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
});
it('does not appear when pipeline does not use needs', () => {
expect(getViewSelector().exists()).toBe(false);
});
});
}); });
}); });
...@@ -8,6 +8,7 @@ export const mockPipelineResponse = { ...@@ -8,6 +8,7 @@ export const mockPipelineResponse = {
__typename: 'Pipeline', __typename: 'Pipeline',
id: 163, id: 163,
iid: '22', iid: '22',
usesNeeds: true,
downstream: null, downstream: null,
upstream: null, upstream: null,
stages: { stages: {
...@@ -569,6 +570,7 @@ export const wrappedPipelineReturn = { ...@@ -569,6 +570,7 @@ export const wrappedPipelineReturn = {
__typename: 'Pipeline', __typename: 'Pipeline',
id: 'gid://gitlab/Ci::Pipeline/175', id: 'gid://gitlab/Ci::Pipeline/175',
iid: '38', iid: '38',
usesNeeds: true,
downstream: { downstream: {
__typename: 'PipelineConnection', __typename: 'PipelineConnection',
nodes: [], nodes: [],
......
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