Commit dc14dd09 authored by Mark Florian's avatar Mark Florian

Merge branch '10703-remote-router-logic-from-dashboard-stores' into 'master'

Removes the router from old security dashboards

See merge request gitlab-org/gitlab!31353
parents b1f39ca5 390c008c
......@@ -6,10 +6,8 @@ import FirstClassGroupSecurityDashboard from './components/first_class_group_sec
import FirstClassInstanceSecurityDashboard from './components/first_class_instance_security_dashboard.vue';
import UnavailableState from './components/unavailable_state.vue';
import createStore from './store';
import createRouter from './store/router';
import projectsPlugin from './store/plugins/projects';
import projectSelector from './store/plugins/project_selector';
import syncWithRouter from './store/plugins/sync_with_router';
import apolloProvider from './graphql/provider';
const isRequired = message => {
......@@ -64,16 +62,14 @@ export default (
props.vulnerabilitiesExportEndpoint = el.dataset.vulnerabilitiesExportEndpoint;
}
const router = createRouter();
const store = createStore({
dashboardType,
plugins: [projectSelector, projectsPlugin, syncWithRouter(router)],
plugins: [projectSelector, projectsPlugin],
});
return new Vue({
el,
store,
router,
apolloProvider,
render(createElement) {
return createElement(component, { props });
......
......@@ -3,9 +3,7 @@ import GroupSecurityDashboard from './components/group_security_dashboard.vue';
import UnavailableState from './components/unavailable_state.vue';
import createStore from './store';
import { DASHBOARD_TYPES } from './store/constants';
import createRouter from './store/router';
import projectsPlugin from './store/plugins/projects';
import syncWithRouter from './store/plugins/sync_with_router';
export default () => {
const el = document.getElementById('js-group-security-dashboard');
......@@ -25,15 +23,13 @@ export default () => {
});
}
const router = createRouter();
const store = createStore({
dashboardType: DASHBOARD_TYPES.GROUP,
plugins: [projectsPlugin, syncWithRouter(router)],
plugins: [projectsPlugin],
});
return new Vue({
el,
store,
router,
render(createElement) {
return createElement(GroupSecurityDashboard, {
props: {
......
import Vue from 'vue';
import createRouter from './store/router';
import projectSelector from './store/plugins/project_selector';
import syncWithRouter from './store/plugins/sync_with_router';
import createStore from './store';
import { DASHBOARD_TYPES } from './store/constants';
import InstanceSecurityDashboard from './components/instance_security_dashboard.vue';
......@@ -19,15 +17,13 @@ export default () => {
vulnerabilityFeedbackHelpPath,
vulnerableProjectsEndpoint,
} = el.dataset;
const router = createRouter();
const store = createStore({
dashboardType: DASHBOARD_TYPES.INSTANCE,
plugins: [projectSelector, syncWithRouter(router)],
plugins: [projectSelector],
});
return new Vue({
el,
router,
store,
render(createElement) {
return createElement(InstanceSecurityDashboard, {
......
import Vue from 'vue';
import createRouter from './store/router';
import syncWithRouter from './store/plugins/sync_with_router';
import createStore from './store';
import { DASHBOARD_TYPES } from './store/constants';
import ProjectSecurityDashboard from './components/project_security_dashboard.vue';
......@@ -40,16 +38,13 @@ export default () => {
});
}
const router = createRouter();
const store = createStore({
dashboardType: DASHBOARD_TYPES.PROJECT,
plugins: [syncWithRouter(router)],
});
return new Vue({
el: securityTab,
store,
router,
render(createElement) {
return createElement(ProjectSecurityDashboard, {
props,
......
/**
* Vuex store plugin to sync some Group Security Dashboard view settings with the URL.
*/
export default router => store => {
let syncingRouter = false;
// Update store from routing events
router.beforeEach((to, from, next) => {
const updatedFromState = (to.params && to.params.updatedFromState) || false;
if (to.name === 'dashboard' && !updatedFromState) {
syncingRouter = true;
const page = parseInt(to.query.page, 10) || 1;
store.dispatch(`vulnerabilities/setVulnerabilitiesPage`, page);
const dayRange = parseInt(to.query.days, 10);
if (Number.isFinite(dayRange)) {
store.dispatch(`vulnerabilities/setVulnerabilitiesHistoryDayRange`, dayRange);
}
store.dispatch(`filters/setAllFilters`, to.query);
syncingRouter = false;
}
next();
});
// Update router from store mutations
const updateRouter = (queryParams = {}) => {
const activeFilters = store.getters['filters/activeFilters'];
const routePayload = {
name: 'dashboard',
query: {
...activeFilters,
page: store.state.vulnerabilities.pageInfo.page,
days: store.state.vulnerabilities.vulnerabilitiesHistoryDayRange,
...queryParams,
},
params: { updatedFromState: true },
};
const resolvedRoute = router.resolve(routePayload);
if (resolvedRoute.route.fullPath !== router.currentRoute.fullPath) {
router.push(routePayload);
}
};
store.subscribeAction(({ type, payload }) => {
if (syncingRouter) {
return;
}
switch (type) {
case `vulnerabilities/fetchVulnerabilities`:
updateRouter({ page: payload.page });
break;
case `vulnerabilities/setVulnerabilitiesHistoryDayRange`:
updateRouter({ days: payload });
break;
default:
}
});
};
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
// Unfortunately Vue Router doesn't work without at least a fake component
// If you do only data handling
const EmptyRouterComponent = {
render(createElement) {
return createElement('div');
},
};
export default () => {
const routes = [{ path: '/', name: 'dashboard', component: EmptyRouterComponent }];
const router = new VueRouter({
mode: 'history',
base: window.location.pathname,
routes,
});
return router;
};
import createStore from 'ee/security_dashboard/store/index';
import syncWithRouter from 'ee/security_dashboard/store/plugins/sync_with_router';
import createRouter from 'ee/security_dashboard/store/router';
import { DAYS } from 'ee/security_dashboard/store/modules/vulnerabilities/constants';
describe('syncWithRouter', () => {
let router;
let store;
const noop = () => {};
beforeEach(() => {
router = createRouter();
store = createStore({ plugins: [syncWithRouter(router)] });
});
it('updates store after URL changes', () => {
const page = 3;
const days = DAYS.SIXTY;
const query = { example: ['test'], page, days };
jest.spyOn(store, 'dispatch');
const routerPush = router.push.bind(router);
jest.spyOn(router, 'push');
routerPush({ name: 'dashboard', query });
// Assert no implicit synchronous recursive calls occurred
expect(router.push).not.toHaveBeenCalled();
expect(store.dispatch).toHaveBeenCalledWith(`filters/setAllFilters`, query);
expect(store.dispatch).toHaveBeenCalledWith(`vulnerabilities/setVulnerabilitiesPage`, page);
expect(store.dispatch).toHaveBeenCalledWith(
`vulnerabilities/setVulnerabilitiesHistoryDayRange`,
days,
);
});
it('sets page to 1 if query query string does not contain a page param after URL changes', () => {
const page = undefined;
const days = DAYS.SIXTY;
const query = { example: ['test'], page, days };
jest.spyOn(store, 'dispatch');
const routerPush = router.push.bind(router);
jest.spyOn(router, 'push');
routerPush({ name: 'dashboard', query });
expect(store.dispatch).toHaveBeenCalledWith(`vulnerabilities/setVulnerabilitiesPage`, 1);
});
it("doesn't update the store if the URL update originated from the mediator", () => {
const query = { example: ['test'] };
jest.spyOn(store, 'commit').mockImplementation(noop);
router.push({ name: 'dashboard', query, params: { updatedFromState: true } });
expect(store.commit).toHaveBeenCalledTimes(0);
});
it('it updates the route after a successful vulnerability retrieval', () => {
const activeFilters = store.getters['filters/activeFilters'];
const page = 2;
jest.spyOn(router, 'push').mockImplementation(noop);
store.dispatch(`vulnerabilities/fetchVulnerabilities`, { page });
expect(router.push).toHaveBeenCalledTimes(1);
expect(router.push).toHaveBeenCalledWith(
expect.objectContaining({
name: 'dashboard',
query: expect.objectContaining({
...activeFilters,
page,
days: store.state.vulnerabilities.vulnerabilitiesHistoryDayRange,
}),
params: { updatedFromState: true },
}),
);
});
it('it updates the route after changing the vulnerability history day range', () => {
const activeFilters = store.getters['filters/activeFilters'];
const days = DAYS.SIXTY;
jest.spyOn(router, 'push').mockImplementation(noop);
store.dispatch(`vulnerabilities/setVulnerabilitiesHistoryDayRange`, days);
expect(router.push).toHaveBeenCalledTimes(1);
expect(router.push).toHaveBeenCalledWith(
expect.objectContaining({
name: 'dashboard',
query: expect.objectContaining({
...activeFilters,
page: store.state.vulnerabilities.pageInfo.page,
days,
}),
params: { updatedFromState: true },
}),
);
});
});
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