Commit 8f5e1ce0 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera

Merge branch '326701-move-vsa-filters-into-shared-component' into 'master'

Moves the VSA filters into a reusable component

See merge request gitlab-org/gitlab!65329
parents 6b587b1a 857d228b
...@@ -4,29 +4,23 @@ import { mapActions, mapState, mapGetters } from 'vuex'; ...@@ -4,29 +4,23 @@ import { mapActions, mapState, mapGetters } from 'vuex';
import PathNavigation from '~/cycle_analytics/components/path_navigation.vue'; import PathNavigation from '~/cycle_analytics/components/path_navigation.vue';
import { OVERVIEW_STAGE_ID } from '~/cycle_analytics/constants'; import { OVERVIEW_STAGE_ID } from '~/cycle_analytics/constants';
import UrlSync from '~/vue_shared/components/url_sync.vue'; import UrlSync from '~/vue_shared/components/url_sync.vue';
import DateRange from '../../shared/components/daterange.vue';
import ProjectsDropdownFilter from '../../shared/components/projects_dropdown_filter.vue';
import { DATE_RANGE_LIMIT } from '../../shared/constants';
import { toYmd } from '../../shared/utils'; import { toYmd } from '../../shared/utils';
import { PROJECTS_PER_PAGE } from '../constants';
import DurationChart from './duration_chart.vue'; import DurationChart from './duration_chart.vue';
import FilterBar from './filter_bar.vue';
import Metrics from './metrics.vue'; import Metrics from './metrics.vue';
import StageTable from './stage_table.vue'; import StageTable from './stage_table.vue';
import TypeOfWorkCharts from './type_of_work_charts.vue'; import TypeOfWorkCharts from './type_of_work_charts.vue';
import ValueStreamFilters from './value_stream_filters.vue';
import ValueStreamSelect from './value_stream_select.vue'; import ValueStreamSelect from './value_stream_select.vue';
export default { export default {
name: 'CycleAnalytics', name: 'CycleAnalytics',
components: { components: {
DateRange,
DurationChart, DurationChart,
GlEmptyState, GlEmptyState,
ProjectsDropdownFilter,
TypeOfWorkCharts, TypeOfWorkCharts,
StageTable, StageTable,
PathNavigation, PathNavigation,
FilterBar, ValueStreamFilters,
ValueStreamSelect, ValueStreamSelect,
UrlSync, UrlSync,
Metrics, Metrics,
...@@ -56,8 +50,8 @@ export default { ...@@ -56,8 +50,8 @@ export default {
'stages', 'stages',
'selectedStageEvents', 'selectedStageEvents',
'errorCode', 'errorCode',
'startDate', 'createdAfter',
'endDate', 'createdBefore',
'isLoadingValueStreams', 'isLoadingValueStreams',
'selectedStageError', 'selectedStageError',
'selectedValueStream', 'selectedValueStream',
...@@ -90,7 +84,7 @@ export default { ...@@ -90,7 +84,7 @@ export default {
return Boolean(!this.shouldRenderEmptyState && !this.isLoadingValueStreams); return Boolean(!this.shouldRenderEmptyState && !this.isLoadingValueStreams);
}, },
hasDateRangeSet() { hasDateRangeSet() {
return this.startDate && this.endDate; return this.createdAfter && this.createdBefore;
}, },
query() { query() {
const selectedProjectIds = this.selectedProjectIds?.length ? this.selectedProjectIds : null; const selectedProjectIds = this.selectedProjectIds?.length ? this.selectedProjectIds : null;
...@@ -109,8 +103,8 @@ export default { ...@@ -109,8 +103,8 @@ export default {
return { return {
value_stream_id: this.selectedValueStream?.id || null, value_stream_id: this.selectedValueStream?.id || null,
project_ids: selectedProjectIds, project_ids: selectedProjectIds,
created_after: toYmd(this.startDate), created_after: toYmd(this.createdAfter),
created_before: toYmd(this.endDate), created_before: toYmd(this.createdBefore),
stage_id: (!this.isOverviewStageSelected && this.selectedStage?.id) || null, // the `overview` stage is always the default, so dont persist the id if its selected stage_id: (!this.isOverviewStageSelected && this.selectedStage?.id) || null, // the `overview` stage is always the default, so dont persist the id if its selected
...paginationUrlParams, ...paginationUrlParams,
}; };
...@@ -118,12 +112,6 @@ export default { ...@@ -118,12 +112,6 @@ export default {
stageCount() { stageCount() {
return this.activeStages.length; return this.activeStages.length;
}, },
projectsQueryParams() {
return {
first: PROJECTS_PER_PAGE,
includeSubgroups: true,
};
},
}, },
methods: { methods: {
...mapActions([ ...mapActions([
...@@ -147,12 +135,16 @@ export default { ...@@ -147,12 +135,16 @@ export default {
this.updateStageTablePagination({ ...this.pagination, page: 1 }); this.updateStageTablePagination({ ...this.pagination, page: 1 });
} }
}, },
onSetDateRange({ startDate, endDate }) {
this.setDateRange({
createdAfter: new Date(startDate),
createdBefore: new Date(endDate),
});
},
onHandleUpdatePagination(data) { onHandleUpdatePagination(data) {
this.updateStageTablePagination(data); this.updateStageTablePagination(data);
}, },
}, },
multiProjectSelect: true,
maxDateRange: DATE_RANGE_LIMIT,
}; };
</script> </script>
<template> <template>
...@@ -183,37 +175,16 @@ export default { ...@@ -183,37 +175,16 @@ export default {
:selected-stage="selectedStage" :selected-stage="selectedStage"
@selected="onStageSelect" @selected="onStageSelect"
/> />
<div class="gl-mt-3 gl-py-2 gl-px-3 bg-gray-light border-top border-bottom"> <value-stream-filters
<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
v-if="shouldDisplayFilters"
class="gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-justify-content-space-between"
>
<projects-dropdown-filter
:key="currentGroup.id"
class="js-projects-dropdown-filter project-select gl-mb-2 gl-lg-mb-0"
:group-id="currentGroup.id" :group-id="currentGroup.id"
:group-namespace="currentGroupPath" :group-path="currentGroupPath"
:query-params="projectsQueryParams" :selected-projects="selectedProjects"
:multi-select="$options.multiProjectSelect" :start-date="createdAfter"
:default-projects="selectedProjects" :end-date="createdBefore"
@selected="onProjectsSelect" @selectProject="onProjectsSelect"
/> @setDateRange="onSetDateRange"
<date-range
:start-date="startDate"
:end-date="endDate"
:max-date-range="$options.maxDateRange"
:include-selected-date="true"
class="js-daterange-picker"
@change="setDateRange"
/> />
</div> </div>
</div>
</div>
<div v-if="!shouldRenderEmptyState" class="cycle-analytics gl-mt-2"> <div v-if="!shouldRenderEmptyState" class="cycle-analytics gl-mt-2">
<gl-empty-state <gl-empty-state
v-if="hasNoAccessError" v-if="hasNoAccessError"
......
<script>
import DateRange from '../../shared/components/daterange.vue';
import ProjectsDropdownFilter from '../../shared/components/projects_dropdown_filter.vue';
import { DATE_RANGE_LIMIT } from '../../shared/constants';
import { PROJECTS_PER_PAGE } from '../constants';
import FilterBar from './filter_bar.vue';
export default {
name: 'ValueStreamFilters',
components: {
DateRange,
ProjectsDropdownFilter,
FilterBar,
},
props: {
selectedProjects: {
type: Array,
required: false,
default: () => [],
},
hasProjectFilter: {
type: Boolean,
required: false,
default: true,
},
hasDateRangeFilter: {
type: Boolean,
required: false,
default: true,
},
groupId: {
type: Number,
required: true,
},
groupPath: {
type: String,
required: true,
},
startDate: {
type: Date,
required: false,
default: null,
},
endDate: {
type: Date,
required: false,
default: null,
},
},
computed: {
projectsQueryParams() {
return {
first: PROJECTS_PER_PAGE,
includeSubgroups: true,
};
},
},
multiProjectSelect: true,
maxDateRange: DATE_RANGE_LIMIT,
};
</script>
<template>
<div class="gl-mt-3 gl-py-2 gl-px-3 bg-gray-light border-top border-bottom">
<filter-bar
class="js-filter-bar filtered-search-box gl-display-flex gl-mb-2 gl-mr-3 gl-border-none"
:group-path="groupPath"
/>
<div
v-if="hasDateRangeFilter || hasProjectFilter"
class="gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-justify-content-space-between"
>
<projects-dropdown-filter
v-if="hasProjectFilter"
:key="groupId"
class="js-projects-dropdown-filter project-select gl-mb-2 gl-lg-mb-0"
:group-id="groupId"
:group-namespace="groupPath"
:query-params="projectsQueryParams"
:multi-select="$options.multiProjectSelect"
:default-projects="selectedProjects"
@selected="$emit('selectProject', $event)"
/>
<date-range
v-if="hasDateRangeFilter"
:start-date="startDate"
:end-date="endDate"
:max-date-range="$options.maxDateRange"
:include-selected-date="true"
class="js-daterange-picker"
@change="$emit('setDateRange', $event)"
/>
</div>
</div>
</template>
...@@ -34,9 +34,9 @@ export const setSelectedStage = ({ commit }, stage) => commit(types.SET_SELECTED ...@@ -34,9 +34,9 @@ export const setSelectedStage = ({ commit }, stage) => commit(types.SET_SELECTED
export const setDateRange = ( export const setDateRange = (
{ commit, dispatch, getters: { isOverviewStageSelected }, state: { selectedStage } }, { commit, dispatch, getters: { isOverviewStageSelected }, state: { selectedStage } },
{ startDate, endDate }, { createdAfter, createdBefore },
) => { ) => {
commit(types.SET_DATE_RANGE, { startDate, endDate }); commit(types.SET_DATE_RANGE, { createdBefore, createdAfter });
if (selectedStage && !isOverviewStageSelected) dispatch('fetchStageData', selectedStage.id); if (selectedStage && !isOverviewStageSelected) dispatch('fetchStageData', selectedStage.id);
return dispatch('fetchCycleAnalyticsData'); return dispatch('fetchCycleAnalyticsData');
}; };
......
...@@ -21,8 +21,8 @@ export const selectedProjectIds = ({ selectedProjects }) => ...@@ -21,8 +21,8 @@ export const selectedProjectIds = ({ selectedProjects }) =>
export const cycleAnalyticsRequestParams = (state, getters) => { export const cycleAnalyticsRequestParams = (state, getters) => {
const { const {
startDate = null, createdAfter = null,
endDate = null, createdBefore = null,
filters: { filters: {
authors: { selected: selectedAuthor }, authors: { selected: selectedAuthor },
milestones: { selected: selectedMilestone }, milestones: { selected: selectedMilestone },
...@@ -40,8 +40,8 @@ export const cycleAnalyticsRequestParams = (state, getters) => { ...@@ -40,8 +40,8 @@ export const cycleAnalyticsRequestParams = (state, getters) => {
return { return {
project_ids: getters.selectedProjectIds, project_ids: getters.selectedProjectIds,
created_after: startDate ? dateFormat(startDate, dateFormats.isoDate) : null, created_after: createdAfter ? dateFormat(createdAfter, dateFormats.isoDate) : null,
created_before: endDate ? dateFormat(endDate, dateFormats.isoDate) : null, created_before: createdBefore ? dateFormat(createdBefore, dateFormats.isoDate) : null,
...filterBarQuery, ...filterBarQuery,
}; };
}; };
......
import { getDurationChartData } from '../../../utils'; import { getDurationChartData } from '../../../utils';
export const durationChartPlottableData = (state, _, rootState) => { export const durationChartPlottableData = (state, _, rootState) => {
const { startDate, endDate } = rootState; const { createdAfter, createdBefore } = rootState;
const { durationData } = state; const { durationData } = state;
const selectedStagesDurationData = durationData.filter((stage) => stage.selected); const selectedStagesDurationData = durationData.filter((stage) => stage.selected);
const plottableData = getDurationChartData(selectedStagesDurationData, startDate, endDate); const plottableData = getDurationChartData(
selectedStagesDurationData,
createdAfter,
createdBefore,
);
return plottableData.length ? plottableData : []; return plottableData.length ? plottableData : [];
}; };
...@@ -2,24 +2,29 @@ import { getTasksByTypeData } from '../../../utils'; ...@@ -2,24 +2,29 @@ import { getTasksByTypeData } from '../../../utils';
export const selectedTasksByTypeFilters = (state = {}, _, rootState = {}) => { export const selectedTasksByTypeFilters = (state = {}, _, rootState = {}) => {
const { selectedLabelIds = [], subject } = state; const { selectedLabelIds = [], subject } = state;
const { currentGroup, selectedProjectIds = [], startDate = null, endDate = null } = rootState; const {
currentGroup,
selectedProjectIds = [],
createdAfter = null,
createdBefore = null,
} = rootState;
return { return {
currentGroup, currentGroup,
selectedProjectIds, selectedProjectIds,
startDate, createdAfter,
endDate, createdBefore,
selectedLabelIds, selectedLabelIds,
subject, subject,
}; };
}; };
export const tasksByTypeChartData = ({ data = [] } = {}, _, rootState = {}) => { export const tasksByTypeChartData = ({ data = [] } = {}, _, rootState = {}) => {
const { startDate = null, endDate = null } = rootState; const { createdAfter = null, createdBefore = null } = rootState;
return data.length return data.length
? getTasksByTypeData({ ? getTasksByTypeData({
data, data,
startDate, startDate: createdAfter,
endDate, endDate: createdBefore,
}) })
: { groupBy: [], data: [] }; : { groupBy: [], data: [] };
}; };
...@@ -14,9 +14,9 @@ export default { ...@@ -14,9 +14,9 @@ export default {
[types.SET_SELECTED_STAGE](state, rawData) { [types.SET_SELECTED_STAGE](state, rawData) {
state.selectedStage = convertObjectPropsToCamelCase(rawData); state.selectedStage = convertObjectPropsToCamelCase(rawData);
}, },
[types.SET_DATE_RANGE](state, { startDate, endDate }) { [types.SET_DATE_RANGE](state, { createdBefore, createdAfter }) {
state.startDate = startDate; state.createdBefore = createdBefore;
state.endDate = endDate; state.createdAfter = createdAfter;
}, },
[types.SET_STAGE_EVENTS](state, data = []) { [types.SET_STAGE_EVENTS](state, data = []) {
state.formEvents = data.map((ev) => convertObjectPropsToCamelCase(ev, { deep: true })); state.formEvents = data.map((ev) => convertObjectPropsToCamelCase(ev, { deep: true }));
...@@ -88,8 +88,8 @@ export default { ...@@ -88,8 +88,8 @@ export default {
state, state,
{ {
group = null, group = null,
createdAfter: startDate = null, createdAfter = null,
createdBefore: endDate = null, createdBefore = null,
selectedProjects = [], selectedProjects = [],
selectedValueStream = {}, selectedValueStream = {},
defaultStageConfig = [], defaultStageConfig = [],
...@@ -100,8 +100,8 @@ export default { ...@@ -100,8 +100,8 @@ export default {
state.currentGroup = group; state.currentGroup = group;
state.selectedProjects = selectedProjects; state.selectedProjects = selectedProjects;
state.selectedValueStream = selectedValueStream; state.selectedValueStream = selectedValueStream;
state.startDate = startDate; state.createdBefore = createdBefore;
state.endDate = endDate; state.createdAfter = createdAfter;
state.defaultStageConfig = defaultStageConfig; state.defaultStageConfig = defaultStageConfig;
Vue.set(state, 'pagination', { Vue.set(state, 'pagination', {
......
...@@ -4,8 +4,8 @@ export default () => ({ ...@@ -4,8 +4,8 @@ export default () => ({
featureFlags: {}, featureFlags: {},
defaultStageConfig: [], defaultStageConfig: [],
startDate: null, createdAfter: null,
endDate: null, createdBefore: null,
isLoading: false, isLoading: false,
isLoadingStage: false, isLoadingStage: false,
......
...@@ -5,14 +5,12 @@ import MockAdapter from 'axios-mock-adapter'; ...@@ -5,14 +5,12 @@ import MockAdapter from 'axios-mock-adapter';
import Vuex from 'vuex'; import Vuex from 'vuex';
import Component from 'ee/analytics/cycle_analytics/components/base.vue'; import Component from 'ee/analytics/cycle_analytics/components/base.vue';
import DurationChart from 'ee/analytics/cycle_analytics/components/duration_chart.vue'; import DurationChart from 'ee/analytics/cycle_analytics/components/duration_chart.vue';
import FilterBar from 'ee/analytics/cycle_analytics/components/filter_bar.vue';
import Metrics from 'ee/analytics/cycle_analytics/components/metrics.vue'; import Metrics from 'ee/analytics/cycle_analytics/components/metrics.vue';
import StageTable from 'ee/analytics/cycle_analytics/components/stage_table.vue'; import StageTable from 'ee/analytics/cycle_analytics/components/stage_table.vue';
import TypeOfWorkCharts from 'ee/analytics/cycle_analytics/components/type_of_work_charts.vue'; import TypeOfWorkCharts from 'ee/analytics/cycle_analytics/components/type_of_work_charts.vue';
import ValueStreamFilters from 'ee/analytics/cycle_analytics/components/value_stream_filters.vue';
import ValueStreamSelect from 'ee/analytics/cycle_analytics/components/value_stream_select.vue'; import ValueStreamSelect from 'ee/analytics/cycle_analytics/components/value_stream_select.vue';
import createStore from 'ee/analytics/cycle_analytics/store'; import createStore from 'ee/analytics/cycle_analytics/store';
import Daterange from 'ee/analytics/shared/components/daterange.vue';
import ProjectsDropdownFilter from 'ee/analytics/shared/components/projects_dropdown_filter.vue';
import { toYmd } from 'ee/analytics/shared/utils'; import { toYmd } from 'ee/analytics/shared/utils';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import PathNavigation from '~/cycle_analytics/components/path_navigation.vue'; import PathNavigation from '~/cycle_analytics/components/path_navigation.vue';
...@@ -55,8 +53,8 @@ const [selectedValueStream] = mockData.valueStreams; ...@@ -55,8 +53,8 @@ const [selectedValueStream] = mockData.valueStreams;
const initialCycleAnalyticsState = { const initialCycleAnalyticsState = {
selectedValueStream, selectedValueStream,
createdAfter: mockData.startDate, createdAfter: mockData.createdAfter,
createdBefore: mockData.endDate, createdBefore: mockData.createdBefore,
group: currentGroup, group: currentGroup,
stage, stage,
}; };
...@@ -159,14 +157,6 @@ describe('EE Value Stream Analytics component', () => { ...@@ -159,14 +157,6 @@ describe('EE Value Stream Analytics component', () => {
const findPathNavigation = () => wrapper.findComponent(PathNavigation); const findPathNavigation = () => wrapper.findComponent(PathNavigation);
const findStageTable = () => wrapper.findComponent(StageTable); const findStageTable = () => wrapper.findComponent(StageTable);
const displaysProjectsDropdownFilter = (flag) => {
expect(wrapper.findComponent(ProjectsDropdownFilter).exists()).toBe(flag);
};
const displaysDateRangePicker = (flag) => {
expect(wrapper.findComponent(Daterange).exists()).toBe(flag);
};
const displaysMetrics = (flag) => { const displaysMetrics = (flag) => {
expect(wrapper.findComponent(Metrics).exists()).toBe(flag); expect(wrapper.findComponent(Metrics).exists()).toBe(flag);
}; };
...@@ -187,8 +177,8 @@ describe('EE Value Stream Analytics component', () => { ...@@ -187,8 +177,8 @@ describe('EE Value Stream Analytics component', () => {
expect(findPathNavigation().exists()).toBe(flag); expect(findPathNavigation().exists()).toBe(flag);
}; };
const displaysFilterBar = (flag) => { const displaysFilters = (flag) => {
expect(wrapper.findComponent(FilterBar).exists()).toBe(flag); expect(wrapper.findComponent(ValueStreamFilters).exists()).toBe(flag);
}; };
const displaysValueStreamSelect = (flag) => { const displaysValueStreamSelect = (flag) => {
...@@ -215,14 +205,6 @@ describe('EE Value Stream Analytics component', () => { ...@@ -215,14 +205,6 @@ describe('EE Value Stream Analytics component', () => {
expect(emptyState.props('svgPath')).toBe(emptyStateSvgPath); expect(emptyState.props('svgPath')).toBe(emptyStateSvgPath);
}); });
it('does not display the projects filter', () => {
displaysProjectsDropdownFilter(false);
});
it('does not display the date range picker', () => {
displaysDateRangePicker(false);
});
it('does not display the metrics cards', () => { it('does not display the metrics cards', () => {
displaysMetrics(false); displaysMetrics(false);
}); });
...@@ -263,14 +245,6 @@ describe('EE Value Stream Analytics component', () => { ...@@ -263,14 +245,6 @@ describe('EE Value Stream Analytics component', () => {
expect(emptyState.props('svgPath')).toBe(noAccessSvgPath); expect(emptyState.props('svgPath')).toBe(noAccessSvgPath);
}); });
it('does not display the projects filter', () => {
displaysProjectsDropdownFilter(false);
});
it('does not display the date range picker', () => {
displaysDateRangePicker(false);
});
it('does not display the metrics', () => { it('does not display the metrics', () => {
displaysMetrics(false); displaysMetrics(false);
}); });
...@@ -309,27 +283,12 @@ describe('EE Value Stream Analytics component', () => { ...@@ -309,27 +283,12 @@ describe('EE Value Stream Analytics component', () => {
expect(wrapper.findComponent(GlEmptyState).exists()).toBe(false); expect(wrapper.findComponent(GlEmptyState).exists()).toBe(false);
}); });
it('displays the projects filter', () => {
displaysProjectsDropdownFilter(true);
expect(wrapper.findComponent(ProjectsDropdownFilter).props()).toEqual(
expect.objectContaining({
queryParams: wrapper.vm.projectsQueryParams,
multiSelect: wrapper.vm.$options.multiProjectSelect,
}),
);
});
it('displays the value stream select component', () => { it('displays the value stream select component', () => {
displaysValueStreamSelect(true); displaysValueStreamSelect(true);
}); });
it('displays the date range picker', () => {
displaysDateRangePicker(true);
});
it('displays the filter bar', () => { it('displays the filter bar', () => {
displaysFilterBar(true); displaysFilters(true);
}); });
it('displays the metrics', () => { it('displays the metrics', () => {
...@@ -505,8 +464,8 @@ describe('EE Value Stream Analytics component', () => { ...@@ -505,8 +464,8 @@ describe('EE Value Stream Analytics component', () => {
describe('Url parameters', () => { describe('Url parameters', () => {
const defaultParams = { const defaultParams = {
value_stream_id: selectedValueStream.id, value_stream_id: selectedValueStream.id,
created_after: toYmd(mockData.startDate), created_after: toYmd(mockData.createdAfter),
created_before: toYmd(mockData.endDate), created_before: toYmd(mockData.createdBefore),
stage_id: null, stage_id: null,
project_ids: null, project_ids: null,
sort: null, sort: null,
...@@ -556,8 +515,8 @@ describe('EE Value Stream Analytics component', () => { ...@@ -556,8 +515,8 @@ describe('EE Value Stream Analytics component', () => {
it('sets the value_stream_id url parameter', async () => { it('sets the value_stream_id url parameter', async () => {
await shouldMergeUrlParams(wrapper, { await shouldMergeUrlParams(wrapper, {
...defaultParams, ...defaultParams,
created_after: toYmd(mockData.startDate), created_after: toYmd(mockData.createdAfter),
created_before: toYmd(mockData.endDate), created_before: toYmd(mockData.createdBefore),
project_ids: null, project_ids: null,
}); });
}); });
...@@ -573,8 +532,8 @@ describe('EE Value Stream Analytics component', () => { ...@@ -573,8 +532,8 @@ describe('EE Value Stream Analytics component', () => {
it('sets the project_ids url parameter', async () => { it('sets the project_ids url parameter', async () => {
await shouldMergeUrlParams(wrapper, { await shouldMergeUrlParams(wrapper, {
...defaultParams, ...defaultParams,
created_after: toYmd(mockData.startDate), created_after: toYmd(mockData.createdAfter),
created_before: toYmd(mockData.endDate), created_before: toYmd(mockData.createdBefore),
project_ids: selectedProjectIds, project_ids: selectedProjectIds,
stage_id: null, stage_id: null,
}); });
......
import { shallowMount } from '@vue/test-utils';
import FilterBar from 'ee/analytics/cycle_analytics/components/filter_bar.vue';
import ValueStreamFilters from 'ee/analytics/cycle_analytics/components/value_stream_filters.vue';
import Daterange from 'ee/analytics/shared/components/daterange.vue';
import ProjectsDropdownFilter from 'ee/analytics/shared/components/projects_dropdown_filter.vue';
import {
createdAfter as startDate,
createdBefore as endDate,
currentGroup,
selectedProjects,
} from '../mock_data';
function createComponent(props = {}) {
return shallowMount(ValueStreamFilters, {
propsData: {
selectedProjects,
groupId: currentGroup.id,
groupPath: currentGroup.fullPath,
startDate,
endDate,
...props,
},
});
}
describe('ValueStreamFilters', () => {
let wrapper;
const findProjectsDropdown = () => wrapper.findComponent(ProjectsDropdownFilter);
const findDateRangePicker = () => wrapper.findComponent(Daterange);
const findFilterBar = () => wrapper.findComponent(FilterBar);
beforeEach(() => {
wrapper = createComponent();
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('will render the filter bar', () => {
expect(findFilterBar().exists()).toBe(true);
});
it('will render the projects dropdown', () => {
expect(findProjectsDropdown().exists()).toBe(true);
expect(wrapper.findComponent(ProjectsDropdownFilter).props()).toEqual(
expect.objectContaining({
queryParams: wrapper.vm.projectsQueryParams,
multiSelect: wrapper.vm.$options.multiProjectSelect,
}),
);
});
it('will render the date range picker', () => {
expect(findDateRangePicker().exists()).toBe(true);
});
it('will emit `selectProject` when a project is selected', () => {
findProjectsDropdown().vm.$emit('selected');
expect(wrapper.emitted('selectProject')).not.toBeUndefined();
});
it('will emit `setDateRange` when the date range changes', () => {
findDateRangePicker().vm.$emit('change');
expect(wrapper.emitted('setDateRange')).not.toBeUndefined();
});
describe('hasDateRangeFilter = false', () => {
beforeEach(() => {
wrapper = createComponent({ hasDateRangeFilter: false });
});
it('will not render the date range picker', () => {
expect(findDateRangePicker().exists()).toBe(false);
});
});
describe('hasProjectFilter = false', () => {
beforeEach(() => {
wrapper = createComponent({ hasProjectFilter: false });
});
it('will not render the project dropdown', () => {
expect(findProjectsDropdown().exists()).toBe(false);
});
});
});
...@@ -158,8 +158,8 @@ export const stageCounts = rawStageMedians.reduce((acc, { id, value }) => { ...@@ -158,8 +158,8 @@ export const stageCounts = rawStageMedians.reduce((acc, { id, value }) => {
return { ...acc, [stageId]: value }; return { ...acc, [stageId]: value };
}, {}); }, {});
export const endDate = new Date(2019, 0, 14); export const createdBefore = new Date(2019, 0, 14);
export const startDate = getDateInPast(endDate, DEFAULT_DAYS_IN_PAST); export const createdAfter = getDateInPast(createdBefore, DEFAULT_DAYS_IN_PAST);
export const issueEvents = deepCamelCase(stageFixtures.issue); export const issueEvents = deepCamelCase(stageFixtures.issue);
export const planEvents = deepCamelCase(stageFixtures.plan); export const planEvents = deepCamelCase(stageFixtures.plan);
...@@ -204,7 +204,7 @@ export const labelEndEvent = customStageLabelEvents.find( ...@@ -204,7 +204,7 @@ export const labelEndEvent = customStageLabelEvents.find(
(ev) => ev.identifier === labelStartEvent.allowedEndEvents[0], (ev) => ev.identifier === labelStartEvent.allowedEndEvents[0],
); );
const dateRange = getDatesInRange(startDate, endDate, toYmd); const dateRange = getDatesInRange(createdAfter, createdBefore, toYmd);
export const apiTasksByTypeData = getJSONFixture( export const apiTasksByTypeData = getJSONFixture(
'analytics/charts/type_of_work/tasks_by_type.json', 'analytics/charts/type_of_work/tasks_by_type.json',
......
...@@ -10,8 +10,8 @@ import httpStatusCodes from '~/lib/utils/http_status'; ...@@ -10,8 +10,8 @@ import httpStatusCodes from '~/lib/utils/http_status';
import { import {
currentGroup, currentGroup,
allowedStages as stages, allowedStages as stages,
startDate, createdAfter,
endDate, createdBefore,
customizableStagesAndEvents, customizableStagesAndEvents,
endpoints, endpoints,
valueStreams, valueStreams,
...@@ -53,8 +53,8 @@ describe('Value Stream Analytics actions', () => { ...@@ -53,8 +53,8 @@ describe('Value Stream Analytics actions', () => {
beforeEach(() => { beforeEach(() => {
state = { state = {
startDate, createdAfter,
endDate, createdBefore,
stages: [], stages: [],
featureFlags: { featureFlags: {
hasDurationChart: true, hasDurationChart: true,
...@@ -269,7 +269,7 @@ describe('Value Stream Analytics actions', () => { ...@@ -269,7 +269,7 @@ describe('Value Stream Analytics actions', () => {
} }
beforeEach(() => { beforeEach(() => {
state = { ...state, currentGroup, startDate, endDate }; state = { ...state, currentGroup, createdAfter, createdBefore };
}); });
it(`dispatches actions for required value stream analytics analytics data`, () => { it(`dispatches actions for required value stream analytics analytics data`, () => {
...@@ -962,7 +962,7 @@ describe('Value Stream Analytics actions', () => { ...@@ -962,7 +962,7 @@ describe('Value Stream Analytics actions', () => {
describe.each` describe.each`
targetAction | payload | mutations targetAction | payload | mutations
${actions.setDateRange} | ${{ startDate, endDate }} | ${[{ type: 'SET_DATE_RANGE', payload: { startDate, endDate } }]} ${actions.setDateRange} | ${{ createdAfter, createdBefore }} | ${[{ type: 'SET_DATE_RANGE', payload: { createdAfter, createdBefore } }]}
${actions.setFilters} | ${''} | ${[]} ${actions.setFilters} | ${''} | ${[]}
`('$action', ({ targetAction, payload, mutations }) => { `('$action', ({ targetAction, payload, mutations }) => {
let stateWithOverview = null; let stateWithOverview = null;
......
...@@ -9,8 +9,8 @@ import { ...@@ -9,8 +9,8 @@ import {
getFilterValues, getFilterValues,
} from 'jest/vue_shared/components/filtered_search_bar/store/modules/filters/test_helper'; } from 'jest/vue_shared/components/filtered_search_bar/store/modules/filters/test_helper';
import { import {
startDate, createdAfter,
endDate, createdBefore,
allowedStages, allowedStages,
selectedProjects, selectedProjects,
issueStage, issueStage,
...@@ -97,8 +97,8 @@ describe('Value Stream Analytics getters', () => { ...@@ -97,8 +97,8 @@ describe('Value Stream Analytics getters', () => {
currentGroup: { currentGroup: {
fullPath, fullPath,
}, },
startDate, createdAfter,
endDate, createdBefore,
selectedProjects, selectedProjects,
filters: { filters: {
authors: { selected: selectedUserParams[0] }, authors: { selected: selectedUserParams[0] },
......
...@@ -10,8 +10,8 @@ import httpStatusCodes from '~/lib/utils/http_status'; ...@@ -10,8 +10,8 @@ import httpStatusCodes from '~/lib/utils/http_status';
import { import {
group, group,
allowedStages as stages, allowedStages as stages,
startDate, createdAfter,
endDate, createdBefore,
rawDurationData, rawDurationData,
transformedDurationData, transformedDurationData,
endpoints, endpoints,
...@@ -27,8 +27,8 @@ const [selectedValueStream] = valueStreams; ...@@ -27,8 +27,8 @@ const [selectedValueStream] = valueStreams;
const error = new Error(`Request failed with status code ${httpStatusCodes.BAD_REQUEST}`); const error = new Error(`Request failed with status code ${httpStatusCodes.BAD_REQUEST}`);
const rootState = { const rootState = {
startDate, createdAfter,
endDate, createdBefore,
stages: [...activeStages, hiddenStage], stages: [...activeStages, hiddenStage],
selectedGroup, selectedGroup,
selectedValueStream, selectedValueStream,
......
import * as getters from 'ee/analytics/cycle_analytics/store/modules/duration_chart/getters'; import * as getters from 'ee/analytics/cycle_analytics/store/modules/duration_chart/getters';
import { import {
startDate, createdAfter,
endDate, createdBefore,
transformedDurationData, transformedDurationData,
durationChartPlottableData, durationChartPlottableData,
} from '../../../mock_data'; } from '../../../mock_data';
const rootState = { const rootState = {
startDate, createdAfter,
endDate, createdBefore,
}; };
describe('DurationChart getters', () => { describe('DurationChart getters', () => {
......
...@@ -11,7 +11,13 @@ import * as types from 'ee/analytics/cycle_analytics/store/modules/type_of_work/ ...@@ -11,7 +11,13 @@ import * as types from 'ee/analytics/cycle_analytics/store/modules/type_of_work/
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import createFlash from '~/flash'; import createFlash from '~/flash';
import httpStatusCodes from '~/lib/utils/http_status'; import httpStatusCodes from '~/lib/utils/http_status';
import { groupLabels, endpoints, startDate, endDate, rawTasksByTypeData } from '../../../mock_data'; import {
groupLabels,
endpoints,
createdAfter,
createdBefore,
rawTasksByTypeData,
} from '../../../mock_data';
jest.mock('~/flash'); jest.mock('~/flash');
...@@ -33,7 +39,7 @@ describe('Type of work actions', () => { ...@@ -33,7 +39,7 @@ describe('Type of work actions', () => {
...rootGetters, ...rootGetters,
...getters, ...getters,
...state, ...state,
rootState: { startDate, endDate }, rootState: { createdAfter, createdBefore },
}; };
beforeEach(() => { beforeEach(() => {
......
...@@ -2,13 +2,13 @@ import { tasksByTypeChartData } from 'ee/analytics/cycle_analytics/store/modules ...@@ -2,13 +2,13 @@ import { tasksByTypeChartData } from 'ee/analytics/cycle_analytics/store/modules
import { import {
rawTasksByTypeData, rawTasksByTypeData,
transformedTasksByTypeData, transformedTasksByTypeData,
startDate, createdAfter,
endDate, createdBefore,
} from '../../../mock_data'; } from '../../../mock_data';
describe('Type of work getters', () => { describe('Type of work getters', () => {
describe('tasksByTypeChartData', () => { describe('tasksByTypeChartData', () => {
const rootState = { startDate, endDate }; const rootState = { createdAfter, createdBefore };
describe('with data', () => { describe('with data', () => {
it('correctly transforms the raw task by type data', () => { it('correctly transforms the raw task by type data', () => {
expect(tasksByTypeChartData(rawTasksByTypeData, null, rootState)).toEqual( expect(tasksByTypeChartData(rawTasksByTypeData, null, rootState)).toEqual(
......
...@@ -11,8 +11,8 @@ import { ...@@ -11,8 +11,8 @@ import {
codeStage, codeStage,
stagingStage, stagingStage,
reviewStage, reviewStage,
startDate, createdAfter,
endDate, createdBefore,
selectedProjects, selectedProjects,
customizableStagesAndEvents, customizableStagesAndEvents,
valueStreams, valueStreams,
...@@ -91,7 +91,7 @@ describe('Value Stream Analytics mutations', () => { ...@@ -91,7 +91,7 @@ describe('Value Stream Analytics mutations', () => {
mutation | payload | expectedState mutation | payload | expectedState
${types.SET_FEATURE_FLAGS} | ${{ hasDurationChart: true }} | ${{ featureFlags: { hasDurationChart: true } }} ${types.SET_FEATURE_FLAGS} | ${{ hasDurationChart: true }} | ${{ featureFlags: { hasDurationChart: true } }}
${types.SET_SELECTED_PROJECTS} | ${selectedProjects} | ${{ selectedProjects }} ${types.SET_SELECTED_PROJECTS} | ${selectedProjects} | ${{ selectedProjects }}
${types.SET_DATE_RANGE} | ${{ startDate, endDate }} | ${{ startDate, endDate }} ${types.SET_DATE_RANGE} | ${{ createdAfter, createdBefore }} | ${{ createdAfter, createdBefore }}
${types.SET_SELECTED_STAGE} | ${{ id: 'first-stage' }} | ${{ selectedStage: { id: 'first-stage' } }} ${types.SET_SELECTED_STAGE} | ${{ id: 'first-stage' }} | ${{ selectedStage: { id: 'first-stage' } }}
${types.RECEIVE_CREATE_VALUE_STREAM_ERROR} | ${valueStreamErrors} | ${{ createValueStreamErrors: expectedValueStreamErrors, isCreatingValueStream: false }} ${types.RECEIVE_CREATE_VALUE_STREAM_ERROR} | ${valueStreamErrors} | ${{ createValueStreamErrors: expectedValueStreamErrors, isCreatingValueStream: false }}
${types.RECEIVE_UPDATE_VALUE_STREAM_ERROR} | ${valueStreamErrors} | ${{ createValueStreamErrors: expectedValueStreamErrors, isEditingValueStream: false }} ${types.RECEIVE_UPDATE_VALUE_STREAM_ERROR} | ${valueStreamErrors} | ${{ createValueStreamErrors: expectedValueStreamErrors, isEditingValueStream: false }}
...@@ -235,8 +235,8 @@ describe('Value Stream Analytics mutations', () => { ...@@ -235,8 +235,8 @@ describe('Value Stream Analytics mutations', () => {
stateKey | expectedState stateKey | expectedState
${'isLoading'} | ${true} ${'isLoading'} | ${true}
${'selectedProjects'} | ${initialData.selectedProjects} ${'selectedProjects'} | ${initialData.selectedProjects}
${'startDate'} | ${initialData.createdAfter} ${'createdAfter'} | ${initialData.createdAfter}
${'endDate'} | ${initialData.createdBefore} ${'createdBefore'} | ${initialData.createdBefore}
`('$stateKey will be set to $expectedState', ({ stateKey, expectedState }) => { `('$stateKey will be set to $expectedState', ({ stateKey, expectedState }) => {
state = {}; state = {};
mutations[types.INITIALIZE_VSA](state, initialData); mutations[types.INITIALIZE_VSA](state, initialData);
......
...@@ -32,8 +32,8 @@ import { ...@@ -32,8 +32,8 @@ import {
transformedDurationData, transformedDurationData,
flattenedDurationData, flattenedDurationData,
durationChartPlottableData, durationChartPlottableData,
startDate, createdAfter,
endDate, createdBefore,
issueStage, issueStage,
rawCustomStage, rawCustomStage,
rawTasksByTypeData, rawTasksByTypeData,
...@@ -141,7 +141,11 @@ describe('Value Stream Analytics utils', () => { ...@@ -141,7 +141,11 @@ describe('Value Stream Analytics utils', () => {
describe('cycleAnalyticsDurationChart', () => { describe('cycleAnalyticsDurationChart', () => {
it('computes the plottable data as expected', () => { it('computes the plottable data as expected', () => {
const plottableData = getDurationChartData(transformedDurationData, startDate, endDate); const plottableData = getDurationChartData(
transformedDurationData,
createdAfter,
createdBefore,
);
expect(plottableData).toStrictEqual(durationChartPlottableData); expect(plottableData).toStrictEqual(durationChartPlottableData);
}); });
...@@ -251,7 +255,7 @@ describe('Value Stream Analytics utils', () => { ...@@ -251,7 +255,7 @@ describe('Value Stream Analytics utils', () => {
describe('getTasksByTypeData', () => { describe('getTasksByTypeData', () => {
let transformed = {}; let transformed = {};
const groupBy = getDatesInRange(startDate, endDate, toYmd); const groupBy = getDatesInRange(createdAfter, createdBefore, toYmd);
// only return the values, drop the date which is the first paramater // only return the values, drop the date which is the first paramater
const extractSeriesValues = ({ label: { title: name }, series }) => { const extractSeriesValues = ({ label: { title: name }, series }) => {
return { return {
...@@ -268,17 +272,23 @@ describe('Value Stream Analytics utils', () => { ...@@ -268,17 +272,23 @@ describe('Value Stream Analytics utils', () => {
}); });
it('will return blank arrays if given no data', () => { it('will return blank arrays if given no data', () => {
[{ data: [], startDate, endDate }, [], {}].forEach((chartData) => { [{ data: [], startDate: createdAfter, endDate: createdBefore }, [], {}].forEach(
(chartData) => {
transformed = getTasksByTypeData(chartData); transformed = getTasksByTypeData(chartData);
['data', 'groupBy'].forEach((key) => { ['data', 'groupBy'].forEach((key) => {
expect(transformed[key]).toEqual([]); expect(transformed[key]).toEqual([]);
}); });
}); },
);
}); });
describe('with data', () => { describe('with data', () => {
beforeEach(() => { beforeEach(() => {
transformed = getTasksByTypeData({ data: rawTasksByTypeData, startDate, endDate }); transformed = getTasksByTypeData({
data: rawTasksByTypeData,
startDate: createdAfter,
endDate: createdBefore,
});
}); });
it('will return an object with the properties needed for the chart', () => { it('will return an object with the properties needed for the chart', () => {
...@@ -293,11 +303,11 @@ describe('Value Stream Analytics utils', () => { ...@@ -293,11 +303,11 @@ describe('Value Stream Analytics utils', () => {
}); });
it('the start date is the first element', () => { it('the start date is the first element', () => {
expect(transformed.groupBy[0]).toEqual(toYmd(startDate)); expect(transformed.groupBy[0]).toEqual(toYmd(createdAfter));
}); });
it('the end date is the last element', () => { it('the end date is the last element', () => {
expect(transformed.groupBy[transformed.groupBy.length - 1]).toEqual(toYmd(endDate)); expect(transformed.groupBy[transformed.groupBy.length - 1]).toEqual(toYmd(createdBefore));
}); });
}); });
......
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