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