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
- **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**.
## 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.
......
......@@ -112,7 +112,7 @@ export default {
shouldDisplayFilterBar() {
// TODO: After we remove instance VSA currentGroupPath will be always set
// https://gitlab.com/gitlab-org/gitlab/-/issues/223735
return this.featureFlags.hasFilterBar && this.currentGroupPath;
return this.currentGroupPath;
},
shouldDisplayCreateMultipleValueStreams() {
return Boolean(
......
......@@ -16,7 +16,6 @@ export default () => {
cycleAnalyticsScatterplotEnabled: hasDurationChart = false,
cycleAnalyticsScatterplotMedianEnabled: hasDurationChartMedian = false,
valueStreamAnalyticsPathNavigation: hasPathNavigation = false,
valueStreamAnalyticsFilterBar: hasFilterBar = false,
valueStreamAnalyticsCreateMultipleValueStreams: hasCreateMultipleValueStreams = false,
analyticsSimilaritySearch: hasAnalyticsSimilaritySearch = false,
} = gon?.features;
......@@ -27,7 +26,6 @@ export default () => {
hasDurationChart,
hasDurationChartMedian,
hasPathNavigation,
hasFilterBar,
hasCreateMultipleValueStreams,
hasAnalyticsSimilaritySearch,
},
......
......@@ -8,15 +8,9 @@ import { removeFlash, handleErrorOrRethrow, isStageNameExistsError } from '../ut
export const setFeatureFlags = ({ commit }, 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);
const { featureFlags } = state;
if (featureFlags?.hasFilterBar) {
return dispatch('filters/initialize', {
groupPath: group.full_path,
});
}
return Promise.resolve();
return dispatch('filters/initialize', { groupPath: group.full_path });
};
export const setSelectedProjects = ({ commit }, projects) =>
......@@ -256,16 +250,12 @@ export const initializeCycleAnalytics = ({ dispatch, commit }, initialData = {})
commit(types.SET_FEATURE_FLAGS, featureFlags);
if (initialData.group?.fullPath) {
if (featureFlags?.hasFilterBar) {
dispatch('filters/initialize', {
groupPath: initialData.group.fullPath,
...initialData,
});
}
return dispatch('fetchCycleAnalyticsData').then(() =>
dispatch('initializeCycleAnalyticsSuccess'),
);
return Promise.resolve()
.then(() =>
dispatch('filters/initialize', { groupPath: initialData.group.fullPath, ...initialData }),
)
.then(() => dispatch('fetchCycleAnalyticsData'))
.then(() => dispatch('initializeCycleAnalyticsSuccess'));
}
return dispatch('initializeCycleAnalyticsSuccess');
};
......
......@@ -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_median_enabled, default_enabled: true)
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(:analytics_similarity_search, @group, default_enabled: true)
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
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
# This can be removed when the feature flag is removed
context 'create multiple value streams disabled' do
......
......@@ -21,7 +21,6 @@ RSpec.describe 'Group value stream analytics' do
cycleAnalyticsScatterplotEnabled: true,
cycleAnalyticsScatterplotMedianEnabled: true,
valueStreamAnalyticsPathNavigation: true,
valueStreamAnalyticsFilterBar: true,
analyticsSimilaritySearch: true
)
end
......@@ -38,18 +37,6 @@ RSpec.describe 'Group value stream analytics' do
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
before do
stub_feature_flags(value_stream_analytics_create_multiple_value_streams: false, thing: group)
......
......@@ -52,7 +52,6 @@ const defaultFeatureFlags = {
hasDurationChart: true,
hasDurationChartMedian: true,
hasPathNavigation: false,
hasFilterBar: false,
hasCreateMultipleValueStreams: false,
};
......@@ -192,7 +191,6 @@ describe('Cycle Analytics component', () => {
wrapper = createComponent({
featureFlags: {
hasPathNavigation: true,
hasFilterBar: true,
},
});
});
......@@ -294,7 +292,6 @@ describe('Cycle Analytics component', () => {
withStageSelected: true,
featureFlags: {
hasPathNavigation: true,
hasFilterBar: true,
},
});
});
......@@ -350,6 +347,10 @@ describe('Cycle Analytics component', () => {
displaysStageTable(true);
});
it('displays the filter bar', () => {
displaysFilterBar(true);
});
it('displays the add stage button', () => {
wrapper = createComponent({
opts: {
......@@ -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', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
......
......@@ -117,46 +117,29 @@ describe('Cycle analytics actions', () => {
});
describe('setSelectedGroup', () => {
it('commits the setSelectedGroup mutation', () => {
return testAction(
actions.setSelectedGroup,
{ ...selectedGroup },
state,
[{ type: types.SET_SELECTED_GROUP, payload: selectedGroup }],
[],
);
});
const { fullPath } = selectedGroup;
describe('with hasFilterBar=true', () => {
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 },
{ full_path: fullPath },
state,
[{ type: types.SET_SELECTED_GROUP, payload: { full_path: selectedGroup.fullPath } }],
[{ type: types.SET_SELECTED_GROUP, payload: { full_path: fullPath } }],
[
{
type: 'filters/initialize',
payload: {
groupPath: selectedGroup.fullPath,
groupPath: fullPath,
},
},
],
);
});
});
});
describe('fetchStageData', () => {
beforeEach(() => {
......
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