Commit e69eff54 authored by Daniel Tian's avatar Daniel Tian

Clone vulnerability filters

parent d850bb85
<script>
import { debounce, cloneDeep, isEqual } from 'lodash';
import {
stateFilter,
severityFilter,
vendorScannerFilter,
simpleScannerFilter,
activityFilter,
getProjectFilter,
} from 'ee/security_dashboard/helpers';
import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ActivityFilter from '../filters/activity_filter.vue';
import ProjectFilter from '../filters/project_filter.vue';
import ProjectFilterDeprecated from '../filters/project_filter_deprecated.vue';
import ScannerFilter from '../filters/scanner_filter.vue';
import SimpleFilter from '../filters/simple_filter.vue';
export default {
components: {
SimpleFilter,
ScannerFilter,
ActivityFilter,
ProjectFilter,
ProjectFilterDeprecated,
},
mixins: [glFeatureFlagsMixin()],
inject: ['dashboardType'],
props: {
projects: { type: Array, required: false, default: undefined },
},
data() {
return {
filterQuery: {},
};
},
computed: {
isProjectDashboard() {
return this.dashboardType === DASHBOARD_TYPES.PROJECT;
},
isPipeline() {
return this.dashboardType === DASHBOARD_TYPES.PIPELINE;
},
isGroupDashboard() {
return this.dashboardType === DASHBOARD_TYPES.GROUP;
},
isInstanceDashboard() {
return this.dashboardType === DASHBOARD_TYPES.INSTANCE;
},
shouldShowProjectFilter() {
return this.isGroupDashboard || this.isInstanceDashboard;
},
shouldShowNewProjectFilter() {
return this.glFeatures.vulnReportNewProjectFilter && this.shouldShowProjectFilter;
},
projectFilter() {
return getProjectFilter(this.projects);
},
},
methods: {
updateFilterQuery(query) {
const oldQuery = cloneDeep(this.filterQuery);
this.filterQuery = { ...this.filterQuery, ...query };
if (!isEqual(oldQuery, this.filterQuery)) {
this.emitFilterChange();
}
},
// When this component is first shown, every filter will emit its own @filter-changed event at
// the same time, which will trigger this method multiple times. We'll debounce it so that it
// only runs once.
emitFilterChange: debounce(function emit() {
this.$emit('filterChange', this.filterQuery);
}),
},
simpleFilters: [stateFilter, severityFilter],
vendorScannerFilter,
simpleScannerFilter,
activityFilter,
};
</script>
<template>
<div
class="vulnerability-report-filters gl-p-5 gl-bg-gray-10 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
>
<simple-filter
v-for="filter in $options.simpleFilters"
:key="filter.id"
:filter="filter"
:data-testid="filter.id"
@filter-changed="updateFilterQuery"
/>
<scanner-filter
v-if="isProjectDashboard"
:filter="$options.vendorScannerFilter"
@filter-changed="updateFilterQuery"
/>
<simple-filter
v-else
:filter="$options.simpleScannerFilter"
:data-testid="$options.simpleScannerFilter.id"
@filter-changed="updateFilterQuery"
/>
<activity-filter
v-if="!isPipeline"
:filter="$options.activityFilter"
@filter-changed="updateFilterQuery"
/>
<project-filter
v-if="shouldShowNewProjectFilter"
:filter="projectFilter"
@filter-changed="updateFilterQuery"
/>
<project-filter-deprecated
v-else-if="shouldShowProjectFilter"
:filter="projectFilter"
:data-testid="projectFilter.id"
@filter-changed="updateFilterQuery"
/>
</div>
</template>
import { shallowMount } from '@vue/test-utils';
import ActivityFilter from 'ee/security_dashboard/components/shared/filters/activity_filter.vue';
import VulnerabilityFilters from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_filters.vue';
import ProjectFilter from 'ee/security_dashboard/components/shared/filters/project_filter.vue';
import ScannerFilter from 'ee/security_dashboard/components/shared/filters/scanner_filter.vue';
import SimpleFilter from 'ee/security_dashboard/components/shared/filters/simple_filter.vue';
import { getProjectFilter, simpleScannerFilter } from 'ee/security_dashboard/helpers';
import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
describe('First class vulnerability filters component', () => {
let wrapper;
const projects = [
{ id: 'gid://gitlab/Project/11', name: 'GitLab Org' },
{ id: 'gid://gitlab/Project/12', name: 'GitLab Com' },
];
const findSimpleFilters = () => wrapper.findAllComponents(SimpleFilter);
const findSimpleScannerFilter = () => wrapper.findByTestId(simpleScannerFilter.id);
const findVendorScannerFilter = () => wrapper.findComponent(ScannerFilter);
const findActivityFilter = () => wrapper.findComponent(ActivityFilter);
const findProjectFilter = () => wrapper.findByTestId(getProjectFilter([]).id);
const findNewProjectFilter = () => wrapper.findComponent(ProjectFilter);
const createComponent = ({ props, provide } = {}) => {
return extendedWrapper(
shallowMount(VulnerabilityFilters, {
propsData: props,
provide: {
dashboardType: DASHBOARD_TYPES.PROJECT,
...provide,
},
}),
);
};
afterEach(() => {
wrapper.destroy();
});
describe('on render without project filter', () => {
beforeEach(() => {
wrapper = createComponent();
});
it('should render the default filters', () => {
expect(findSimpleFilters()).toHaveLength(2);
expect(findActivityFilter().exists()).toBe(true);
expect(findProjectFilter().exists()).toBe(false);
});
it('should emit filterChange when a filter is changed', () => {
const options = { foo: 'bar' };
findActivityFilter().vm.$emit('filter-changed', options);
expect(wrapper.emitted('filterChange')[0][0]).toEqual(options);
});
});
describe('project filter', () => {
it.each`
dashboardType | isShown
${DASHBOARD_TYPES.PROJECT} | ${false}
${DASHBOARD_TYPES.PIPELINE} | ${false}
${DASHBOARD_TYPES.GROUP} | ${true}
${DASHBOARD_TYPES.INSTANCE} | ${true}
`(
'on the $dashboardType report the project filter shown is $isShown',
({ dashboardType, isShown }) => {
wrapper = createComponent({ provide: { dashboardType } });
expect(findProjectFilter().exists()).toBe(isShown);
},
);
it('should render the project filter with the expected options', () => {
wrapper = createComponent({
provide: { dashboardType: DASHBOARD_TYPES.GROUP },
props: { projects },
});
expect(findProjectFilter().props('filter').options).toEqual([
{ id: '11', name: projects[0].name },
{ id: '12', name: projects[1].name },
]);
});
it.each`
featureFlag | isProjectFilterShown | isNewProjectFilterShown
${false} | ${true} | ${false}
${true} | ${false} | ${true}
`(
'should show the correct project filter when vulnReportNewProjectFilter feature flag is $featureFlag',
({ featureFlag, isProjectFilterShown, isNewProjectFilterShown }) => {
wrapper = createComponent({
provide: {
dashboardType: DASHBOARD_TYPES.GROUP,
glFeatures: { vulnReportNewProjectFilter: featureFlag },
},
});
expect(findProjectFilter().exists()).toBe(isProjectFilterShown);
expect(findNewProjectFilter().exists()).toBe(isNewProjectFilterShown);
},
);
});
describe('activity filter', () => {
beforeEach(() => {
wrapper = createComponent({ provide: { dashboardType: DASHBOARD_TYPES.PIPELINE } });
});
it('does not display on the pipeline dashboard', () => {
expect(findActivityFilter().exists()).toBe(false);
});
});
describe('scanner filter', () => {
it.each`
type | dashboardType
${'vendor'} | ${DASHBOARD_TYPES.PROJECT}
${'simple'} | ${DASHBOARD_TYPES.GROUP}
${'simple'} | ${DASHBOARD_TYPES.INSTANCE}
${'simple'} | ${DASHBOARD_TYPES.PIPELINE}
`('shows the $type scanner filter on the $dashboardType report', ({ type, dashboardType }) => {
wrapper = createComponent({ provide: { dashboardType } });
expect(findSimpleScannerFilter().exists()).toBe(type === 'simple');
expect(findVendorScannerFilter().exists()).toBe(type === 'vendor');
});
});
});
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