Commit 350e23e7 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '13076-fe-persist-custom-cycle-analytics' into 'master'

Customizable cycle analytics - Persist custom stages

See merge request gitlab-org/gitlab!18372
parents b70403cf 08593361
...@@ -48,6 +48,7 @@ export default { ...@@ -48,6 +48,7 @@ export default {
'isLoadingStage', 'isLoadingStage',
'isEmptyStage', 'isEmptyStage',
'isAddingCustomStage', 'isAddingCustomStage',
'isSavingCustomStage',
'selectedGroup', 'selectedGroup',
'selectedProjectIds', 'selectedProjectIds',
'selectedStageId', 'selectedStageId',
...@@ -87,6 +88,7 @@ export default { ...@@ -87,6 +88,7 @@ export default {
'fetchCustomStageFormData', 'fetchCustomStageFormData',
'fetchCycleAnalyticsData', 'fetchCycleAnalyticsData',
'fetchStageData', 'fetchStageData',
'fetchGroupStagesAndEvents',
'setCycleAnalyticsDataEndpoint', 'setCycleAnalyticsDataEndpoint',
'setStageDataEndpoint', 'setStageDataEndpoint',
'setSelectedGroup', 'setSelectedGroup',
...@@ -97,6 +99,7 @@ export default { ...@@ -97,6 +99,7 @@ export default {
'hideCustomStageForm', 'hideCustomStageForm',
'showCustomStageForm', 'showCustomStageForm',
'setDateRange', 'setDateRange',
'createCustomStage',
]), ]),
onGroupSelect(group) { onGroupSelect(group) {
this.setCycleAnalyticsDataEndpoint(group.full_path); this.setCycleAnalyticsDataEndpoint(group.full_path);
...@@ -122,6 +125,9 @@ export default { ...@@ -122,6 +125,9 @@ export default {
const startDate = getDateInPast(endDate, DEFAULT_DAYS_IN_PAST); const startDate = getDateInPast(endDate, DEFAULT_DAYS_IN_PAST);
this.setDateRange({ skipFetch: true, startDate, endDate }); this.setDateRange({ skipFetch: true, startDate, endDate });
}, },
onCreateCustomStage(data) {
this.createCustomStage(data);
},
}, },
groupsQueryParams: { groupsQueryParams: {
min_access_level: featureAccessLevel.EVERYONE, min_access_level: featureAccessLevel.EVERYONE,
...@@ -209,6 +215,7 @@ export default { ...@@ -209,6 +215,7 @@ export default {
:is-loading="isLoadingStage" :is-loading="isLoadingStage"
:is-empty-stage="isEmptyStage" :is-empty-stage="isEmptyStage"
:is-adding-custom-stage="isAddingCustomStage" :is-adding-custom-stage="isAddingCustomStage"
:is-saving-custom-stage="isSavingCustomStage"
:current-stage-events="currentStageEvents" :current-stage-events="currentStageEvents"
:custom-stage-form-events="customStageFormEvents" :custom-stage-form-events="customStageFormEvents"
:labels="labels" :labels="labels"
...@@ -217,6 +224,7 @@ export default { ...@@ -217,6 +224,7 @@ export default {
:can-edit-stages="hasCustomizableCycleAnalytics" :can-edit-stages="hasCustomizableCycleAnalytics"
@selectStage="onStageSelect" @selectStage="onStageSelect"
@showAddStageForm="onShowAddStageForm" @showAddStageForm="onShowAddStageForm"
@submit="onCreateCustomStage"
/> />
</div> </div>
</div> </div>
......
<script> <script>
import { isEqual } from 'underscore'; import { isEqual } from 'underscore';
import { GlButton, GlFormGroup, GlFormInput, GlFormSelect } from '@gitlab/ui'; import { GlButton, GlFormGroup, GlFormInput, GlFormSelect, GlLoadingIcon } from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import LabelsSelector from './labels_selector.vue'; import LabelsSelector from './labels_selector.vue';
import { import {
...@@ -26,6 +26,7 @@ export default { ...@@ -26,6 +26,7 @@ export default {
GlFormGroup, GlFormGroup,
GlFormInput, GlFormInput,
GlFormSelect, GlFormSelect,
GlLoadingIcon,
LabelsSelector, LabelsSelector,
}, },
props: { props: {
...@@ -44,6 +45,11 @@ export default { ...@@ -44,6 +45,11 @@ export default {
...initFields, ...initFields,
}), }),
}, },
isSavingCustomStage: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
return { return {
...@@ -116,7 +122,14 @@ export default { ...@@ -116,7 +122,14 @@ export default {
this.$emit('cancel'); this.$emit('cancel');
}, },
handleSave() { handleSave() {
this.$emit('submit', this.fields); const { startEvent, startEventLabel, stopEvent, stopEventLabel, name } = this.fields;
this.$emit('submit', {
name,
start_event_identifier: startEvent,
start_event_label_id: startEventLabel,
end_event_identifier: stopEvent,
end_event_label_id: stopEventLabel,
});
}, },
handleSelectLabel(key, labelId = null) { handleSelectLabel(key, labelId = null) {
this.fields[key] = labelId; this.fields[key] = labelId;
...@@ -128,7 +141,7 @@ export default { ...@@ -128,7 +141,7 @@ export default {
}; };
</script> </script>
<template> <template>
<form class="add-stage-form m-4"> <form class="custom-stage-form m-4 mt-0">
<div class="mb-1"> <div class="mb-1">
<h4>{{ s__('CustomCycleAnalytics|New stage') }}</h4> <h4>{{ s__('CustomCycleAnalytics|New stage') }}</h4>
</div> </div>
...@@ -137,7 +150,7 @@ export default { ...@@ -137,7 +150,7 @@ export default {
v-model="fields.name" v-model="fields.name"
class="form-control" class="form-control"
type="text" type="text"
name="add-stage-name" name="custom-stage-name"
:placeholder="s__('CustomCycleAnalytics|Enter a name for the stage')" :placeholder="s__('CustomCycleAnalytics|Enter a name for the stage')"
required required
/> />
...@@ -147,7 +160,7 @@ export default { ...@@ -147,7 +160,7 @@ export default {
<gl-form-group :label="s__('CustomCycleAnalytics|Start event')"> <gl-form-group :label="s__('CustomCycleAnalytics|Start event')">
<gl-form-select <gl-form-select
v-model="fields.startEvent" v-model="fields.startEvent"
name="add-stage-start-event" name="custom-stage-start-event"
:required="true" :required="true"
:options="startEventOptions" :options="startEventOptions"
/> />
...@@ -158,7 +171,7 @@ export default { ...@@ -158,7 +171,7 @@ export default {
<labels-selector <labels-selector
:labels="labels" :labels="labels"
:selected-label-id="fields.startEventLabel" :selected-label-id="fields.startEventLabel"
name="add-stage-start-event-label" name="custom-stage-start-event-label"
@selectLabel="labelId => handleSelectLabel('startEventLabel', labelId)" @selectLabel="labelId => handleSelectLabel('startEventLabel', labelId)"
@clearLabel="handleClearLabel('startEventLabel')" @clearLabel="handleClearLabel('startEventLabel')"
/> />
...@@ -177,7 +190,7 @@ export default { ...@@ -177,7 +190,7 @@ export default {
> >
<gl-form-select <gl-form-select
v-model="fields.stopEvent" v-model="fields.stopEvent"
name="add-stage-stop-event" name="custom-stage-stop-event"
:options="stopEventOptions" :options="stopEventOptions"
:required="true" :required="true"
:disabled="!hasStartEvent" :disabled="!hasStartEvent"
...@@ -189,7 +202,7 @@ export default { ...@@ -189,7 +202,7 @@ export default {
<labels-selector <labels-selector
:labels="labels" :labels="labels"
:selected-label-id="fields.stopEventLabel" :selected-label-id="fields.stopEventLabel"
name="add-stage-stop-event-label" name="custom-stage-stop-event-label"
@selectLabel="labelId => handleSelectLabel('stopEventLabel', labelId)" @selectLabel="labelId => handleSelectLabel('stopEventLabel', labelId)"
@clearLabel="handleClearLabel('stopEventLabel')" @clearLabel="handleClearLabel('stopEventLabel')"
/> />
...@@ -197,10 +210,10 @@ export default { ...@@ -197,10 +210,10 @@ export default {
</div> </div>
</div> </div>
<div class="add-stage-form-actions"> <div class="custom-stage-form-actions">
<button <button
:disabled="!isDirty" :disabled="!isDirty"
class="btn btn-cancel js-add-stage-cancel" class="btn btn-cancel js-custom-stage-form-cancel"
type="button" type="button"
@click="handleCancel" @click="handleCancel"
> >
...@@ -209,9 +222,10 @@ export default { ...@@ -209,9 +222,10 @@ export default {
<button <button
:disabled="!isComplete || !isDirty" :disabled="!isComplete || !isDirty"
type="button" type="button"
class="js-add-stage btn btn-success" class="js-custom-stage-form-submit btn btn-success"
@click="handleSave" @click="handleSave"
> >
<gl-loading-icon v-if="isSavingCustomStage" size="sm" inline />
{{ s__('CustomCycleAnalytics|Add stage') }} {{ s__('CustomCycleAnalytics|Add stage') }}
</button> </button>
</div> </div>
......
...@@ -44,6 +44,10 @@ export default { ...@@ -44,6 +44,10 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
isSavingCustomStage: {
type: Boolean,
required: true,
},
currentStageEvents: { currentStageEvents: {
type: Array, type: Array,
required: true, required: true,
...@@ -95,23 +99,17 @@ export default { ...@@ -95,23 +99,17 @@ export default {
title: this.stageName, title: this.stageName,
description: __('The collection of events added to the data gathered for that stage.'), description: __('The collection of events added to the data gathered for that stage.'),
classes: 'event-header pl-3', classes: 'event-header pl-3',
displayHeader: !this.isAddingCustomStage,
}, },
{ {
title: __('Total Time'), title: __('Total Time'),
description: __('The time taken by each data entry gathered by that stage.'), description: __('The time taken by each data entry gathered by that stage.'),
classes: 'total-time-header pr-5 text-right', classes: 'total-time-header pr-5 text-right',
displayHeader: !this.isAddingCustomStage,
}, },
]; ];
}, },
}, },
methods: {
selectStage(stage) {
this.$emit('selectStage', stage);
},
showAddStageForm() {
this.$emit('showAddStageForm');
},
},
}; };
</script> </script>
<template> <template>
...@@ -121,7 +119,8 @@ export default { ...@@ -121,7 +119,8 @@ export default {
<nav class="col-headers"> <nav class="col-headers">
<ul> <ul>
<stage-table-header <stage-table-header
v-for="({ title, description, classes }, i) in stageHeaders" v-for="({ title, description, classes, displayHeader = true }, i) in stageHeaders"
v-show="displayHeader"
:key="`stage-header-${i}`" :key="`stage-header-${i}`"
:header-classes="classes" :header-classes="classes"
:title="title" :title="title"
...@@ -140,12 +139,12 @@ export default { ...@@ -140,12 +139,12 @@ export default {
:value="stage.value" :value="stage.value"
:is-active="!isAddingCustomStage && stage.id === currentStage.id" :is-active="!isAddingCustomStage && stage.id === currentStage.id"
:is-default-stage="!stage.custom" :is-default-stage="!stage.custom"
@select="selectStage(stage)" @select="$emit('selectStage', stage)"
/> />
<add-stage-button <add-stage-button
v-if="canEditStages" v-if="canEditStages"
:active="isAddingCustomStage" :active="isAddingCustomStage"
@showform="showAddStageForm" @showform="$emit('showAddStageForm')"
/> />
</ul> </ul>
</nav> </nav>
...@@ -155,6 +154,8 @@ export default { ...@@ -155,6 +154,8 @@ export default {
v-else-if="isAddingCustomStage" v-else-if="isAddingCustomStage"
:events="customStageFormEvents" :events="customStageFormEvents"
:labels="labels" :labels="labels"
:is-saving-custom-stage="isSavingCustomStage"
@submit="$emit('submit', $event)"
/> />
<template v-else> <template v-else>
<stage-event-list <stage-event-list
......
...@@ -157,3 +157,38 @@ export const fetchGroupStagesAndEvents = ({ state, dispatch, getters }) => { ...@@ -157,3 +157,38 @@ export const fetchGroupStagesAndEvents = ({ state, dispatch, getters }) => {
.then(({ data }) => dispatch('receiveGroupStagesAndEventsSuccess', data)) .then(({ data }) => dispatch('receiveGroupStagesAndEventsSuccess', data))
.catch(error => dispatch('receiveGroupStagesAndEventsError', error)); .catch(error => dispatch('receiveGroupStagesAndEventsError', error));
}; };
export const requestCreateCustomStage = ({ commit }) => commit(types.REQUEST_CREATE_CUSTOM_STAGE);
export const receiveCreateCustomStageSuccess = ({ commit, dispatch }, { data: { title } }) => {
commit(types.RECEIVE_CREATE_CUSTOM_STAGE_RESPONSE);
createFlash(__(`Your custom stage '${title}' was created`), 'notice');
return dispatch('fetchGroupStagesAndEvents').then(() => dispatch('fetchSummaryData'));
};
export const receiveCreateCustomStageError = ({ commit }, { error, data }) => {
commit(types.RECEIVE_CREATE_CUSTOM_STAGE_RESPONSE);
const { name } = data;
const { status } = error;
const message =
status !== httpStatus.UNPROCESSABLE_ENTITY
? __(`'${name}' stage already exists'`)
: __('There was a problem saving your custom stage, please try again');
createFlash(message);
};
export const createCustomStage = ({ dispatch, state }, data) => {
const {
selectedGroup: { fullPath },
} = state;
const endpoint = `/-/analytics/cycle_analytics/stages?group_id=${fullPath}`;
dispatch('requestCreateCustomStage');
axios
.post(endpoint, data)
.then(response => dispatch('receiveCreateCustomStageSuccess', response))
.catch(error => dispatch('receiveCreateCustomStageError', { error, data }));
};
...@@ -29,3 +29,6 @@ export const RECEIVE_SUMMARY_DATA_ERROR = 'RECEIVE_SUMMARY_DATA_ERROR'; ...@@ -29,3 +29,6 @@ export const RECEIVE_SUMMARY_DATA_ERROR = 'RECEIVE_SUMMARY_DATA_ERROR';
export const REQUEST_GROUP_STAGES_AND_EVENTS = 'REQUEST_GROUP_STAGES_AND_EVENTS'; export const REQUEST_GROUP_STAGES_AND_EVENTS = 'REQUEST_GROUP_STAGES_AND_EVENTS';
export const RECEIVE_GROUP_STAGES_AND_EVENTS_SUCCESS = 'RECEIVE_GROUP_STAGES_AND_EVENTS_SUCCESS'; export const RECEIVE_GROUP_STAGES_AND_EVENTS_SUCCESS = 'RECEIVE_GROUP_STAGES_AND_EVENTS_SUCCESS';
export const RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR = 'RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR'; export const RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR = 'RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR';
export const REQUEST_CREATE_CUSTOM_STAGE = 'REQUEST_CREATE_CUSTOM_STAGE';
export const RECEIVE_CREATE_CUSTOM_STAGE_RESPONSE = 'RECEIVE_CREATE_CUSTOM_STAGE_RESPONSE';
...@@ -120,4 +120,10 @@ export default { ...@@ -120,4 +120,10 @@ export default {
state.selectedStageId = id; state.selectedStageId = id;
} }
}, },
[types.REQUEST_CREATE_CUSTOM_STAGE](state) {
state.isSavingCustomStage = true;
},
[types.RECEIVE_CREATE_CUSTOM_STAGE_RESPONSE](state) {
state.isSavingCustomStage = false;
},
}; };
...@@ -16,6 +16,7 @@ export default () => ({ ...@@ -16,6 +16,7 @@ export default () => ({
errorCode: null, errorCode: null,
isAddingCustomStage: false, isAddingCustomStage: false,
isSavingCustomStage: false,
selectedGroup: null, selectedGroup: null,
selectedProjectIds: [], selectedProjectIds: [],
......
...@@ -61,7 +61,7 @@ describe 'Group Cycle Analytics', :js do ...@@ -61,7 +61,7 @@ describe 'Group Cycle Analytics', :js do
dropdown.click dropdown.click
dropdown.find('a').click dropdown.find('a').click
wait_for_requests wait_for_stages_to_load
end end
def select_project def select_project
...@@ -218,11 +218,7 @@ describe 'Group Cycle Analytics', :js do ...@@ -218,11 +218,7 @@ describe 'Group Cycle Analytics', :js do
context 'enabled' do context 'enabled' do
before do before do
dropdown = page.find('.dropdown-groups') select_group
dropdown.click
dropdown.find('a').click
wait_for_stages_to_load
end end
context 'Add a stage button' do context 'Add a stage button' do
...@@ -247,6 +243,77 @@ describe 'Group Cycle Analytics', :js do ...@@ -247,6 +243,77 @@ describe 'Group Cycle Analytics', :js do
expect(page).to have_text('New stage') expect(page).to have_text('New stage')
end end
end end
context 'Custom stage form' do
let(:show_form_button_class) { '.js-add-stage-button' }
def select_dropdown_option(name, elem = "option", index = 1)
page.find("select[name='#{name}']").all(elem)[index].select_option
end
before do
select_group
page.find(show_form_button_class).click
wait_for_requests
end
context 'with empty fields' do
it 'submit button is disabled by default' do
expect(page).to have_button('Add stage', disabled: true)
end
end
context 'with all required fields set' do
custom_stage_name = "cool beans"
before do
fill_in 'custom-stage-name', with: custom_stage_name
select_dropdown_option 'custom-stage-start-event'
select_dropdown_option 'custom-stage-stop-event'
end
it 'submit button is enabled' do
expect(page).to have_button('Add stage', disabled: false)
end
it 'submit button is disabled if the start event changes' do
select_dropdown_option 'custom-stage-start-event', 'option', 2
expect(page).to have_button('Add stage', disabled: true)
end
it 'an error message is displayed if the start event is changed' do
select_dropdown_option 'custom-stage-start-event', 'option', 2
expect(page).to have_text 'Start event changed, please select a valid stop event'
end
context 'submit button is clicked' do
it 'the custom stage is saved' do
click_button 'Add stage'
expect(page).to have_selector('.stage-nav-item', text: custom_stage_name)
end
it 'a confirmation message is displayed' do
name = 'cool beans number 2'
fill_in 'custom-stage-name', with: name
click_button 'Add stage'
expect(page.find('.flash-notice')).to have_text("Your custom stage '#{name}' was created")
end
it 'with a default name' do
name = 'issue'
fill_in 'custom-stage-name', with: name
click_button 'Add stage'
expect(page.find('.flash-alert')).to have_text("'#{name}' stage already exists")
end
end
end
end
end end
context 'not enabled' do context 'not enabled' do
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CustomStageForm does not have a loading icon 1`] = `
"<button type=\\"button\\" class=\\"js-custom-stage-form-submit btn btn-success\\"><!---->
Add stage
</button>"
`;
exports[`CustomStageForm isSavingCustomStage=true displays a loading icon 1`] = `
"<button disabled=\\"disabled\\" type=\\"button\\" class=\\"js-custom-stage-form-submit btn btn-success\\"><span class=\\"gl-spinner-container\\"><span aria-label=\\"Loading\\" aria-hidden=\\"true\\" class=\\"gl-spinner gl-spinner-orange gl-spinner-sm\\"></span></span>
Add stage
</button>"
`;
...@@ -33,13 +33,13 @@ describe('CustomStageForm', () => { ...@@ -33,13 +33,13 @@ describe('CustomStageForm', () => {
let wrapper = null; let wrapper = null;
const sel = { const sel = {
name: '[name="add-stage-name"]', name: '[name="custom-stage-name"]',
startEvent: '[name="add-stage-start-event"]', startEvent: '[name="custom-stage-start-event"]',
startEventLabel: '[name="add-stage-start-event-label"]', startEventLabel: '[name="custom-stage-start-event-label"]',
stopEvent: '[name="add-stage-stop-event"]', stopEvent: '[name="custom-stage-stop-event"]',
stopEventLabel: '[name="add-stage-stop-event-label"]', stopEventLabel: '[name="custom-stage-stop-event-label"]',
submit: '.js-add-stage', submit: '.js-custom-stage-form-submit',
cancel: '.js-add-stage-cancel', cancel: '.js-custom-stage-form-cancel',
invalidFeedback: '.invalid-feedback', invalidFeedback: '.invalid-feedback',
}; };
...@@ -405,10 +405,10 @@ describe('CustomStageForm', () => { ...@@ -405,10 +405,10 @@ describe('CustomStageForm', () => {
const res = [ const res = [
{ {
name: 'Cool stage', name: 'Cool stage',
startEvent: startEv.identifier, start_event_identifier: startEv.identifier,
startEventLabel: null, start_event_label_id: null,
stopEvent: selectedStopEvent.attributes('value'), end_event_identifier: selectedStopEvent.attributes('value'),
stopEventLabel: null, end_event_label_id: null,
}, },
]; ];
...@@ -597,11 +597,38 @@ describe('CustomStageForm', () => { ...@@ -597,11 +597,38 @@ describe('CustomStageForm', () => {
Vue.nextTick(() => { Vue.nextTick(() => {
const submitted = wrapper.emitted().submit[0]; const submitted = wrapper.emitted().submit[0];
expect(submitted).not.toEqual([initData]); expect(submitted).not.toEqual([initData]);
expect(submitted).toEqual([{ ...initData, name: 'Cool updated form' }]); expect(submitted).toEqual([
{
start_event_identifier: labelStartEvent.identifier,
start_event_label_id: groupLabels[0].id,
end_event_identifier: labelStopEvent.identifier,
end_event_label_id: groupLabels[1].id,
name: 'Cool updated form',
},
]);
done(); done();
}); });
}); });
}); });
}); });
}); });
it('does not have a loading icon', () => {
expect(wrapper.find(sel.submit).html()).toMatchSnapshot();
});
describe('isSavingCustomStage=true', () => {
beforeEach(() => {
wrapper = createComponent(
{
isSavingCustomStage: true,
},
false,
);
});
it('displays a loading icon', () => {
expect(wrapper.find(sel.submit).html()).toMatchSnapshot();
});
});
}); });
import Vue from 'vue'; import Vue from 'vue';
import { shallowMount, mount } from '@vue/test-utils'; import { shallowMount, mount } from '@vue/test-utils';
import StageTable from 'ee/analytics/cycle_analytics/components/stage_table.vue'; import StageTable from 'ee/analytics/cycle_analytics/components/stage_table.vue';
import { issueEvents, issueStage, allowedStages, groupLabels } from '../mock_data'; import {
issueEvents,
issueStage,
allowedStages,
groupLabels,
customStageEvents,
} from '../mock_data';
let wrapper = null; let wrapper = null;
const $sel = { const $sel = {
...@@ -30,10 +36,11 @@ function createComponent(props = {}, shallow = false) { ...@@ -30,10 +36,11 @@ function createComponent(props = {}, shallow = false) {
isLoading: false, isLoading: false,
isEmptyStage: false, isEmptyStage: false,
isAddingCustomStage: false, isAddingCustomStage: false,
isSavingCustomStage: false,
noDataSvgPath, noDataSvgPath,
noAccessSvgPath, noAccessSvgPath,
canEditStages: false, canEditStages: false,
customStageFormEvents: [], customStageFormEvents: customStageEvents,
...props, ...props,
}, },
stubs: { stubs: {
......
...@@ -45,6 +45,8 @@ describe('Cycle analytics mutations', () => { ...@@ -45,6 +45,8 @@ describe('Cycle analytics mutations', () => {
${types.REQUEST_GROUP_STAGES_AND_EVENTS} | ${'stages'} | ${[]} ${types.REQUEST_GROUP_STAGES_AND_EVENTS} | ${'stages'} | ${[]}
${types.RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR} | ${'customStageFormEvents'} | ${[]} ${types.RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR} | ${'customStageFormEvents'} | ${[]}
${types.REQUEST_GROUP_STAGES_AND_EVENTS} | ${'customStageFormEvents'} | ${[]} ${types.REQUEST_GROUP_STAGES_AND_EVENTS} | ${'customStageFormEvents'} | ${[]}
${types.REQUEST_CREATE_CUSTOM_STAGE} | ${'isSavingCustomStage'} | ${true}
${types.RECEIVE_CREATE_CUSTOM_STAGE_RESPONSE} | ${'isSavingCustomStage'} | ${false}
`('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => { `('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => {
mutations[mutation](state); mutations[mutation](state);
......
...@@ -17260,6 +17260,9 @@ msgstr "" ...@@ -17260,6 +17260,9 @@ msgstr ""
msgid "There was a problem communicating with your device." msgid "There was a problem communicating with your device."
msgstr "" msgstr ""
msgid "There was a problem saving your custom stage, please try again"
msgstr ""
msgid "There was a problem sending the confirmation email" msgid "There was a problem sending the confirmation email"
msgstr "" msgstr ""
......
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