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

Allow to render the report without the collapse button

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