Commit 851b2b47 authored by Mark Florian's avatar Mark Florian Committed by Kushal Pandya

Add ability to sort Dependency List by Severity

This adds "Severity" to the available sorting options on the Dependency
List. This will sort the dependencies according to the severity of any
of their detected vulnerabilities.

This contributes towards the larger [feature][1] for adding dependency
scanning results to the Dependency List, behind the
`dependency_list_vulnerabilities` feature flag.

[1]: https://gitlab.com/gitlab-org/gitlab-ee/issues/10077
parent 6c2c7b66
......@@ -31,11 +31,6 @@ export default {
type: String,
required: true,
},
dependencyListVulnerabilities: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
......
......@@ -3,7 +3,11 @@ import { mapActions, mapState } from 'vuex';
import { GlButton, GlDropdown, GlDropdownItem, GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { DEPENDENCY_LIST_TYPES } from '../store/constants';
import { SORT_ORDER } from '../store/modules/list/constants';
import {
SORT_FIELDS,
SORT_FIELDS_WITH_SEVERITY,
SORT_ORDER,
} from '../store/modules/list/constants';
export default {
name: 'DependenciesActions',
......@@ -16,6 +20,12 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: {
dependencyListVulnerabilities: {
from: 'dependencyListVulnerabilities',
default: false,
},
},
props: {
namespace: {
type: String,
......@@ -23,14 +33,16 @@ export default {
validator: value => Object.values(DEPENDENCY_LIST_TYPES).includes(value),
},
},
data() {
return {
sortFields: this.dependencyListVulnerabilities ? SORT_FIELDS_WITH_SEVERITY : SORT_FIELDS,
};
},
computed: {
...mapState({
sortField(state) {
return state[this.namespace].sortField;
},
sortFields(state) {
return state[this.namespace].sortFields;
},
sortOrder(state) {
return state[this.namespace].sortOrder;
},
......
......@@ -15,13 +15,15 @@ export default () => {
components: {
DependenciesApp,
},
provide: {
dependencyListVulnerabilities,
},
render(createElement) {
return createElement(DependenciesApp, {
props: {
endpoint,
emptyStateSvgPath,
documentationPath,
dependencyListVulnerabilities,
},
});
},
......
......@@ -5,6 +5,11 @@ export const SORT_FIELDS = {
packager: s__('Dependencies|Packager'),
};
export const SORT_FIELDS_WITH_SEVERITY = {
...SORT_FIELDS,
severity: s__('Vulnerability|Severity'),
};
export const SORT_ORDER = {
ascending: 'asc',
descending: 'desc',
......
import { REPORT_STATUS, SORT_FIELDS, SORT_ORDER } from './constants';
import { REPORT_STATUS, SORT_ORDER } from './constants';
export default () => ({
endpoint: '',
......@@ -12,6 +12,5 @@ export default () => ({
jobPath: '',
},
sortField: 'name',
sortFields: SORT_FIELDS,
sortOrder: SORT_ORDER.ascending,
});
......@@ -72,3 +72,91 @@ exports[`DependenciesActions component matches the snapshot 1`] = `
</glbutton-stub>
</div>
`;
exports[`DependenciesActions component with feature flag enabled matches the snapshot 1`] = `
<div
class="btn-toolbar"
>
<div
class="btn-group flex-grow-1 mr-2"
>
<gldropdown-stub
class="flex-grow-1 text-center"
right=""
text="Component name"
>
<gldropdownitem-stub>
<span
class="d-flex"
>
<icon-stub
class="flex-shrink-0 append-right-4"
cssclasses=""
name="mobile-issue-close"
size="16"
/>
Component name
</span>
</gldropdownitem-stub>
<gldropdownitem-stub>
<span
class="d-flex"
>
<icon-stub
class="flex-shrink-0 append-right-4 invisible"
cssclasses=""
name="mobile-issue-close"
size="16"
/>
Packager
</span>
</gldropdownitem-stub>
<gldropdownitem-stub>
<span
class="d-flex"
>
<icon-stub
class="flex-shrink-0 append-right-4 invisible"
cssclasses=""
name="mobile-issue-close"
size="16"
/>
Severity
</span>
</gldropdownitem-stub>
</gldropdown-stub>
<glbutton-stub
class="flex-grow-0 js-sort-order"
data-original-title="Sort direction"
title=""
>
<icon-stub
cssclasses=""
name="sort-lowest"
size="16"
/>
</glbutton-stub>
</div>
<glbutton-stub
class="js-download"
data-original-title="Export as JSON"
download="dependencies.json"
href="http://test.host/dependencies.json"
title=""
>
<icon-stub
cssclasses=""
name="download"
size="16"
/>
</glbutton-stub>
</div>
`;
......@@ -3,30 +3,41 @@ import { GlDropdownItem } from '@gitlab/ui';
import { TEST_HOST } from 'helpers/test_constants';
import createStore from 'ee/dependencies/store';
import { DEPENDENCY_LIST_TYPES } from 'ee/dependencies/store/constants';
import { SORT_FIELDS } from 'ee/dependencies/store/modules/list/constants';
import {
SORT_FIELDS,
SORT_FIELDS_WITH_SEVERITY,
} from 'ee/dependencies/store/modules/list/constants';
import DependenciesActions from 'ee/dependencies/components/dependencies_actions.vue';
describe('DependenciesActions component', () => {
describe.each`
context | isFeatureFlagEnabled | sortFields
${''} | ${false} | ${SORT_FIELDS}
${' with feature flag enabled'} | ${true} | ${SORT_FIELDS_WITH_SEVERITY}
`('DependenciesActions component$context', ({ isFeatureFlagEnabled, sortFields }) => {
let store;
let wrapper;
const listType = DEPENDENCY_LIST_TYPES.all;
const factory = (props = {}) => {
const factory = ({ propsData, ...options } = {}) => {
const localVue = createLocalVue();
store = createStore();
jest.spyOn(store, 'dispatch').mockImplementation();
wrapper = shallowMount(localVue.extend(DependenciesActions), {
...options,
localVue,
store,
sync: false,
propsData: { ...props },
propsData: { ...propsData },
});
};
beforeEach(() => {
factory({ namespace: listType });
factory({
propsData: { namespace: listType },
provide: { dependencyListVulnerabilities: isFeatureFlagEnabled },
});
store.state[listType].endpoint = `${TEST_HOST}/dependencies`;
return wrapper.vm.$nextTick();
});
......@@ -50,7 +61,7 @@ describe('DependenciesActions component', () => {
expect(store.dispatch.mock.calls).toEqual(
expect.arrayContaining(
Object.keys(SORT_FIELDS).map(field => [`${listType}/setSortField`, field]),
Object.keys(sortFields).map(field => [`${listType}/setSortField`, field]),
),
);
});
......
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