Commit 37cd1364 authored by Clement Ho's avatar Clement Ho

Merge branch '12846-update-security-dashboard-layout-for-improved-usability' into 'master'

Update Security Dashboard layout for improved usability

Closes #12846

See merge request gitlab-org/gitlab-ee!15050
parents b01101a3 be636d8b
...@@ -121,18 +121,25 @@ export default { ...@@ -121,18 +121,25 @@ export default {
</script> </script>
<template> <template>
<div> <section>
<header>
<filters /> <filters />
<vulnerability-count-list :class="{ 'mb-0': isLockedToProject }" /> </header>
<vulnerability-chart v-if="!isLockedToProject" /> <vulnerability-count-list v-if="isLockedToProject" class="mb-0" />
<h4 v-if="!isLockedToProject" class="my-4">{{ __('Vulnerability List') }}</h4>
<div class="row mt-4">
<main role="main" class="col" :class="{ 'col-xl-7': !isLockedToProject }">
<security-dashboard-table <security-dashboard-table
:dashboard-documentation="dashboardDocumentation" :dashboard-documentation="dashboardDocumentation"
:empty-state-svg-path="emptyStateSvgPath" :empty-state-svg-path="emptyStateSvgPath"
/> />
</main>
<aside v-if="!isLockedToProject" class="col-xl-5">
<vulnerability-chart />
</aside>
</div>
<issue-modal <issue-modal
:modal="modal" :modal="modal"
...@@ -153,5 +160,5 @@ export default { ...@@ -153,5 +160,5 @@ export default {
@revertDismissVulnerability="undoDismiss({ vulnerability })" @revertDismissVulnerability="undoDismiss({ vulnerability })"
@downloadPatch="downloadPatch({ vulnerability })" @downloadPatch="downloadPatch({ vulnerability })"
/> />
</div> </section>
</template> </template>
...@@ -53,7 +53,7 @@ export default { ...@@ -53,7 +53,7 @@ export default {
</script> </script>
<template> <template>
<div class="ci-table"> <div class="ci-table js-security-dashboard-table">
<div <div
class="gl-responsive-table-row table-row-header vulnerabilities-row-header px-2" class="gl-responsive-table-row table-row-header vulnerabilities-row-header px-2"
role="row" role="row"
......
...@@ -3,7 +3,7 @@ import _ from 'underscore'; ...@@ -3,7 +3,7 @@ import _ from 'underscore';
import dateFormat from 'dateformat'; import dateFormat from 'dateformat';
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import GlLineChart from '@gitlab/ui/dist/components/charts/line/line'; import GlLineChart from '@gitlab/ui/dist/components/charts/line/line';
import { __ } from '~/locale'; import { __, s__, sprintf } from '~/locale';
import ChartTooltip from './vulnerability_chart_tooltip.vue'; import ChartTooltip from './vulnerability_chart_tooltip.vue';
import ChartButtons from './vulnerability_chart_buttons.vue'; import ChartButtons from './vulnerability_chart_buttons.vue';
import { DAY_IN_MS, DAYS } from '../store/modules/vulnerabilities/constants'; import { DAY_IN_MS, DAYS } from '../store/modules/vulnerabilities/constants';
...@@ -70,9 +70,9 @@ export default { ...@@ -70,9 +70,9 @@ export default {
options() { options() {
return { return {
grid: { grid: {
bottom: 70, bottom: 30,
left: 75, left: 30,
right: 15, right: 20,
top: 10, top: 10,
}, },
tooltip: { tooltip: {
...@@ -87,14 +87,7 @@ export default { ...@@ -87,14 +87,7 @@ export default {
margin: 8, margin: 8,
}, },
maxInterval: DAY_IN_MS * this.vulnerabilitiesHistoryMaxDayInterval, maxInterval: DAY_IN_MS * this.vulnerabilitiesHistoryMaxDayInterval,
min: Date.now() - DAY_IN_MS * this.vulnerabilitiesHistoryDayRange, min: this.startDate,
name: __('Date'),
nameGap: 35,
nameLocation: 'center',
nameTextStyle: {
color: '#2e2e2e',
fontWeight: 'bold',
},
type: 'time', type: 'time',
}, },
yAxis: { yAxis: {
...@@ -102,19 +95,21 @@ export default { ...@@ -102,19 +95,21 @@ export default {
color: '#707070', color: '#707070',
}, },
boundaryGap: [0, '5%'], boundaryGap: [0, '5%'],
name: __('Vulnerabilities'),
nameGap: 42,
nameLocation: 'center',
nameRotation: 90,
nameTextStyle: {
color: '#2e2e2e',
fontWeight: 'bold',
},
minInterval: 1, minInterval: 1,
type: 'value', type: 'value',
}, },
}; };
}, },
startDate() {
return Date.now() - DAY_IN_MS * this.vulnerabilitiesHistoryDayRange;
},
dateInfo() {
const formattedStartDate = dateFormat(this.startDate, 'mmmm dS');
return sprintf(s__('VulnerabilityChart|%{formattedStartDate} to today'), {
formattedStartDate,
});
},
days() { days() {
const { $options } = this; const { $options } = this;
return [$options.DAYS.THIRTY, $options.DAYS.SIXTY, $options.DAYS.NINETY]; return [$options.DAYS.THIRTY, $options.DAYS.SIXTY, $options.DAYS.NINETY];
...@@ -133,29 +128,34 @@ export default { ...@@ -133,29 +128,34 @@ export default {
</script> </script>
<template> <template>
<div> <section class="border rounded p-3">
<div class="d-flex justify-content-between"> <header>
<h4 class="my-4">{{ __('Vulnerability Chart') }}</h4> <h4 class="mt-0 mb-1">
{{ __('Vulnerabilities over time') }}
<div class="align-self-center"> </h4>
<p class="text-secondary mt-0 js-vulnerabilities-chart-time-info">
{{ dateInfo }}
</p>
</header>
<div class="align-self-center mb-3">
<chart-buttons <chart-buttons
:days="days" :days="days"
:active-day="vulnerabilitiesHistoryDayRange" :active-day="vulnerabilitiesHistoryDayRange"
@click="setVulnerabilitiesHistoryDayRange" @click="setVulnerabilitiesHistoryDayRange"
/> />
</div> </div>
</div>
<div class="vulnerabilities-chart"> <div class="vulnerabilities-chart">
<div class="vulnerabilities-chart-wrapper"> <div class="vulnerabilities-chart-wrapper">
<resizable-chart-container> <resizable-chart-container>
<gl-line-chart <gl-line-chart
slot-scope="{ width }" slot-scope="{ width }"
class="js-vulnerabilities-chart-line-chart"
:width="width" :width="width"
:option="options" :option="options"
:data="series" :data="series"
:format-tooltip-text="noop" :format-tooltip-text="noop"
:include-legend-avg-max="false" :include-legend-avg-max="true"
> >
<span slot="tooltipTitle">{{ tooltipTitle }}</span> <span slot="tooltipTitle">{{ tooltipTitle }}</span>
<chart-tooltip slot="tooltipContent" :entries="tooltipEntries" /> <chart-tooltip slot="tooltipContent" :entries="tooltipEntries" />
...@@ -163,5 +163,5 @@ export default { ...@@ -163,5 +163,5 @@ export default {
</resizable-chart-container> </resizable-chart-container>
</div> </div>
</div> </div>
</div> </section>
</template> </template>
...@@ -31,7 +31,7 @@ export default { ...@@ -31,7 +31,7 @@ export default {
</script> </script>
<template> <template>
<div class="btn-group"> <div class="btn-group w-100">
<gl-button <gl-button
v-for="day in days" v-for="day in days"
:key="day" :key="day"
......
---
title: Update Security Dashboard for improved usability
merge_request: 15050
author:
type: changed
...@@ -40,9 +40,14 @@ describe 'Group overview', :js do ...@@ -40,9 +40,14 @@ describe 'Group overview', :js do
it 'displays the Security Dashboard view' do it 'displays the Security Dashboard view' do
visit group_path(group) visit group_path(group)
page.within(find('.content')) do page.within(find('main')) do
expect(page).to have_content 'Vulnerability Chart' expect(page).to have_selector('.js-security-dashboard-table')
expect(page).to have_content 'Vulnerability List' end
page.within(find('aside')) do
expect(page).to have_content 'Vulnerabilities over time'
expect(page).to have_selector('.js-vulnerabilities-chart-time-info')
expect(page).to have_selector('.js-vulnerabilities-chart-line-chart')
end end
end end
end end
......
...@@ -63,16 +63,31 @@ describe('Card security reports app', () => { ...@@ -63,16 +63,31 @@ describe('Card security reports app', () => {
createComponent(); createComponent();
}); });
it('render sub components', () => { it('renders the filters', () => {
expect(wrapper.find(Filters).exists()).toBe(true); expect(wrapper.find(Filters).exists()).toBe(true);
});
it('renders the security dashboard table ', () => {
expect(wrapper.find(SecurityDashboardTable).exists()).toBe(true); expect(wrapper.find(SecurityDashboardTable).exists()).toBe(true);
});
it('renders the vulnerability chart', () => {
expect(wrapper.find(VulnerabilityChart).exists()).toBe(true); expect(wrapper.find(VulnerabilityChart).exists()).toBe(true);
expect(wrapper.find(VulnerabilityCountList).exists()).toBe(true);
}); });
it('fetches projects and does not lock projects filter', () => { it('does not render the vulnerability count list', () => {
expect(wrapper.find(VulnerabilityCountList).exists()).toBe(false);
});
it('does not lock to a project', () => {
expect(wrapper.vm.isLockedToProject).toBe(false); expect(wrapper.vm.isLockedToProject).toBe(false);
});
it('fetches projects', () => {
expect(fetchProjectsSpy).toHaveBeenCalled(); expect(fetchProjectsSpy).toHaveBeenCalled();
});
it('does not lock project filters', () => {
expect(lockFilterSpy).not.toHaveBeenCalled(); expect(lockFilterSpy).not.toHaveBeenCalled();
}); });
}); });
...@@ -89,9 +104,19 @@ describe('Card security reports app', () => { ...@@ -89,9 +104,19 @@ describe('Card security reports app', () => {
}); });
}); });
it('locks to given project and does not fetch projects', () => { it('renders the vulnerability count list', () => {
expect(wrapper.find(VulnerabilityCountList).exists()).toBe(true);
});
it('locks to a given project', () => {
expect(wrapper.vm.isLockedToProject).toBe(true); expect(wrapper.vm.isLockedToProject).toBe(true);
});
it('does not fetch projects', () => {
expect(fetchProjectsSpy).not.toHaveBeenCalled(); expect(fetchProjectsSpy).not.toHaveBeenCalled();
});
it('locks the filters to a given project', () => {
expect(lockFilterSpy).toHaveBeenCalledWith({ expect(lockFilterSpy).toHaveBeenCalledWith({
filterId: 'project_id', filterId: 'project_id',
optionId: project.id, optionId: project.id,
......
...@@ -4566,9 +4566,6 @@ msgstr "" ...@@ -4566,9 +4566,6 @@ msgstr ""
msgid "Data is still calculating..." msgid "Data is still calculating..."
msgstr "" msgstr ""
msgid "Date"
msgstr ""
msgid "Date picker" msgid "Date picker"
msgstr "" msgstr ""
...@@ -17063,13 +17060,13 @@ msgstr "" ...@@ -17063,13 +17060,13 @@ msgstr ""
msgid "Vulnerabilities" msgid "Vulnerabilities"
msgstr "" msgstr ""
msgid "Vulnerability Chart" msgid "Vulnerabilities over time"
msgstr "" msgstr ""
msgid "Vulnerability List" msgid "Vulnerability-Check requires one or more merge request approvals only if high or critical security vulnerabilities are detected."
msgstr "" msgstr ""
msgid "Vulnerability-Check requires one or more merge request approvals only if high or critical security vulnerabilities are detected." msgid "VulnerabilityChart|%{formattedStartDate} to today"
msgstr "" msgstr ""
msgid "Vulnerability|Class" msgid "Vulnerability|Class"
......
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