From 0dd713ce9f6c284070f7970e7bf630cf89f8090d Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Thu, 21 Mar 2019 19:17:29 +0530 Subject: [PATCH] Add Vuex store for Roadmap Adds Vuex store with mutations, getters and actions and initial support for initializing state object on app initialization. --- ee/app/assets/javascripts/roadmap/index.js | 19 +++++ .../javascripts/roadmap/store/actions.js | 6 ++ .../javascripts/roadmap/store/getters.js | 43 ++++++++++ .../assets/javascripts/roadmap/store/index.js | 17 ++++ .../roadmap/store/mutation_types.js | 5 ++ .../javascripts/roadmap/store/mutations.js | 7 ++ .../assets/javascripts/roadmap/store/state.js | 8 ++ .../javascripts/roadmap/store/actions_spec.js | 23 ++++++ .../javascripts/roadmap/store/getters_spec.js | 82 +++++++++++++++++++ .../roadmap/store/mutations_spec.js | 18 ++++ 10 files changed, 228 insertions(+) create mode 100644 ee/app/assets/javascripts/roadmap/store/actions.js create mode 100644 ee/app/assets/javascripts/roadmap/store/getters.js create mode 100644 ee/app/assets/javascripts/roadmap/store/index.js create mode 100644 ee/app/assets/javascripts/roadmap/store/mutation_types.js create mode 100644 ee/app/assets/javascripts/roadmap/store/mutations.js create mode 100644 ee/app/assets/javascripts/roadmap/store/state.js create mode 100644 ee/spec/javascripts/roadmap/store/actions_spec.js create mode 100644 ee/spec/javascripts/roadmap/store/getters_spec.js create mode 100644 ee/spec/javascripts/roadmap/store/mutations_spec.js diff --git a/ee/app/assets/javascripts/roadmap/index.js b/ee/app/assets/javascripts/roadmap/index.js index 9c8234716188cd..ff6f4d5ed8bbe3 100644 --- a/ee/app/assets/javascripts/roadmap/index.js +++ b/ee/app/assets/javascripts/roadmap/index.js @@ -1,4 +1,5 @@ import Vue from 'vue'; +import { mapActions } from 'vuex'; import Translate from '~/vue_shared/translate'; @@ -9,6 +10,7 @@ import { PRESET_TYPES, EPIC_DETAILS_CELL_WIDTH } from './constants'; import { getTimeframeForPreset, getEpicsPathForPreset } from './utils/roadmap_utils'; +import createStore from './store'; import RoadmapStore from './store/roadmap_store'; import RoadmapService from './service/roadmap_service'; @@ -36,6 +38,7 @@ export default () => { return new Vue({ el, + store: createStore(), components: { roadmapApp, }, @@ -82,8 +85,24 @@ export default () => { epicsState: dataset.epicsState, newEpicEndpoint: dataset.newEpicEndpoint, emptyStateIllustrationPath: dataset.emptyStateIllustration, + + // Part of Vuex Store + currentGroupId: parseInt(dataset.groupId, 0), + sortedBy: dataset.sortedBy, + timeframe, }; }, + created() { + this.setInitialData({ + currentGroupId: this.currentGroupId, + sortedBy: this.sortedBy, + presetType: this.presetType, + timeframe: this.timeframe, + }); + }, + methods: { + ...mapActions(['setInitialData']), + }, render(createElement) { return createElement('roadmap-app', { props: { diff --git a/ee/app/assets/javascripts/roadmap/store/actions.js b/ee/app/assets/javascripts/roadmap/store/actions.js new file mode 100644 index 00000000000000..0ba874fb08a325 --- /dev/null +++ b/ee/app/assets/javascripts/roadmap/store/actions.js @@ -0,0 +1,6 @@ +import * as types from './mutation_types'; + +export const setInitialData = ({ commit }, data) => commit(types.SET_INITIAL_DATA, data); + +// prevent babel-plugin-rewire from generating an invalid default during karma tests +export default () => {}; diff --git a/ee/app/assets/javascripts/roadmap/store/getters.js b/ee/app/assets/javascripts/roadmap/store/getters.js new file mode 100644 index 00000000000000..6c8499eb231344 --- /dev/null +++ b/ee/app/assets/javascripts/roadmap/store/getters.js @@ -0,0 +1,43 @@ +import { newDate } from '~/lib/utils/datetime_utility'; + +import { PRESET_TYPES, DAYS_IN_WEEK } from '../constants'; + +/** + * Returns number representing index of last item of timeframe array from state + * + * @param {Object} state + */ +export const lastTimeframeIndex = state => state.timeframe.length - 1; + +/** + * Returns first item of the timeframe array from state + * + * @param {Object} state + */ +export const timeframeStartDate = state => { + if (state.presetType === PRESET_TYPES.QUARTERS) { + return state.timeframe[0].range[0]; + } + return state.timeframe[0]; +}; + +/** + * Returns last item of the timeframe array from state depending on preset + * type set. + * + * @param {Object} state + * @param {Object} getters + */ +export const timeframeEndDate = (state, getters) => { + if (state.presetType === PRESET_TYPES.QUARTERS) { + return state.timeframe[getters.lastTimeframeIndex].range[2]; + } else if (state.presetType === PRESET_TYPES.MONTHS) { + return state.timeframe[getters.lastTimeframeIndex]; + } + const endDate = newDate(state.timeframe[getters.lastTimeframeIndex]); + endDate.setDate(endDate.getDate() + DAYS_IN_WEEK); + return endDate; +}; + +// prevent babel-plugin-rewire from generating an invalid default during karma tests +export default () => {}; diff --git a/ee/app/assets/javascripts/roadmap/store/index.js b/ee/app/assets/javascripts/roadmap/store/index.js new file mode 100644 index 00000000000000..d6fa19cabda51a --- /dev/null +++ b/ee/app/assets/javascripts/roadmap/store/index.js @@ -0,0 +1,17 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; + +import * as actions from './actions'; +import * as getters from './getters'; +import mutations from './mutations'; +import state from './state'; + +Vue.use(Vuex); + +export default () => + new Vuex.Store({ + actions, + getters, + mutations, + state: state(), + }); diff --git a/ee/app/assets/javascripts/roadmap/store/mutation_types.js b/ee/app/assets/javascripts/roadmap/store/mutation_types.js new file mode 100644 index 00000000000000..9fd83aebb84bec --- /dev/null +++ b/ee/app/assets/javascripts/roadmap/store/mutation_types.js @@ -0,0 +1,5 @@ +export const SET_INITIAL_DATA = 'SET_INITIAL_DATA'; + +export const REQUEST_EPICS = 'REQUEST_EPICS'; +export const REQUEST_EPICS_SUCCESS = 'REQUEST_EPICS_SUCCESS'; +export const REQUEST_EPICS_FAILURE = 'REQUEST_EPICS_FAILURE'; diff --git a/ee/app/assets/javascripts/roadmap/store/mutations.js b/ee/app/assets/javascripts/roadmap/store/mutations.js new file mode 100644 index 00000000000000..79e57d18e97fad --- /dev/null +++ b/ee/app/assets/javascripts/roadmap/store/mutations.js @@ -0,0 +1,7 @@ +import * as types from './mutation_types'; + +export default { + [types.SET_INITIAL_DATA](state, data) { + Object.assign(state, { ...data }); + }, +}; diff --git a/ee/app/assets/javascripts/roadmap/store/state.js b/ee/app/assets/javascripts/roadmap/store/state.js new file mode 100644 index 00000000000000..62aaa7576df8ab --- /dev/null +++ b/ee/app/assets/javascripts/roadmap/store/state.js @@ -0,0 +1,8 @@ +export default () => ({ + epics: [], + epicIds: [], + currentGroupId: -1, + timeframe: [], + presetType: '', + sortedBy: '', +}); diff --git a/ee/spec/javascripts/roadmap/store/actions_spec.js b/ee/spec/javascripts/roadmap/store/actions_spec.js new file mode 100644 index 00000000000000..3a290e4191ddff --- /dev/null +++ b/ee/spec/javascripts/roadmap/store/actions_spec.js @@ -0,0 +1,23 @@ +import * as actions from 'ee/roadmap/store/actions'; + +import testAction from 'spec/helpers/vuex_action_helper'; + +describe('Roadmap Vuex Actions', () => { + describe('setInitialData', () => { + it('Should set initial roadmap props', done => { + const mockRoadmap = { + foo: 'bar', + bar: 'baz', + }; + + testAction( + actions.setInitialData, + mockRoadmap, + {}, + [{ type: 'SET_INITIAL_DATA', payload: mockRoadmap }], + [], + done, + ); + }); + }); +}); diff --git a/ee/spec/javascripts/roadmap/store/getters_spec.js b/ee/spec/javascripts/roadmap/store/getters_spec.js new file mode 100644 index 00000000000000..0fa1947eefa048 --- /dev/null +++ b/ee/spec/javascripts/roadmap/store/getters_spec.js @@ -0,0 +1,82 @@ +import * as getters from 'ee/roadmap/store/getters'; + +import { PRESET_TYPES } from 'ee/roadmap/constants'; + +describe('Roadmap Store Getters', () => { + describe('lastTimeframeIndex', () => { + it('Should return last index of the timeframe array from state', () => { + const roadmapState = { + timeframe: [1, 2, 3, 4], + }; + + expect(getters.lastTimeframeIndex(roadmapState)).toBe(3); + }); + }); + + describe('timeframeStartDate', () => { + it('Should return first item of the timeframe range array from the state when preset type is Quarters', () => { + const roadmapState = { + timeframe: [{ range: ['foo', 'bar', 'baz'] }, { range: ['abc', 'cde', 'efg'] }], + presetType: PRESET_TYPES.QUARTERS, + }; + + expect(getters.timeframeStartDate(roadmapState)).toBe('foo'); + }); + + it('Should return first item of the timeframe array from the state when preset type is Months or Weeks', () => { + const roadmapState = { + timeframe: ['foo', 'bar', 'baz'], + presetType: PRESET_TYPES.MONTHS, + }; + + expect(getters.timeframeStartDate(roadmapState)).toBe('foo'); + + roadmapState.presetType = PRESET_TYPES.WEEKS; + + expect(getters.timeframeStartDate(roadmapState)).toBe('foo'); + }); + }); + + describe('timeframeEndDate', () => { + it('Should return last item of the timeframe range array from the state when preset type is Quarters', () => { + const roadmapState = { + timeframe: [{ range: ['foo', 'bar', 'baz'] }, { range: ['abc', 'cde', 'efg'] }], + presetType: PRESET_TYPES.QUARTERS, + }; + + expect( + getters.timeframeEndDate(roadmapState, { + lastTimeframeIndex: roadmapState.timeframe.length - 1, + }), + ).toBe('efg'); + }); + + it('Should return last item of the timeframe array from the state when preset type is Months', () => { + const roadmapState = { + timeframe: ['foo', 'bar', 'baz'], + presetType: PRESET_TYPES.MONTHS, + }; + + expect( + getters.timeframeEndDate(roadmapState, { + lastTimeframeIndex: roadmapState.timeframe.length - 1, + }), + ).toBe('baz'); + }); + + it('Should return last item of the timeframe array from the state when preset type is Weeks', () => { + const roadmapState = { + timeframe: [new Date(2018, 11, 23), new Date(2018, 11, 30), new Date(2019, 0, 6)], + presetType: PRESET_TYPES.WEEKS, + }; + + expect( + getters + .timeframeEndDate(roadmapState, { + lastTimeframeIndex: roadmapState.timeframe.length - 1, + }) + .getTime(), + ).toBe(new Date(2019, 0, 13).getTime()); + }); + }); +}); diff --git a/ee/spec/javascripts/roadmap/store/mutations_spec.js b/ee/spec/javascripts/roadmap/store/mutations_spec.js new file mode 100644 index 00000000000000..90888e69b61625 --- /dev/null +++ b/ee/spec/javascripts/roadmap/store/mutations_spec.js @@ -0,0 +1,18 @@ +import mutations from 'ee/roadmap/store/mutations'; +import * as types from 'ee/roadmap/store/mutation_types'; + +describe('Roadmap Store Mutations', () => { + describe('SET_INITIAL_DATA', () => { + it('Should set initial Roadmap data to state', () => { + const state = {}; + const mockData = { + foo: 'bar', + bar: 'baz', + }; + + mutations[types.SET_INITIAL_DATA](state, mockData); + + expect(state).toEqual(mockData); + }); + }); +}); -- GitLab