Commit 786a5be6 authored by Filipa Lacerda's avatar Filipa Lacerda

Allow to render the report without the collapse button

parent fa195537
<script>
import CollapsibleSection from 'ee/vue_shared/security_reports/components/report_collapsible_section.vue';
import ReportSection from 'ee/vue_shared/security_reports/components/report_section.vue';
import securityMixin from 'ee/vue_shared/security_reports/mixins/security_report_mixin';
import LoadingIcon from '../../../vue_shared/components/loading_icon.vue';
......@@ -7,7 +7,7 @@
name: 'SecurityReportTab',
components: {
LoadingIcon,
CollapsibleSection,
ReportSection,
},
mixins: [
securityMixin,
......@@ -22,7 +22,7 @@
</script>
<template>
<div class="pipeline-graph">
<collapsible-section
<report-section
class="js-sast-widget"
type="security"
:status="checkReportStatus(securityReports.sast.isLoading, securityReports.sast.hasError)"
......@@ -33,6 +33,7 @@
:resolved-issues="securityReports.sast.resolvedIssues"
:all-issues="securityReports.sast.allIssues"
:has-priority="true"
:is-collapsible="false"
/>
</div>
</template>
......@@ -85,13 +85,15 @@ document.addEventListener('DOMContentLoaded', () => {
SecurityReportApp,
},
data() {
const datasetOptions = this.$options.el.dataset;
return {
endpoint: this.$options.el.dataset.endpoint,
endpoint: datasetOptions.endpoint,
blobPath: datasetOptions.blobPath,
mediator,
};
},
created() {
this.mediator.fetchSastReport(this.endpoint);
this.mediator.fetchSastReport(this.endpoint, this.blobPath);
},
render(createElement) {
return createElement('security-report-app', {
......
......@@ -60,11 +60,11 @@ export default class pipelinesMediator {
/**
* EE only
*/
fetchSastReport(endpoint) {
fetchSastReport(endpoint, blobPath) {
PipelineService.getSecurityReport(endpoint)
.then(response => response.json())
.then((data) => {
this.store.storeSastData(data);
this.store.storeSastData(data, blobPath);
})
.catch(() => Flash(__('Something when wrong while fetching SAST.')));
}
......
......@@ -20,7 +20,10 @@ export default class PipelineStore {
/**
* EE only
*/
storeSastReport(data) {
Object.assign(this.state.securityReports.sast, setSastReport({ head: data, headBlobPath: '' }));
storeSastReport(data, blobPath) {
Object.assign(
this.state.securityReports.sast,
setSastReport({ head: data, headBlobPath: blobPath }),
);
}
}
......@@ -61,4 +61,4 @@
%pre.build-log= build_summary(build, skip: index >= 10)
- if sast_artifact
#js-tab-security.build-security.tab-pane
#js-security-report-app{ data: { endpoint: sast_artifact_url} }
#js-security-report-app{ data: { endpoint: sast_artifact_url, blobPath: '' } }
......@@ -2,7 +2,7 @@ import { n__, s__, __ } from '~/locale';
import CEWidgetOptions from '~/vue_merge_request_widget/mr_widget_options';
import WidgetApprovals from './components/approvals/mr_widget_approvals';
import GeoSecondaryNode from './components/states/mr_widget_secondary_geo_node';
import CollapsibleSection from '../vue_shared/security_reports/components/report_collapsible_section.vue';
import ReportSection from '../vue_shared/security_reports/components/report_section.vue';
import securityMixin from '../vue_shared/security_reports/mixins/security_report_mixin';
export default {
......@@ -10,7 +10,7 @@ export default {
components: {
'mr-widget-approvals': WidgetApprovals,
'mr-widget-geo-secondary-node': GeoSecondaryNode,
CollapsibleSection,
ReportSection,
},
mixins: [
securityMixin,
......@@ -308,7 +308,7 @@ export default {
:mr="mr"
:service="service"
/>
<collapsible-section
<report-section
class="js-codequality-widget"
v-if="shouldRenderCodeQuality"
type="codequality"
......@@ -319,7 +319,7 @@ export default {
:unresolved-issues="mr.codeclimateMetrics.newIssues"
:resolved-issues="mr.codeclimateMetrics.resolvedIssues"
/>
<collapsible-section
<report-section
class="js-performance-widget"
v-if="shouldRenderPerformance"
type="performance"
......@@ -331,7 +331,7 @@ export default {
:resolved-issues="mr.performanceMetrics.improved"
:neutral-issues="mr.performanceMetrics.neutral"
/>
<collapsible-section
<report-section
class="js-sast-widget"
v-if="shouldRenderSecurityReport"
type="security"
......@@ -344,7 +344,7 @@ export default {
:all-issues="mr.securityReport.allIssues"
:has-priority="true"
/>
<collapsible-section
<report-section
class="js-docker-widget"
v-if="shouldRenderDockerReport"
type="docker"
......@@ -357,7 +357,7 @@ export default {
:info-text="sastContainerInformationText()"
:has-priority="true"
/>
<collapsible-section
<report-section
class="js-dast-widget"
v-if="shouldRenderDastReport"
type="dast"
......
......@@ -5,13 +5,18 @@
import IssuesBlock from './report_issues.vue';
export default {
name: 'ReportCollapsibleSection',
name: 'ReportSection',
components: {
IssuesBlock,
LoadingIcon,
StatusIcon,
},
props: {
isCollapsible: {
type: Boolean,
required: false,
default: true,
},
// security | codequality | performance | docker
type: {
type: String,
......@@ -67,10 +72,16 @@
},
data() {
if (this.isCollapsible) {
return {
collapseText: __('Expand'),
isCollapsed: true,
isFullReportVisible: false,
};
}
return {
collapseText: __('Expand'),
isCollapsed: true,
isFullReportVisible: false,
isFullReportVisible: true,
};
},
......@@ -148,8 +159,8 @@
<button
type="button"
class="btn pull-right btn-sm"
v-if="hasIssues"
class="js-collapse-btn btn pull-right btn-sm"
v-if="isCollapsible && hasIssues"
@click="toggleCollapsed"
>
{{ collapseText }}
......@@ -160,7 +171,7 @@
<div
class="report-block-container"
v-if="hasIssues"
v-show="!isCollapsed"
v-show="!isCollapsible || (isCollapsible && !isCollapsed)"
>
<p
......
<script>
import LoadingIcon from '~/vue_shared/components/loading_icon.vue';
export default {
name: 'ReportSummary',
components: {
LoadingIcon,
},
props: {
// security | codequality | performance | docker
type: {
type: String,
required: true,
},
// loading | success | error
status: {
type: String,
required: true,
},
loadingText: {
type: String,
required: true,
},
errorText: {
type: String,
required: true,
},
successText: {
type: String,
required: true,
},
hasCollapseButton: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
isLoading() {
return this.status === 'loading';
},
loadingFailed() {
return this.status === 'error';
},
isSuccess() {
return this.status === 'success';
},
statusIconName() {
if (this.loadingFailed || this.unresolvedIssues.length) {
return 'warning';
}
return 'success';
},
},
methods: {
toggleCollapsed() {
this.$emit('toggleCollapsed');
},
},
};
</script>
<template>
<div>
<div
v-if="isLoading"
class="media"
>
<div
class="mr-widget-icon"
>
<loading-icon />
</div>
<div
class="media-body"
>
{{ loadingText }}
</div>
</div>
<div
v-else-if="isSuccess"
class="media"
>
<status-icon
:status="statusIconName"
/>
<div
class="media-body space-children"
>
<span
class="js-code-text"
>
{{ successText }}
</span>
<button
type="button"
class="btn pull-right btn-sm"
v-if="hasCollapseButton"
@click="toggleCollapsed"
>
{{ collapseText }}
</button>
</div>
</div>
</div>
</template>
import Vue from 'vue';
import reportCollapsibleSection from 'ee/vue_shared/security_reports/components/report_collapsible_section.vue';
import reportSection from 'ee/vue_shared/security_reports/components/report_section.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper';
import { codequalityParsedIssues } from '../../../vue_mr_widget/mock_data';
describe('Report Collapsible section', () => {
describe('Report section', () => {
let vm;
let ReportCollapsibleSection;
let ReportSection;
beforeEach(() => {
ReportCollapsibleSection = Vue.extend(reportCollapsibleSection);
ReportSection = Vue.extend(reportSection);
});
afterEach(() => {
......@@ -17,7 +17,7 @@ describe('Report Collapsible section', () => {
describe('when it is loading', () => {
it('should render loading indicator', () => {
vm = mountComponent(ReportCollapsibleSection, {
vm = mountComponent(ReportSection, {
type: 'codequality',
status: 'loading',
loadingText: 'Loading codeclimate report',
......@@ -30,7 +30,7 @@ describe('Report Collapsible section', () => {
describe('with success status', () => {
it('should render provided data', () => {
vm = mountComponent(ReportCollapsibleSection, {
vm = mountComponent(ReportSection, {
type: 'codequality',
status: 'success',
loadingText: 'Loading codeclimate report',
......@@ -50,7 +50,7 @@ describe('Report Collapsible section', () => {
describe('toggleCollapsed', () => {
it('toggles issues', (done) => {
vm = mountComponent(ReportCollapsibleSection, {
vm = mountComponent(ReportSection, {
type: 'codequality',
status: 'success',
loadingText: 'Loading codeclimate report',
......@@ -88,7 +88,7 @@ describe('Report Collapsible section', () => {
describe('with failed request', () => {
it('should render error indicator', () => {
vm = mountComponent(ReportCollapsibleSection, {
vm = mountComponent(ReportSection, {
type: 'codequality',
status: 'error',
loadingText: 'Loading codeclimate report',
......@@ -101,7 +101,7 @@ describe('Report Collapsible section', () => {
describe('With full report', () => {
beforeEach(() => {
vm = mountComponent(ReportCollapsibleSection, {
vm = mountComponent(ReportSection, {
status: 'success',
successText: 'SAST improved on 1 security vulnerability and degraded on 1 security vulnerability',
type: 'security',
......@@ -172,4 +172,28 @@ describe('Report Collapsible section', () => {
});
});
});
describe('When it is not collapsible', () => {
beforeEach(() => {
vm = mountComponent(ReportSection, {
type: 'codequality',
status: 'success',
loadingText: 'Loading codeclimate report',
errorText: 'foo',
successText: 'Code quality improved on 1 point and degraded on 1 point',
resolvedIssues: codequalityParsedIssues,
isCollapsible: false,
});
});
it('should not render collapse button', () => {
expect(vm.$el.querySelector('.js-collapse-btn')).toBe(null);
});
it('should show the report by default', () => {
expect(
vm.$el.querySelectorAll('.report-block-list .report-block-list-item').length,
).toEqual(codequalityParsedIssues.length);
});
});
});
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