Commit 97d5c52a authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Replace vsa stage slug with id

Previously, default value stream stages did not have an `id` when
they were initialized, the `id` is assigned after a change
is made to the value stream and it is persisted. To work around
this we would use the value stream `title` instead, but this
causes issues when the user's language is changed.

Default value stream stages now have an `id` so we should
always use that instead.

Changelog: fixed
EE: true
parent b41f073f
......@@ -124,7 +124,7 @@ export default {
this.setSelectedProjects(projects);
},
onStageSelect(stage) {
if (stage.slug === OVERVIEW_STAGE_ID) {
if (stage.id === OVERVIEW_STAGE_ID) {
this.setDefaultSelectedStage();
} else {
this.setSelectedStage(stage);
......
......@@ -25,7 +25,6 @@ export const FETCH_VALUE_STREAM_DATA = 'fetchValueStreamData';
export const OVERVIEW_STAGE_CONFIG = {
id: OVERVIEW_STAGE_ID,
slug: OVERVIEW_STAGE_ID,
title: __('Overview'),
icon: 'home',
};
......
......@@ -78,7 +78,7 @@ export const fetchStageMedianValues = ({ dispatch, commit, getters }) => {
activeStages,
currentValueStreamId,
} = getters;
const stageIds = activeStages.map((s) => s.slug);
const stageIds = activeStages.map((s) => s.id);
dispatch('requestStageMedianValues');
return Promise.all(
......@@ -115,7 +115,7 @@ export const fetchStageCountValues = ({ commit, getters }) => {
activeStages,
currentValueStreamId,
} = getters;
const stageIds = activeStages.map((s) => s.slug);
const stageIds = activeStages.map((s) => s.id);
commit(types.REQUEST_STAGE_COUNTS);
return Promise.all(
......
......@@ -25,16 +25,16 @@ export const fetchDurationData = ({ dispatch, commit, rootGetters }) => {
} = rootGetters;
return Promise.all(
activeStages.map((stage) => {
const { slug } = stage;
const { id } = stage;
return Api.cycleAnalyticsDurationChart({
groupId: currentGroupPath,
valueStreamId: currentValueStreamId,
stageId: slug,
stageId: id,
params: cycleAnalyticsRequestParams,
})
.then(checkForDataError)
.then(({ data }) => ({ slug, selected: true, data }));
.then(({ data }) => ({ id, selected: true, data }));
}),
)
.then((data) => commit(types.RECEIVE_DURATION_DATA_SUCCESS, data))
......@@ -45,7 +45,7 @@ export const updateSelectedDurationChartStages = ({ state, commit }, stages) =>
const setSelectedPropertyOnStages = (data) =>
data.map((stage) => {
const selected = stages.reduce((result, object) => {
if (object.slug === stage.slug) return true;
if (object.id === stage.id) return true;
return result;
}, false);
......
import dateFormat from 'dateformat';
import { isNumber, uniqBy } from 'lodash';
import { uniqBy } from 'lodash';
import { dateFormats } from '~/analytics/shared/constants';
import { toYmd } from '~/analytics/shared/utils';
import { OVERVIEW_STAGE_ID } from '~/cycle_analytics/constants';
......@@ -8,7 +8,6 @@ import createFlash from '~/flash';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { newDate, dayAfter, secondsToDays, getDatesInRange } from '~/lib/utils/datetime_utility';
import httpStatus from '~/lib/utils/http_status';
import { convertToSnakeCase } from '~/lib/utils/text_utility';
const EVENT_TYPE_LABEL = 'label';
......@@ -45,45 +44,12 @@ export const isLabelEvent = (labelEvents = [], ev = null) =>
export const getLabelEventsIdentifiers = (events = []) =>
events.filter((ev) => ev.type && ev.type === EVENT_TYPE_LABEL).map((i) => i.identifier);
/**
* Checks if the specified stage is in memory or persisted to storage based on the id
*
* Default value stream analytics stages are initially stored in memory, when they are first
* created the id for the stage is the name of the stage in lowercase. This string id
* is used to fetch stage data (events, median calculation)
*
* When either a custom stage is created or an edit is made to a default stage then the
* default stages get persisted to storage and will have a numeric id. The new numeric
* id should then be used to access stage data
*
*/
export const isPersistedStage = ({ custom, id }) => custom || isNumber(id);
/**
* Returns the the correct slug to use for a stage
* default stages use the snakecased title of the stage, while custom
* stages will have a numeric id
*
* @param {Object} obj
* @param {string} obj.title - title of the stage
* @param {number} obj.id - numerical object id available for custom stages
* @param {boolean} obj.custom - boolean flag indicating a custom stage
* @returns {(number|string)} Returns a numerical id for customs stages and string for default stages
*/
const stageUrlSlug = ({ id, title, custom = false }) => {
if (custom) return id;
return convertToSnakeCase(title);
};
export const transformRawStages = (stages = []) =>
stages.map(({ id, title, name = '', custom = false, ...rest }) => ({
...convertObjectPropsToCamelCase(rest, { deep: true }),
id,
title,
custom,
slug: isPersistedStage({ custom, id }) ? id : stageUrlSlug({ custom, id, title }),
// the name field is used to create a stage, but the get request returns title
name: name.length ? name : title,
}));
......@@ -113,7 +79,7 @@ export const prepareStageErrors = (stages, errors) =>
* each potentially having multiple data entries.
* [
* {
* slug: 'issue',
* id: 'issue',
* selected: true,
* data: [
* {
......@@ -159,7 +125,7 @@ export const flattenDurationChartData = (data) =>
* each potentially having multiple data entries.
* [
* {
* slug: 'issue',
* id: 'issue',
* selected: true,
* data: [
* {
......
......@@ -10,7 +10,6 @@ Array [
"id": 18,
"legend": "Cool legend",
"name": "Coolest beans stage",
"slug": 18,
"startEventIdentifier": "issue_first_mentioned_in_commit",
"title": "Coolest beans stage",
},
......
......@@ -414,8 +414,8 @@ describe('EE Value Stream Analytics component', () => {
});
describe('Path navigation', () => {
const selectedStage = { title: 'Plan', slug: 2 };
const overviewStage = { title: 'Overview', slug: OVERVIEW_STAGE_ID };
const selectedStage = { id: 2, title: 'Plan' };
const overviewStage = { id: OVERVIEW_STAGE_ID, title: 'Overview' };
let actionSpies = {};
beforeEach(async () => {
......
......@@ -241,12 +241,12 @@ export const rawDurationData = [
export const transformedDurationData = [
{
slug: 1,
id: 1,
selected: true,
data: rawDurationData,
},
{
slug: 2,
id: 2,
selected: true,
data: rawDurationData,
},
......
......@@ -217,7 +217,7 @@ describe('Value Stream Analytics actions / stages', () => {
describe('fetchStageMedianValues', () => {
let mockDispatch = jest.fn();
const fetchMedianResponse = activeStages.map(({ slug: id }) => ({ events: [], id }));
const fetchMedianResponse = activeStages.map(({ id }) => ({ events: [], id }));
beforeEach(() => {
state = { ...state, stages, currentGroup };
......@@ -257,7 +257,7 @@ describe('Value Stream Analytics actions / stages', () => {
describe(`Status ${httpStatusCodes.OK} and error message in response`, () => {
const dataError = 'Too much data';
const payload = activeStages.map(({ slug: id }) => ({ value: null, id, error: dataError }));
const payload = activeStages.map(({ id }) => ({ value: null, id, error: dataError }));
beforeEach(() => {
mock.onGet(endpoints.stageMedian).reply(httpStatusCodes.OK, { error: dataError });
......@@ -316,7 +316,7 @@ describe('Value Stream Analytics actions / stages', () => {
});
describe('fetchStageCountValues', () => {
const fetchCountResponse = activeStages.map(({ slug: id }) => ({ events: [], id }));
const fetchCountResponse = activeStages.map(({ id }) => ({ events: [], id }));
beforeEach(() => {
state = {
......
......@@ -9,7 +9,6 @@ import {
flattenDurationChartData,
getDurationChartData,
transformRawStages,
isPersistedStage,
getTasksByTypeData,
flattenTaskByTypeSeries,
orderByDate,
......@@ -160,13 +159,6 @@ describe('Value Stream Analytics utils', () => {
});
});
it('sets the slug to the value of the stage id', () => {
const transformed = transformRawStages([issueStage, rawCustomStage]);
transformed.forEach((t) => {
expect(t.slug).toEqual(t.id);
});
});
it('sets the name to the value of the stage title if its not set', () => {
const transformed = transformRawStages([issueStage, rawCustomStage]);
transformed.forEach((t) => {
......@@ -199,18 +191,6 @@ describe('Value Stream Analytics utils', () => {
});
});
describe('isPersistedStage', () => {
it.each`
custom | id | expected
${true} | ${'this-is-a-string'} | ${true}
${true} | ${42} | ${true}
${false} | ${42} | ${true}
${false} | ${'this-is-a-string'} | ${false}
`('with custom=$custom and id=$id', ({ custom, id, expected }) => {
expect(isPersistedStage({ custom, id })).toEqual(expected);
});
});
describe('flattenTaskByTypeSeries', () => {
const dummySeries = Object.fromEntries([
['2019-01-16', 40],
......
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