Commit 247cee62 authored by samdbeckham's avatar samdbeckham

Adds error states for the group sec dashboard

- Adds seperate error states for count and list failures
- Displays different errors when one, or both fails
- Updates tests to match
parent 029b9639
......@@ -7,7 +7,6 @@ import Tab from '~/vue_shared/components/tabs/tab.vue';
import IssueModal from 'ee/vue_shared/security_reports/components/modal.vue';
import SecurityDashboardTable from './security_dashboard_table.vue';
import VulnerabilityCountList from './vulnerability_count_list.vue';
import SvgBlankState from '~/pipelines/components/blank_state.vue';
import Icon from '~/vue_shared/components/icon.vue';
import popover from '~/vue_shared/directives/popover';
......@@ -20,7 +19,6 @@ export default {
Icon,
IssueModal,
SecurityDashboardTable,
SvgBlankState,
Tab,
Tabs,
VulnerabilityCountList,
......@@ -30,14 +28,6 @@ export default {
type: String,
required: true,
},
emptyStateSvgPath: {
type: String,
required: true,
},
errorStateSvgPath: {
type: String,
required: true,
},
vulnerabilitiesEndpoint: {
type: String,
required: true,
......@@ -49,7 +39,7 @@ export default {
},
computed: {
...mapGetters('vulnerabilities', ['vulnerabilitiesCountByReportType']),
...mapState('vulnerabilities', ['hasError', 'modal']),
...mapState('vulnerabilities', ['modal']),
sastCount() {
return this.vulnerabilitiesCountByReportType('sast');
},
......@@ -96,50 +86,39 @@ export default {
<template>
<div>
<div class="flash-container"></div>
<svg-blank-state
v-if="hasError"
:svg-path="errorStateSvgPath"
:message="s__(`Security Reports|There was an error fetching the dashboard.
Please try again in a few moments or contact your support team.`)"
/>
<div v-else>
<vulnerability-count-list />
<tabs stop-propagation>
<tab active>
<template slot="title">
<span>{{ __('SAST') }}</span>
<span
v-if="sastCount"
class="badge badge-pill"
>
{{ sastCount }}
</span>
<span
v-popover="popoverOptions"
class="text-muted prepend-left-4"
:aria-label="__('help')"
>
<icon
name="question"
class="vertical-align-middle"
/>
</span>
</template>
<vulnerability-count-list />
<tabs stop-propagation>
<tab active>
<template slot="title">
<span>{{ __('SAST') }}</span>
<span
v-if="sastCount"
class="badge badge-pill"
>
{{ sastCount }}
</span>
<span
v-popover="popoverOptions"
class="text-muted prepend-left-4"
:aria-label="__('help')"
>
<icon
name="question"
class="vertical-align-middle"
/>
</span>
</template>
<security-dashboard-table
:empty-state-svg-path="emptyStateSvgPath"
/>
</tab>
</tabs>
<issue-modal
:modal="modal"
:can-create-issue-permission="true"
:can-create-feedback-permission="true"
@createNewIssue="createIssue({ vulnerability: modal.vulnerability })"
@dismissIssue="dismissVulnerability({ vulnerability: modal.vulnerability })"
@revertDismissIssue="undoDismissal({ vulnerability: modal.vulnerability })"
/>
</div>
<security-dashboard-table />
</tab>
</tabs>
<issue-modal
:modal="modal"
:can-create-issue-permission="true"
:can-create-feedback-permission="true"
@createNewIssue="createIssue({ vulnerability: modal.vulnerability })"
@dismissIssue="dismissVulnerability({ vulnerability: modal.vulnerability })"
@revertDismissIssue="undoDismissal({ vulnerability: modal.vulnerability })"
/>
</div>
</template>
......@@ -10,10 +10,19 @@ export default {
SecurityDashboardTableRow,
},
computed: {
...mapState('vulnerabilities', ['vulnerabilities', 'pageInfo', 'isLoadingVulnerabilities']),
...mapState('vulnerabilities', [
'vulnerabilities',
'pageInfo',
'isLoadingVulnerabilities',
'errorLoadingVulnerabilities',
'errorLoadingVulnerabilitiesCount',
]),
showPagination() {
return this.pageInfo && this.pageInfo.total;
},
showError() {
return this.errorLoadingVulnerabilities && !this.errorLoadingVulnerabilitiesCount;
},
},
created() {
this.fetchVulnerabilities();
......@@ -49,6 +58,16 @@ export default {
{{ s__('Reports|Confidence') }}
</div>
</div>
<div class="flash-container">
<div
v-if="showError"
class="flash-alert">
<div class="flash-text container-fluid container-limited limit-container-width">
{{ s__('Security Dashboard|Error fetching the vulnerability list. Please check your network connection and try again.') }}
</div>
</div>
</div>
<div v-if="isLoadingVulnerabilities">
<security-dashboard-table-row
......
......@@ -33,7 +33,7 @@ export default {
{{ severity }}
</div>
<div class="vulnerability-count-body">
<span v-if="isLoading">&nbsp;</span>
<span v-if="isLoading">&mdash;</span>
<span v-else>{{ count }}</span>
</div>
</div>
......
......@@ -12,19 +12,39 @@ export default {
},
computed: {
...mapGetters('vulnerabilities', ['vulnerabilitiesCountBySeverity']),
...mapState('vulnerabilities', ['isLoadingVulnerabilitiesCount']),
...mapState('vulnerabilities', [
'isLoadingVulnerabilitiesCount',
'errorLoadingVulnerabilitiesCount',
'errorLoadingVulnerabilities',
]),
counts() {
return SEVERITIES.map(severity => {
const count = this.vulnerabilitiesCountBySeverity(severity);
return { severity, count };
});
},
dashboardError() {
return this.errorLoadingVulnerabilitiesCount && this.errorLoadingVulnerabilities;
},
countError() {
return this.errorLoadingVulnerabilitiesCount && !this.errorLoadingVulnerabilities;
},
},
};
</script>
<template>
<div class="vulnerabilities-count-list">
<div class="flash-container">
<div
v-if="dashboardError"
class="flash-alert">
<div class="flash-text container-fluid container-limited limit-container-width">
{{ s__('Security Dashboard|Error fetching the dashboard data. Please check your network connection and try again.') }}
</div>
</div>
</div>
<div class="row">
<div
v-for="count in counts"
......@@ -38,6 +58,16 @@ export default {
/>
</div>
</div>
<div class="flash-container">
<div
v-if="countError"
class="flash-alert">
<div class="flash-text container-fluid container-limited limit-container-width">
{{ s__('Security Dashboard|Error fetching the vulnerability counts. Please check your network connection and try again.') }}
</div>
</div>
</div>
</div>
</template>
......
......@@ -112,9 +112,16 @@ export const receiveCreateIssueSuccess = ({ commit }, payload) => {
commit(types.RECEIVE_CREATE_ISSUE_SUCCESS, payload);
};
export const receiveCreateIssueError = ({ commit }) => {
export const receiveCreateIssueError = ({ commit }, { flashError }) => {
commit(types.RECEIVE_CREATE_ISSUE_ERROR);
createFlash(s__('Security Reports|There was an error creating the issue.'));
if (flashError) {
createFlash(
s__('Security Reports|There was an error creating the issue.'),
'alert',
document.querySelector('.ci-table'),
);
}
};
export const dismissVulnerability = ({ dispatch }, { vulnerability, flashError }) => {
......@@ -152,7 +159,11 @@ export const receiveDismissVulnerabilitySuccess = ({ commit }, payload) => {
export const receiveDismissVulnerabilityError = ({ commit }, { flashError }) => {
commit(types.RECEIVE_DISMISS_VULNERABILITY_ERROR);
if (flashError) {
createFlash(s__('Security Reports|There was an error dismissing the issue.'));
createFlash(
s__('Security Reports|There was an error dismissing the vulnerability.'),
'alert',
document.querySelector('.ci-table'),
);
}
};
......@@ -185,7 +196,11 @@ export const receiveUndoDismissalSuccess = ({ commit }, payload) => {
export const receiveUndoDismissalError = ({ commit }, { flashError }) => {
commit(types.RECEIVE_UNDO_DISMISSAL_ERROR);
if (flashError) {
createFlash(s__('Security Reports|There was an error undoing this dismissal.'));
createFlash(
s__('Security Reports|There was an error undoing this dismissal.'),
'alert',
document.querySelector('.ci-table'),
);
}
};
......
......@@ -9,7 +9,7 @@ export default {
},
[types.REQUEST_VULNERABILITIES](state) {
state.isLoadingVulnerabilities = true;
state.hasError = false;
state.errorLoadingVulnerabilities = false;
},
[types.RECEIVE_VULNERABILITIES_SUCCESS](state, payload) {
state.isLoadingVulnerabilities = false;
......@@ -18,14 +18,14 @@ export default {
},
[types.RECEIVE_VULNERABILITIES_ERROR](state) {
state.isLoadingVulnerabilities = false;
state.hasError = true;
state.errorLoadingVulnerabilities = true;
},
[types.SET_VULNERABILITIES_COUNT_ENDPOINT](state, payload) {
state.vulnerabilitiesCountEndpoint = payload;
},
[types.REQUEST_VULNERABILITIES_COUNT](state) {
state.isLoadingVulnerabilitiesCount = true;
state.hasError = false;
state.errorLoadingVulnerabilitiesCount = false;
},
[types.RECEIVE_VULNERABILITIES_COUNT_SUCCESS](state, payload) {
state.isLoadingVulnerabilitiesCount = false;
......@@ -33,7 +33,7 @@ export default {
},
[types.RECEIVE_VULNERABILITIES_COUNT_ERROR](state) {
state.isLoadingVulnerabilitiesCount = false;
state.hasError = true;
state.errorLoadingVulnerabilitiesCount = true;
},
[types.SET_MODAL_DATA](state, payload) {
const { vulnerability } = payload;
......
import { s__ } from '~/locale';
export default () => ({
hasError: false,
isLoadingVulnerabilities: true,
errorLoadingVulnerabilities: false,
isLoadingVulnerabilitiesCount: true,
errorLoadingVulnerabilitiesCount: false,
pageInfo: {},
vulnerabilities: [],
vulnerabilitiesCount: {},
......
---
title: Adds split error states for the group security dashboard
merge_request: 8208
author:
type: changed
......@@ -21,7 +21,7 @@ describe('vulnerabilities module mutations', () => {
beforeEach(() => {
state = {
...createState(),
hasError: true,
errorLoadingVulnerabilities: true,
};
mutations[types.REQUEST_VULNERABILITIES](state);
});
......@@ -30,8 +30,8 @@ describe('vulnerabilities module mutations', () => {
expect(state.isLoadingVulnerabilities).toBeTruthy();
});
it('should set `hasError` to `false`', () => {
expect(state.hasError).toBeFalsy();
it('should set `errorLoadingVulnerabilities` to `false`', () => {
expect(state.errorLoadingVulnerabilities).toBeFalsy();
});
});
......@@ -88,7 +88,7 @@ describe('vulnerabilities module mutations', () => {
beforeEach(() => {
state = {
...createState(),
hasError: true,
errorLoadingVulnerabilitiesCount: true,
};
mutations[types.REQUEST_VULNERABILITIES_COUNT](state);
});
......@@ -97,8 +97,8 @@ describe('vulnerabilities module mutations', () => {
expect(state.isLoadingVulnerabilitiesCount).toBeTruthy();
});
it('should set `hasError` to `false`', () => {
expect(state.hasError).toBeFalsy();
it('should set `errorLoadingVulnerabilitiesCount` to `false`', () => {
expect(state.errorLoadingVulnerabilitiesCount).toBeFalsy();
});
});
......
......@@ -7016,6 +7016,15 @@ msgstr ""
msgid "Security Dashboard"
msgstr ""
msgid "Security Dashboard|Error fetching the dashboard data. Please check your network connection and try again."
msgstr ""
msgid "Security Dashboard|Error fetching the vulnerability counts. Please check your network connection and try again."
msgstr ""
msgid "Security Dashboard|Error fetching the vulnerability list. Please check your network connection and try again."
msgstr ""
msgid "Security Dashboard|Issue Created"
msgstr ""
......@@ -7037,15 +7046,9 @@ msgstr ""
msgid "Security Reports|There was an error creating the issue."
msgstr ""
msgid "Security Reports|There was an error dismissing the issue."
msgstr ""
msgid "Security Reports|There was an error dismissing the vulnerability."
msgstr ""
msgid "Security Reports|There was an error fetching the dashboard. Please try again in a few moments or contact your support team."
msgstr ""
msgid "Security Reports|There was an error undoing the dismissal."
msgstr ""
......
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