Commit ebcb3b6f authored by Fatih Acet's avatar Fatih Acet

Merge branch '10077-add-dependency-scanning-to-dl-vuex-refactor-ee' into 'master'

Refactor Dependency List Vuex store

See merge request gitlab-org/gitlab-ee!14293
parents 25154035 8560f234
...@@ -6,6 +6,7 @@ import DependenciesActions from './dependencies_actions.vue'; ...@@ -6,6 +6,7 @@ import DependenciesActions from './dependencies_actions.vue';
import DependenciesTable from './dependencies_table.vue'; import DependenciesTable from './dependencies_table.vue';
import DependencyListIncompleteAlert from './dependency_list_incomplete_alert.vue'; import DependencyListIncompleteAlert from './dependency_list_incomplete_alert.vue';
import DependencyListJobFailedAlert from './dependency_list_job_failed_alert.vue'; import DependencyListJobFailedAlert from './dependency_list_job_failed_alert.vue';
import { DEPENDENCY_LIST_TYPES } from '../store/constants';
export default { export default {
name: 'DependenciesApp', name: 'DependenciesApp',
...@@ -45,8 +46,9 @@ export default { ...@@ -45,8 +46,9 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters(['isJobNotSetUp', 'isJobFailed', 'isIncomplete']), ...mapState(['currentList']),
...mapState([ ...mapGetters(DEPENDENCY_LIST_TYPES.all, ['isJobNotSetUp', 'isJobFailed', 'isIncomplete']),
...mapState(DEPENDENCY_LIST_TYPES.all, [
'initialized', 'initialized',
'isLoading', 'isLoading',
'errorLoading', 'errorLoading',
...@@ -63,7 +65,7 @@ export default { ...@@ -63,7 +65,7 @@ export default {
this.fetchDependencies(); this.fetchDependencies();
}, },
methods: { methods: {
...mapActions(['setDependenciesEndpoint', 'fetchDependencies']), ...mapActions(DEPENDENCY_LIST_TYPES.all, ['setDependenciesEndpoint', 'fetchDependencies']),
fetchPage(page) { fetchPage(page) {
this.fetchDependencies({ page }); this.fetchDependencies({ page });
}, },
...@@ -109,7 +111,7 @@ export default { ...@@ -109,7 +111,7 @@ export default {
<gl-badge v-if="pageInfo.total" pill>{{ pageInfo.total }}</gl-badge> <gl-badge v-if="pageInfo.total" pill>{{ pageInfo.total }}</gl-badge>
</h4> </h4>
<dependencies-actions /> <dependencies-actions :namespace="currentList" />
</div> </div>
<dependencies-table :dependencies="dependencies" :is-loading="isLoading" /> <dependencies-table :dependencies="dependencies" :is-loading="isLoading" />
......
<script> <script>
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import { GlButton, GlDropdown, GlDropdownItem, GlTooltipDirective } from '@gitlab/ui'; import { GlButton, GlDropdown, GlDropdownItem, GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { SORT_ORDER } from '../store/constants'; import { DEPENDENCY_LIST_TYPES } from '../store/constants';
import { SORT_ORDER } from '../store/modules/list/constants';
export default { export default {
name: 'DependenciesActions', name: 'DependenciesActions',
...@@ -15,9 +16,28 @@ export default { ...@@ -15,9 +16,28 @@ export default {
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },
props: {
namespace: {
type: String,
required: true,
validator: value => Object.values(DEPENDENCY_LIST_TYPES).includes(value),
},
},
computed: { computed: {
...mapState(['sortField', 'sortFields', 'sortOrder']), ...mapState({
...mapGetters(['downloadEndpoint']), sortField(state) {
return state[this.namespace].sortField;
},
sortFields(state) {
return state[this.namespace].sortFields;
},
sortOrder(state) {
return state[this.namespace].sortOrder;
},
downloadEndpoint(state, getters) {
return getters[`${this.namespace}/downloadEndpoint`];
},
}),
sortFieldName() { sortFieldName() {
return this.sortFields[this.sortField]; return this.sortFields[this.sortField];
}, },
...@@ -26,7 +46,14 @@ export default { ...@@ -26,7 +46,14 @@ export default {
}, },
}, },
methods: { methods: {
...mapActions(['setSortField', 'toggleSortOrder']), ...mapActions({
setSortField(dispatch, field) {
dispatch(`${this.namespace}/setSortField`, field);
},
toggleSortOrder(dispatch) {
dispatch(`${this.namespace}/toggleSortOrder`);
},
}),
isCurrentSortField(id) { isCurrentSortField(id) {
return id === this.sortField; return id === this.sortField;
}, },
......
import { __, s__ } from '~/locale'; // eslint-disable-next-line import/prefer-default-export
export const DEPENDENCY_LIST_TYPES = {
export const SORT_FIELDS = { all: 'allDependencies',
name: s__('Dependencies|Component name'),
packager: s__('Dependencies|Packager'),
}; };
export const SORT_ORDER = {
ascending: 'asc',
descending: 'desc',
};
export const REPORT_STATUS = {
ok: 'ok',
jobNotSetUp: 'job_not_set_up',
jobFailed: 'job_failed',
noDependencies: 'no_dependencies',
incomplete: 'no_dependency_files',
};
export const FETCH_ERROR_MESSAGE = __(
'Error fetching the dependency list. Please check your network connection and try again.',
);
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import * as actions from './actions'; import listModule from './modules/list';
import * as getters from './getters';
import mutations from './mutations';
import state from './state'; import state from './state';
Vue.use(Vuex); Vue.use(Vuex);
export default () => export default () => {
new Vuex.Store({ const allDependencies = listModule();
actions,
getters, return new Vuex.Store({
mutations, modules: {
allDependencies,
},
state, state,
}); });
};
import { __, s__ } from '~/locale';
export const SORT_FIELDS = {
name: s__('Dependencies|Component name'),
packager: s__('Dependencies|Packager'),
};
export const SORT_ORDER = {
ascending: 'asc',
descending: 'desc',
};
export const REPORT_STATUS = {
ok: 'ok',
jobNotSetUp: 'job_not_set_up',
jobFailed: 'job_failed',
noDependencies: 'no_dependencies',
incomplete: 'no_dependency_files',
};
export const FETCH_ERROR_MESSAGE = __(
'Error fetching the dependency list. Please check your network connection and try again.',
);
import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations';
import state from './state';
export default () => ({
namespaced: true,
actions,
getters,
mutations,
state,
});
import { REPORT_STATUS, SORT_FIELDS, SORT_ORDER } from './constants';
export default () => ({
endpoint: '',
initialized: false,
isLoading: false,
errorLoading: false,
dependencies: [],
pageInfo: {},
reportInfo: {
status: REPORT_STATUS.ok,
jobPath: '',
},
sortField: 'name',
sortFields: SORT_FIELDS,
sortOrder: SORT_ORDER.ascending,
});
import { REPORT_STATUS, SORT_FIELDS, SORT_ORDER } from './constants'; import { DEPENDENCY_LIST_TYPES } from './constants';
export default () => ({ export default () => ({
endpoint: '', currentList: DEPENDENCY_LIST_TYPES.all,
initialized: false,
isLoading: false,
errorLoading: false,
dependencies: [],
pageInfo: {},
reportInfo: {
status: REPORT_STATUS.ok,
jobPath: '',
},
sortField: 'name',
sortFields: SORT_FIELDS,
sortOrder: SORT_ORDER.ascending,
}); });
...@@ -22,7 +22,9 @@ exports[`DependenciesApp component on creation given a dependency list which is ...@@ -22,7 +22,9 @@ exports[`DependenciesApp component on creation given a dependency list which is
</glbadge-stub> </glbadge-stub>
</h4> </h4>
<dependenciesactions-stub /> <dependenciesactions-stub
namespace="allDependencies"
/>
</div> </div>
<dependenciestable-stub <dependenciestable-stub
...@@ -55,7 +57,9 @@ exports[`DependenciesApp component on creation given a fetch error matches the s ...@@ -55,7 +57,9 @@ exports[`DependenciesApp component on creation given a fetch error matches the s
<!----> <!---->
</h4> </h4>
<dependenciesactions-stub /> <dependenciesactions-stub
namespace="allDependencies"
/>
</div> </div>
<dependenciestable-stub <dependenciestable-stub
...@@ -88,7 +92,9 @@ exports[`DependenciesApp component on creation given a list of dependencies and ...@@ -88,7 +92,9 @@ exports[`DependenciesApp component on creation given a list of dependencies and
</glbadge-stub> </glbadge-stub>
</h4> </h4>
<dependenciesactions-stub /> <dependenciesactions-stub
namespace="allDependencies"
/>
</div> </div>
<dependenciestable-stub <dependenciestable-stub
...@@ -123,7 +129,9 @@ exports[`DependenciesApp component on creation given the dependency list job fai ...@@ -123,7 +129,9 @@ exports[`DependenciesApp component on creation given the dependency list job fai
<!----> <!---->
</h4> </h4>
<dependenciesactions-stub /> <dependenciesactions-stub
namespace="allDependencies"
/>
</div> </div>
<dependenciestable-stub <dependenciestable-stub
......
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import createStore from 'ee/dependencies/store'; import createStore from 'ee/dependencies/store';
import { REPORT_STATUS } from 'ee/dependencies/store/constants'; import { DEPENDENCY_LIST_TYPES } from 'ee/dependencies/store/constants';
import { REPORT_STATUS } from 'ee/dependencies/store/modules/list/constants';
import DependenciesApp from 'ee/dependencies/components/app.vue'; import DependenciesApp from 'ee/dependencies/components/app.vue';
import DependenciesTable from 'ee/dependencies/components/dependencies_table.vue'; import DependenciesTable from 'ee/dependencies/components/dependencies_table.vue';
import DependencyListIncompleteAlert from 'ee/dependencies/components/dependency_list_incomplete_alert.vue'; import DependencyListIncompleteAlert from 'ee/dependencies/components/dependency_list_incomplete_alert.vue';
...@@ -11,6 +12,7 @@ import Pagination from '~/vue_shared/components/pagination_links.vue'; ...@@ -11,6 +12,7 @@ import Pagination from '~/vue_shared/components/pagination_links.vue';
describe('DependenciesApp component', () => { describe('DependenciesApp component', () => {
let store; let store;
let wrapper; let wrapper;
const listType = DEPENDENCY_LIST_TYPES.all;
const basicAppProps = { const basicAppProps = {
endpoint: '/foo', endpoint: '/foo',
...@@ -51,8 +53,8 @@ describe('DependenciesApp component', () => { ...@@ -51,8 +53,8 @@ describe('DependenciesApp component', () => {
it('dispatches the correct initial actions', () => { it('dispatches the correct initial actions', () => {
expect(store.dispatch.mock.calls).toEqual([ expect(store.dispatch.mock.calls).toEqual([
['setDependenciesEndpoint', basicAppProps.endpoint], [`${listType}/setDependenciesEndpoint`, basicAppProps.endpoint],
['fetchDependencies'], [`${listType}/fetchDependencies`, undefined],
]); ]);
}); });
...@@ -64,13 +66,13 @@ describe('DependenciesApp component', () => { ...@@ -64,13 +66,13 @@ describe('DependenciesApp component', () => {
beforeEach(() => { beforeEach(() => {
dependencies = ['foo', 'bar']; dependencies = ['foo', 'bar'];
Object.assign(store.state, { Object.assign(store.state[listType], {
initialized: true, initialized: true,
isLoading: false, isLoading: false,
dependencies, dependencies,
}); });
store.state.pageInfo.total = 100; store.state[listType].pageInfo.total = 100;
store.state.reportInfo.status = REPORT_STATUS.ok; store.state[listType].reportInfo.status = REPORT_STATUS.ok;
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
}); });
...@@ -88,7 +90,7 @@ describe('DependenciesApp component', () => { ...@@ -88,7 +90,7 @@ describe('DependenciesApp component', () => {
it('passes the correct props to the pagination', () => { it('passes the correct props to the pagination', () => {
expectComponentWithProps(Pagination, { expectComponentWithProps(Pagination, {
pageInfo: store.state.pageInfo, pageInfo: store.state[listType].pageInfo,
change: wrapper.vm.fetchPage, change: wrapper.vm.fetchPage,
}); });
}); });
...@@ -98,13 +100,13 @@ describe('DependenciesApp component', () => { ...@@ -98,13 +100,13 @@ describe('DependenciesApp component', () => {
beforeEach(() => { beforeEach(() => {
dependencies = []; dependencies = [];
Object.assign(store.state, { Object.assign(store.state[listType], {
initialized: true, initialized: true,
isLoading: false, isLoading: false,
dependencies, dependencies,
}); });
store.state.pageInfo.total = 0; store.state[listType].pageInfo.total = 0;
store.state.reportInfo.status = REPORT_STATUS.jobNotSetUp; store.state[listType].reportInfo.status = REPORT_STATUS.jobNotSetUp;
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
}); });
...@@ -118,14 +120,14 @@ describe('DependenciesApp component', () => { ...@@ -118,14 +120,14 @@ describe('DependenciesApp component', () => {
beforeEach(() => { beforeEach(() => {
dependencies = []; dependencies = [];
Object.assign(store.state, { Object.assign(store.state[listType], {
initialized: true, initialized: true,
isLoading: false, isLoading: false,
dependencies, dependencies,
}); });
store.state.pageInfo.total = 0; store.state[listType].pageInfo.total = 0;
store.state.reportInfo.status = REPORT_STATUS.jobFailed; store.state[listType].reportInfo.status = REPORT_STATUS.jobFailed;
store.state.reportInfo.jobPath = '/jobs/foo/321'; store.state[listType].reportInfo.jobPath = '/jobs/foo/321';
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
}); });
...@@ -136,7 +138,7 @@ describe('DependenciesApp component', () => { ...@@ -136,7 +138,7 @@ describe('DependenciesApp component', () => {
it('passes the correct props to the job failure alert', () => { it('passes the correct props to the job failure alert', () => {
expectComponentWithProps(DependencyListJobFailedAlert, { expectComponentWithProps(DependencyListJobFailedAlert, {
jobPath: store.state.reportInfo.jobPath, jobPath: store.state[listType].reportInfo.jobPath,
}); });
}); });
...@@ -168,13 +170,13 @@ describe('DependenciesApp component', () => { ...@@ -168,13 +170,13 @@ describe('DependenciesApp component', () => {
beforeEach(() => { beforeEach(() => {
dependencies = ['foo', 'bar']; dependencies = ['foo', 'bar'];
Object.assign(store.state, { Object.assign(store.state[listType], {
initialized: true, initialized: true,
isLoading: false, isLoading: false,
dependencies, dependencies,
}); });
store.state.pageInfo.total = 100; store.state[listType].pageInfo.total = 100;
store.state.reportInfo.status = REPORT_STATUS.incomplete; store.state[listType].reportInfo.status = REPORT_STATUS.incomplete;
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
}); });
...@@ -197,7 +199,7 @@ describe('DependenciesApp component', () => { ...@@ -197,7 +199,7 @@ describe('DependenciesApp component', () => {
it('passes the correct props to the pagination', () => { it('passes the correct props to the pagination', () => {
expectComponentWithProps(Pagination, { expectComponentWithProps(Pagination, {
pageInfo: store.state.pageInfo, pageInfo: store.state[listType].pageInfo,
change: wrapper.vm.fetchPage, change: wrapper.vm.fetchPage,
}); });
}); });
...@@ -219,7 +221,7 @@ describe('DependenciesApp component', () => { ...@@ -219,7 +221,7 @@ describe('DependenciesApp component', () => {
beforeEach(() => { beforeEach(() => {
dependencies = []; dependencies = [];
Object.assign(store.state, { Object.assign(store.state[listType], {
initialized: true, initialized: true,
isLoading: false, isLoading: false,
errorLoading: true, errorLoading: true,
......
...@@ -2,14 +2,16 @@ import { createLocalVue, shallowMount } from '@vue/test-utils'; ...@@ -2,14 +2,16 @@ import { createLocalVue, shallowMount } from '@vue/test-utils';
import { GlDropdownItem } from '@gitlab/ui'; import { GlDropdownItem } from '@gitlab/ui';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import createStore from 'ee/dependencies/store'; import createStore from 'ee/dependencies/store';
import { SORT_FIELDS } from 'ee/dependencies/store/constants'; import { DEPENDENCY_LIST_TYPES } from 'ee/dependencies/store/constants';
import { SORT_FIELDS } from 'ee/dependencies/store/modules/list/constants';
import DependenciesActions from 'ee/dependencies/components/dependencies_actions.vue'; import DependenciesActions from 'ee/dependencies/components/dependencies_actions.vue';
describe('DependenciesActions component', () => { describe('DependenciesActions component', () => {
let store; let store;
let wrapper; let wrapper;
const listType = DEPENDENCY_LIST_TYPES.all;
const factory = () => { const factory = (props = {}) => {
const localVue = createLocalVue(); const localVue = createLocalVue();
store = createStore(); store = createStore();
...@@ -19,12 +21,13 @@ describe('DependenciesActions component', () => { ...@@ -19,12 +21,13 @@ describe('DependenciesActions component', () => {
localVue, localVue,
store, store,
sync: false, sync: false,
propsData: { ...props },
}); });
}; };
beforeEach(() => { beforeEach(() => {
factory(); factory({ namespace: listType });
store.state.endpoint = `${TEST_HOST}/dependencies`; store.state[listType].endpoint = `${TEST_HOST}/dependencies`;
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
}); });
...@@ -46,21 +49,23 @@ describe('DependenciesActions component', () => { ...@@ -46,21 +49,23 @@ describe('DependenciesActions component', () => {
}); });
expect(store.dispatch.mock.calls).toEqual( expect(store.dispatch.mock.calls).toEqual(
expect.arrayContaining(Object.keys(SORT_FIELDS).map(field => ['setSortField', field])), expect.arrayContaining(
Object.keys(SORT_FIELDS).map(field => [`${listType}/setSortField`, field]),
),
); );
}); });
it('dispatches the toggleSortOrder action on clicking the sort order button', () => { it('dispatches the toggleSortOrder action on clicking the sort order button', () => {
const sortButton = wrapper.find('.js-sort-order'); const sortButton = wrapper.find('.js-sort-order');
sortButton.vm.$emit('click'); sortButton.vm.$emit('click');
expect(store.dispatch).toHaveBeenCalledWith('toggleSortOrder'); expect(store.dispatch).toHaveBeenCalledWith(`${listType}/toggleSortOrder`);
}); });
it('has a button to export the dependency list', () => { it('has a button to export the dependency list', () => {
const download = wrapper.find('.js-download'); const download = wrapper.find('.js-download');
expect(download.attributes()).toEqual( expect(download.attributes()).toEqual(
expect.objectContaining({ expect.objectContaining({
href: store.getters.downloadEndpoint, href: store.getters[`${listType}/downloadEndpoint`],
download: expect.any(String), download: expect.any(String),
}), }),
); );
......
...@@ -3,10 +3,10 @@ import axios from 'axios'; ...@@ -3,10 +3,10 @@ import axios from 'axios';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import * as actions from 'ee/dependencies/store/actions'; import * as actions from 'ee/dependencies/store/modules/list/actions';
import * as types from 'ee/dependencies/store/mutation_types'; import * as types from 'ee/dependencies/store/modules/list/mutation_types';
import getInitialState from 'ee/dependencies/store/state'; import getInitialState from 'ee/dependencies/store/modules/list/state';
import { SORT_ORDER, FETCH_ERROR_MESSAGE } from 'ee/dependencies/store/constants'; import { SORT_ORDER, FETCH_ERROR_MESSAGE } from 'ee/dependencies/store/modules/list/constants';
import createFlash from '~/flash'; import createFlash from '~/flash';
import mockDependenciesResponse from './data/mock_dependencies'; import mockDependenciesResponse from './data/mock_dependencies';
......
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import * as getters from 'ee/dependencies/store/getters'; import * as getters from 'ee/dependencies/store/modules/list/getters';
import { REPORT_STATUS } from 'ee/dependencies/store/constants'; import { REPORT_STATUS } from 'ee/dependencies/store/modules/list/constants';
describe('Dependencies getters', () => { describe('Dependencies getters', () => {
describe.each` describe.each`
......
import * as types from 'ee/dependencies/store/mutation_types'; import * as types from 'ee/dependencies/store/modules/list/mutation_types';
import mutations from 'ee/dependencies/store/mutations'; import mutations from 'ee/dependencies/store/modules/list/mutations';
import getInitialState from 'ee/dependencies/store/state'; import getInitialState from 'ee/dependencies/store/modules/list/state';
import { REPORT_STATUS, SORT_ORDER } from 'ee/dependencies/store/constants'; import { REPORT_STATUS, SORT_ORDER } from 'ee/dependencies/store/modules/list/constants';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
describe('Dependencies mutations', () => { describe('Dependencies mutations', () => {
......
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