Commit 625d2a1d authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Fetch value streams and display dropdown

Adds a dropdown to switch the
selected value stream

Fetch stages from value stream
parent 1683ea48
<script>
import { GlButton, GlForm, GlFormInput, GlFormGroup, GlModal, GlModalDirective } from '@gitlab/ui';
import {
GlButton,
GlNewDropdown as GlDropdown,
GlNewDropdownItem as GlDropdownItem,
GlNewDropdownDivider as GlDropdownDivider,
GlForm,
GlFormInput,
GlFormGroup,
GlModal,
GlModalDirective,
} from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
import { sprintf, __ } from '~/locale';
import { debounce } from 'lodash';
......@@ -23,6 +33,9 @@ const validate = ({ name }) => {
export default {
components: {
GlButton,
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
GlForm,
GlFormInput,
GlFormGroup,
......@@ -41,6 +54,8 @@ export default {
...mapState({
isLoading: 'isCreatingValueStream',
initialFormErrors: 'createValueStreamErrors',
data: 'valueStreams',
selectedValueStream: 'selectedValueStream',
}),
isValid() {
return !this.errors?.name.length;
......@@ -48,6 +63,15 @@ export default {
invalidFeedback() {
return this.errors?.name.join('\n');
},
hasValueStreams() {
return Boolean(this.data.length);
},
selectedValueStreamName() {
return this?.selectedValueStream?.name || '';
},
selectedValueStreamId() {
return this?.selectedValueStream?.id || null;
},
},
mounted() {
const { initialFormErrors } = this;
......@@ -58,7 +82,7 @@ export default {
}
},
methods: {
...mapActions(['createValueStream']),
...mapActions(['createValueStream', 'setSelectedValueStream']),
onSubmit() {
const { name } = this;
return this.createValueStream({ name }).then(() => {
......@@ -73,12 +97,32 @@ export default {
const { name } = this;
this.errors = validate({ name });
}, 250),
isSelected(id) {
return this.selectedValueStreamId && this.selectedValueStreamId === id;
},
onSelect(id) {
this.setSelectedValueStream(id);
},
},
};
</script>
<template>
<gl-form>
<gl-button v-gl-modal-directive="'create-value-stream-modal'" @click="onHandleInput">{{
<gl-dropdown v-if="hasValueStreams" :text="selectedValueStreamName" right>
<gl-dropdown-item
v-for="{ id, name: streamName } in data"
:key="id"
:is-check-item="true"
:is-checked="isSelected(id)"
@click="onSelect(id)"
>{{ streamName }}</gl-dropdown-item
>
<gl-dropdown-divider />
<gl-dropdown-item v-gl-modal-directive="'create-value-stream-modal'" @click="onHandleInput">{{
__('Create new value stream')
}}</gl-dropdown-item>
</gl-dropdown>
<gl-button v-else v-gl-modal-directive="'create-value-stream-modal'" @click="onHandleInput">{{
__('Create new value stream')
}}</gl-button>
<gl-modal
......
......@@ -109,7 +109,13 @@ export const fetchCycleAnalyticsData = ({ dispatch }) => {
removeFlash();
dispatch('requestCycleAnalyticsData');
// TODO: we will need to do some extra refactoring here
// We need the selected value stream to be selected first
// once we have that, we can then fetch the groups stages and events,
// this is because they will now live under the /value_streams entity
return Promise.resolve()
.then(() => dispatch('fetchValueStreams'))
.then(() => dispatch('fetchGroupStagesAndEvents'))
.then(() => dispatch('fetchStageMedianValues'))
.then(() => dispatch('receiveCycleAnalyticsDataSuccess'))
......@@ -313,3 +319,34 @@ export const createValueStream = ({ commit, rootState }, data) => {
commit(types.RECEIVE_CREATE_VALUE_STREAM_ERROR, { data, message, errors });
});
};
export const setSelectedValueStream = ({ commit }, streamId) =>
commit(types.SET_SELECTED_VALUE_STREAM, streamId);
export const receiveValueStreams = ({ commit, dispatch }, { data }) => {
commit(types.RECEIVE_VALUE_STREAMS_SUCCESS, data);
const [firstStream] = data;
return dispatch('setSelectedValueStream', firstStream.id);
};
export const fetchValueStreams = ({ commit, dispatch, getters, state }, data) => {
const {
featureFlags: { hasCreateMultipleValueStreams = false },
} = state;
const { currentGroupPath } = getters;
if (hasCreateMultipleValueStreams) {
commit(types.REQUEST_VALUE_STREAMS);
return Api.cycleAnalyticsValueStreams(currentGroupPath)
.then(response => {
const { status, data: responseData } = response;
return dispatch('receiveValueStreams', { status, data: responseData });
})
.catch(({ response } = {}) => {
const { data: { message, errors } = null } = response;
commit(types.RECEIVE_VALUE_STREAMS_ERROR, { data, message, errors });
});
}
return Promise.resolve();
};
......@@ -6,6 +6,8 @@ import { transformStagesForPathNavigation } from '../utils';
export const hasNoAccessError = state => state.errorCode === httpStatus.FORBIDDEN;
export const currentValueStreamId = ({ selectedValueStream }) => selectedValueStream?.id || null;
export const currentGroupPath = ({ selectedGroup }) =>
selectedGroup && selectedGroup.fullPath ? selectedGroup.fullPath : null;
......
......@@ -5,6 +5,7 @@ export const SET_SELECTED_PROJECTS = 'SET_SELECTED_PROJECTS';
export const SET_SELECTED_STAGE = 'SET_SELECTED_STAGE';
export const SET_DATE_RANGE = 'SET_DATE_RANGE';
export const SET_SELECTED_FILTERS = 'SET_SELECTED_FILTERS';
export const SET_SELECTED_VALUE_STREAM = 'SET_SELECTED_VALUE_STREAM';
export const REQUEST_CYCLE_ANALYTICS_DATA = 'REQUEST_CYCLE_ANALYTICS_DATA';
export const RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS = 'RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS';
......@@ -39,3 +40,7 @@ export const RECEIVE_REORDER_STAGE_ERROR = 'RECEIVE_REORDER_STAGE_ERROR';
export const REQUEST_CREATE_VALUE_STREAM = 'REQUEST_CREATE_VALUE_STREAM';
export const RECEIVE_CREATE_VALUE_STREAM_SUCCESS = 'RECEIVE_CREATE_VALUE_STREAM_SUCCESS';
export const RECEIVE_CREATE_VALUE_STREAM_ERROR = 'RECEIVE_CREATE_VALUE_STREAM_ERROR';
export const REQUEST_VALUE_STREAMS = 'REQUEST_VALUE_STREAMS';
export const RECEIVE_VALUE_STREAMS_SUCCESS = 'RECEIVE_VALUE_STREAMS_SUCCESS';
export const RECEIVE_VALUE_STREAMS_ERROR = 'RECEIVE_VALUE_STREAMS_ERROR';
......@@ -134,4 +134,16 @@ export default {
state.isCreatingValueStream = false;
state.createValueStreamErrors = {};
},
[types.SET_SELECTED_VALUE_STREAM](state, streamId) {
state.selectedValueStream = state.valueStreams.find(({ id }) => id === streamId);
},
[types.REQUEST_VALUE_STREAMS](state) {
state.valueStreams = [];
},
[types.RECEIVE_VALUE_STREAMS_ERROR](state) {
state.valueStreams = [];
},
[types.RECEIVE_VALUE_STREAMS_SUCCESS](state, data) {
state.valueStreams = data;
},
};
......@@ -20,6 +20,7 @@ export default () => ({
selectedMilestone: null,
selectedAssignees: [],
selectedLabels: [],
selectedValueStream: null,
currentStageEvents: [],
......@@ -29,4 +30,5 @@ export default () => ({
stages: [],
summary: [],
medians: {},
valueStreams: [],
});
......@@ -15,6 +15,8 @@ export default {
cycleAnalyticsSummaryDataPath: '/groups/:id/-/analytics/value_stream_analytics/summary',
cycleAnalyticsTimeSummaryDataPath: '/groups/:id/-/analytics/value_stream_analytics/time_summary',
cycleAnalyticsGroupStagesAndEventsPath: '/groups/:id/-/analytics/value_stream_analytics/stages',
cycleAnalyticsValueStreamGroupStagesAndEventsPath:
'/groups/:id/-/analytics/value_stream_analytics/value_streams/:value_stream_id/stages',
cycleAnalyticsValueStreamsPath: '/groups/:id/-/analytics/value_stream_analytics/value_streams',
cycleAnalyticsStageEventsPath:
'/groups/:id/-/analytics/value_stream_analytics/stages/:stage_id/records',
......@@ -141,6 +143,14 @@ export default {
return axios.get(url, { params });
},
cycleAnalyticsValueStreamGroupStagesAndEvents(groupId, valueStreamId, params = {}) {
const url = Api.buildUrl(this.cycleAnalyticsValueStreamGroupStagesAndEventsPath)
.replace(':id', groupId)
.replace(':value_stream_id', valueStreamId);
return axios.get(url, { params });
},
cycleAnalyticsStageEvents(groupId, stageId, params = {}) {
const url = Api.buildUrl(this.cycleAnalyticsStageEventsPath)
.replace(':id', groupId)
......@@ -168,6 +178,11 @@ export default {
return axios.post(url, data);
},
cycleAnalyticsValueStreams(groupId, data) {
const url = Api.buildUrl(this.cycleAnalyticsValueStreamsPath).replace(':id', groupId);
return axios.get(url, data);
},
cycleAnalyticsStageUrl(stageId, groupId) {
return Api.buildUrl(this.cycleAnalyticsStagePath)
.replace(':id', groupId)
......
......@@ -246,6 +246,7 @@ describe('Cycle analytics actions', () => {
[],
[
{ type: 'requestCycleAnalyticsData' },
{ type: 'fetchValueStreams' },
{ type: 'fetchGroupStagesAndEvents' },
{ type: 'fetchStageMedianValues' },
{ type: 'receiveCycleAnalyticsDataSuccess' },
......
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