Commit 6df4c4bd authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '225456-feature-flag-enable-value_stream_analytics_filter_bar-feature' into 'master'

Enable value stream analytics filter bar

Closes #225456

See merge request gitlab-org/gitlab!38576
parents 6ee374d8 44142994
...@@ -48,7 +48,30 @@ There are seven stages that are tracked as part of the Value Stream Analytics ca ...@@ -48,7 +48,30 @@ There are seven stages that are tracked as part of the Value Stream Analytics ca
- **Total** (Total) - **Total** (Total)
- Total lifecycle time. That is, the velocity of the project or team. [Previously known](https://gitlab.com/gitlab-org/gitlab/-/issues/38317) as **Production**. - Total lifecycle time. That is, the velocity of the project or team. [Previously known](https://gitlab.com/gitlab-org/gitlab/-/issues/38317) as **Production**.
## Date ranges ## Filter the analytics data
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13216) in GitLab 13.3
GitLab provides the ability to filter analytics based on the following parameters:
- Milestones (Group level)
- Labels (Group level)
- Author
- Assignees
To filter results:
1. Select a group.
1. Click on the filter bar.
1. Select a parameter to filter by.
1. Select a value from the autocompleted results, or type to refine the results.
![Value stream analytics filter bar](img/vsa_filter_bar_v13.3.png "Active filter bar for value stream analytics")
NOTE: **Note:**
Filtering is available only for group-level Value Stream Analytics.
### Date ranges
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13216) in GitLab 12.4. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13216) in GitLab 12.4.
......
...@@ -112,7 +112,7 @@ export default { ...@@ -112,7 +112,7 @@ export default {
shouldDisplayFilterBar() { shouldDisplayFilterBar() {
// TODO: After we remove instance VSA currentGroupPath will be always set // TODO: After we remove instance VSA currentGroupPath will be always set
// https://gitlab.com/gitlab-org/gitlab/-/issues/223735 // https://gitlab.com/gitlab-org/gitlab/-/issues/223735
return this.featureFlags.hasFilterBar && this.currentGroupPath; return this.currentGroupPath;
}, },
shouldDisplayCreateMultipleValueStreams() { shouldDisplayCreateMultipleValueStreams() {
return Boolean( return Boolean(
......
...@@ -16,7 +16,6 @@ export default () => { ...@@ -16,7 +16,6 @@ export default () => {
cycleAnalyticsScatterplotEnabled: hasDurationChart = false, cycleAnalyticsScatterplotEnabled: hasDurationChart = false,
cycleAnalyticsScatterplotMedianEnabled: hasDurationChartMedian = false, cycleAnalyticsScatterplotMedianEnabled: hasDurationChartMedian = false,
valueStreamAnalyticsPathNavigation: hasPathNavigation = false, valueStreamAnalyticsPathNavigation: hasPathNavigation = false,
valueStreamAnalyticsFilterBar: hasFilterBar = false,
valueStreamAnalyticsCreateMultipleValueStreams: hasCreateMultipleValueStreams = false, valueStreamAnalyticsCreateMultipleValueStreams: hasCreateMultipleValueStreams = false,
analyticsSimilaritySearch: hasAnalyticsSimilaritySearch = false, analyticsSimilaritySearch: hasAnalyticsSimilaritySearch = false,
} = gon?.features; } = gon?.features;
...@@ -27,7 +26,6 @@ export default () => { ...@@ -27,7 +26,6 @@ export default () => {
hasDurationChart, hasDurationChart,
hasDurationChartMedian, hasDurationChartMedian,
hasPathNavigation, hasPathNavigation,
hasFilterBar,
hasCreateMultipleValueStreams, hasCreateMultipleValueStreams,
hasAnalyticsSimilaritySearch, hasAnalyticsSimilaritySearch,
}, },
......
...@@ -8,15 +8,9 @@ import { removeFlash, handleErrorOrRethrow, isStageNameExistsError } from '../ut ...@@ -8,15 +8,9 @@ import { removeFlash, handleErrorOrRethrow, isStageNameExistsError } from '../ut
export const setFeatureFlags = ({ commit }, featureFlags) => export const setFeatureFlags = ({ commit }, featureFlags) =>
commit(types.SET_FEATURE_FLAGS, featureFlags); commit(types.SET_FEATURE_FLAGS, featureFlags);
export const setSelectedGroup = ({ commit, dispatch, state }, group) => { export const setSelectedGroup = ({ commit, dispatch }, group) => {
commit(types.SET_SELECTED_GROUP, group); commit(types.SET_SELECTED_GROUP, group);
const { featureFlags } = state; return dispatch('filters/initialize', { groupPath: group.full_path });
if (featureFlags?.hasFilterBar) {
return dispatch('filters/initialize', {
groupPath: group.full_path,
});
}
return Promise.resolve();
}; };
export const setSelectedProjects = ({ commit }, projects) => export const setSelectedProjects = ({ commit }, projects) =>
...@@ -256,16 +250,12 @@ export const initializeCycleAnalytics = ({ dispatch, commit }, initialData = {}) ...@@ -256,16 +250,12 @@ export const initializeCycleAnalytics = ({ dispatch, commit }, initialData = {})
commit(types.SET_FEATURE_FLAGS, featureFlags); commit(types.SET_FEATURE_FLAGS, featureFlags);
if (initialData.group?.fullPath) { if (initialData.group?.fullPath) {
if (featureFlags?.hasFilterBar) { return Promise.resolve()
dispatch('filters/initialize', { .then(() =>
groupPath: initialData.group.fullPath, dispatch('filters/initialize', { groupPath: initialData.group.fullPath, ...initialData }),
...initialData, )
}); .then(() => dispatch('fetchCycleAnalyticsData'))
} .then(() => dispatch('initializeCycleAnalyticsSuccess'));
return dispatch('fetchCycleAnalyticsData').then(() =>
dispatch('initializeCycleAnalyticsSuccess'),
);
} }
return dispatch('initializeCycleAnalyticsSuccess'); return dispatch('initializeCycleAnalyticsSuccess');
}; };
......
...@@ -15,7 +15,6 @@ class Analytics::CycleAnalyticsController < Analytics::ApplicationController ...@@ -15,7 +15,6 @@ class Analytics::CycleAnalyticsController < Analytics::ApplicationController
push_frontend_feature_flag(:cycle_analytics_scatterplot_enabled, default_enabled: true) push_frontend_feature_flag(:cycle_analytics_scatterplot_enabled, default_enabled: true)
push_frontend_feature_flag(:cycle_analytics_scatterplot_median_enabled, default_enabled: true) push_frontend_feature_flag(:cycle_analytics_scatterplot_median_enabled, default_enabled: true)
push_frontend_feature_flag(:value_stream_analytics_path_navigation, @group) push_frontend_feature_flag(:value_stream_analytics_path_navigation, @group)
push_frontend_feature_flag(:value_stream_analytics_filter_bar, @group)
push_frontend_feature_flag(:value_stream_analytics_create_multiple_value_streams, @group) push_frontend_feature_flag(:value_stream_analytics_create_multiple_value_streams, @group)
push_frontend_feature_flag(:analytics_similarity_search, @group, default_enabled: true) push_frontend_feature_flag(:analytics_similarity_search, @group, default_enabled: true)
end end
......
---
title: Add value stream analytics filter bar
merge_request: 38576
author:
type: added
...@@ -177,19 +177,6 @@ RSpec.describe 'Group Value Stream Analytics', :js do ...@@ -177,19 +177,6 @@ RSpec.describe 'Group Value Stream Analytics', :js do
end end
end end
context 'with filter bar feature flag disabled' do
before do
stub_feature_flags(value_stream_analytics_filter_bar: false)
visit analytics_cycle_analytics_path
select_group
end
it 'does not show the filter bar' do
expect(page).not_to have_selector(filter_bar_selector)
end
end
# Adding this context as part of a fix for https://gitlab.com/gitlab-org/gitlab/-/issues/233439 # Adding this context as part of a fix for https://gitlab.com/gitlab-org/gitlab/-/issues/233439
# This can be removed when the feature flag is removed # This can be removed when the feature flag is removed
context 'create multiple value streams disabled' do context 'create multiple value streams disabled' do
......
...@@ -21,7 +21,6 @@ RSpec.describe 'Group value stream analytics' do ...@@ -21,7 +21,6 @@ RSpec.describe 'Group value stream analytics' do
cycleAnalyticsScatterplotEnabled: true, cycleAnalyticsScatterplotEnabled: true,
cycleAnalyticsScatterplotMedianEnabled: true, cycleAnalyticsScatterplotMedianEnabled: true,
valueStreamAnalyticsPathNavigation: true, valueStreamAnalyticsPathNavigation: true,
valueStreamAnalyticsFilterBar: true,
analyticsSimilaritySearch: true analyticsSimilaritySearch: true
) )
end end
...@@ -38,18 +37,6 @@ RSpec.describe 'Group value stream analytics' do ...@@ -38,18 +37,6 @@ RSpec.describe 'Group value stream analytics' do
end end
end end
context 'when `value_stream_analytics_filter_bar` is disabled for a group' do
before do
stub_feature_flags(value_stream_analytics_filter_bar: false, thing: group)
end
it 'pushes disabled feature flag to the frontend' do
visit group_analytics_cycle_analytics_path(group)
expect(page).to have_pushed_frontend_feature_flags(valueStreamAnalyticsFilterBar: false)
end
end
context 'when `value_stream_analytics_create_multiple_value_streams` is disabled for a group' do context 'when `value_stream_analytics_create_multiple_value_streams` is disabled for a group' do
before do before do
stub_feature_flags(value_stream_analytics_create_multiple_value_streams: false, thing: group) stub_feature_flags(value_stream_analytics_create_multiple_value_streams: false, thing: group)
......
...@@ -52,7 +52,6 @@ const defaultFeatureFlags = { ...@@ -52,7 +52,6 @@ const defaultFeatureFlags = {
hasDurationChart: true, hasDurationChart: true,
hasDurationChartMedian: true, hasDurationChartMedian: true,
hasPathNavigation: false, hasPathNavigation: false,
hasFilterBar: false,
hasCreateMultipleValueStreams: false, hasCreateMultipleValueStreams: false,
}; };
...@@ -192,7 +191,6 @@ describe('Cycle Analytics component', () => { ...@@ -192,7 +191,6 @@ describe('Cycle Analytics component', () => {
wrapper = createComponent({ wrapper = createComponent({
featureFlags: { featureFlags: {
hasPathNavigation: true, hasPathNavigation: true,
hasFilterBar: true,
}, },
}); });
}); });
...@@ -294,7 +292,6 @@ describe('Cycle Analytics component', () => { ...@@ -294,7 +292,6 @@ describe('Cycle Analytics component', () => {
withStageSelected: true, withStageSelected: true,
featureFlags: { featureFlags: {
hasPathNavigation: true, hasPathNavigation: true,
hasFilterBar: true,
}, },
}); });
}); });
...@@ -350,6 +347,10 @@ describe('Cycle Analytics component', () => { ...@@ -350,6 +347,10 @@ describe('Cycle Analytics component', () => {
displaysStageTable(true); displaysStageTable(true);
}); });
it('displays the filter bar', () => {
displaysFilterBar(true);
});
it('displays the add stage button', () => { it('displays the add stage button', () => {
wrapper = createComponent({ wrapper = createComponent({
opts: { opts: {
...@@ -409,38 +410,6 @@ describe('Cycle Analytics component', () => { ...@@ -409,38 +410,6 @@ describe('Cycle Analytics component', () => {
}); });
}); });
describe('filter bar', () => {
describe('disabled', () => {
beforeEach(() => {
wrapper = createComponent({
withStageSelected: true,
featureFlags: {
hasFilterBar: false,
},
});
});
it('does not display the filter bar', () => {
displaysFilterBar(false);
});
});
describe('enabled', () => {
beforeEach(() => {
wrapper = createComponent({
withStageSelected: true,
featureFlags: {
hasFilterBar: true,
},
});
});
it('displays the filter bar', () => {
displaysFilterBar(true);
});
});
});
describe('StageTable', () => { describe('StageTable', () => {
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
......
...@@ -117,44 +117,27 @@ describe('Cycle analytics actions', () => { ...@@ -117,44 +117,27 @@ describe('Cycle analytics actions', () => {
}); });
describe('setSelectedGroup', () => { describe('setSelectedGroup', () => {
const { fullPath } = selectedGroup;
beforeEach(() => {
mock = new MockAdapter(axios);
});
it('commits the setSelectedGroup mutation', () => { it('commits the setSelectedGroup mutation', () => {
return testAction( return testAction(
actions.setSelectedGroup, actions.setSelectedGroup,
{ ...selectedGroup }, { full_path: fullPath },
state, state,
[{ type: types.SET_SELECTED_GROUP, payload: selectedGroup }], [{ type: types.SET_SELECTED_GROUP, payload: { full_path: fullPath } }],
[], [
); {
}); type: 'filters/initialize',
payload: {
describe('with hasFilterBar=true', () => { groupPath: fullPath,
beforeEach(() => {
state = {
...state,
featureFlags: {
...state.featureFlags,
hasFilterBar: true,
},
};
mock = new MockAdapter(axios);
});
it('commits the setSelectedGroup mutation', () => {
return testAction(
actions.setSelectedGroup,
{ full_path: selectedGroup.fullPath },
state,
[{ type: types.SET_SELECTED_GROUP, payload: { full_path: selectedGroup.fullPath } }],
[
{
type: 'filters/initialize',
payload: {
groupPath: selectedGroup.fullPath,
},
}, },
], },
); ],
}); );
}); });
}); });
......
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