Commit 1b97ff5b authored by Filipa Lacerda's avatar Filipa Lacerda

Improve CSS in modal for dast

Reuse modal.vue and delete old modal

Adds changelog entry

Update report_issues_spec.js

Fix broken test
parent 163b2b00
<script>
import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import ExpandButton from '~/vue_shared/components/expand_button.vue';
export default {
name: 'ModalDast',
components: {
ExpandButton,
Icon,
},
props: {
title: {
type: String,
required: true,
default: '',
},
targetId: {
type: String,
required: false,
default: '',
},
description: {
type: String,
required: true,
default: '',
},
instances: {
type: Array,
required: false,
default: () => ([]),
},
},
computed: {
instancesLabel() {
return s__('ciReport|Instances');
},
},
mounted() {
$(this.$el).on('hidden.bs.modal', () => {
this.$emit('clearData');
});
},
};
</script>
<template>
<div
:id="targetId"
class="modal fade"
tabindex="-1"
role="dialog"
>
<div
class="modal-dialog modal-lg"
role="document"
>
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">
{{ title }}
</h4>
</div>
<div class="modal-body">
{{ description }}
<h5 class="prepend-top-20">{{ instancesLabel }}</h5>
<ul
v-if="instances"
class="report-block-list"
>
<li
v-for="(instance, i) in instances"
:key="i"
class="report-block-list-item-modal failed"
>
<icon
class="report-block-icon"
name="status_failed_borderless"
:size="32"
/>
{{ instance.method }}
<a
:href="instance.uri"
target="_blank"
rel="noopener noreferrer nofollow"
class="prepend-left-5"
>
{{ instance.uri }}
</a>
<expand-button v-if="instance.evidence">
<pre
slot="expanded"
class="block report-block-dast-code prepend-top-10">{{ instance.evidence }}</pre>
</expand-button>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import Modal from './dast_modal.vue'; import Modal from '~/vue_shared/components/gl_modal.vue';
import ExpandButton from '~/vue_shared/components/expand_button.vue';
const modalDefaultData = { const modalDefaultData = {
modalId: 'modal-mrwidget-issue', modalId: 'modal-mrwidget-issue',
...@@ -16,6 +17,7 @@ ...@@ -16,6 +17,7 @@
components: { components: {
Modal, Modal,
Icon, Icon,
ExpandButton,
}, },
props: { props: {
issues: { issues: {
...@@ -79,6 +81,11 @@ ...@@ -79,6 +81,11 @@
return this.type === 'dast'; return this.type === 'dast';
}, },
}, },
mounted() {
$(this.$refs.modal).on('hidden.bs.modal', () => {
this.clearModalData();
});
},
methods: { methods: {
shouldRenderPriority(issue) { shouldRenderPriority(issue) {
return this.hasPriority && issue.priority; return this.hasPriority && issue.priority;
...@@ -117,88 +124,142 @@ ...@@ -117,88 +124,142 @@
}; };
</script> </script>
<template> <template>
<ul class="report-block-list"> <div>
<li <ul class="report-block-list">
class="report-block-list-issue" <li
v-for="(issue, index) in issues" class="report-block-list-issue"
:key="index" v-for="(issue, index) in issues"
> :key="index"
<div >
class="report-block-list-icon append-right-5" <div
:class="{ class="report-block-list-icon append-right-5"
failed: isStatusFailed, :class="{
success: isStatusSuccess, failed: isStatusFailed,
neutral: isStatusNeutral success: isStatusSuccess,
}"> neutral: isStatusNeutral,
<icon }"
:name="iconName" >
:size="32" <icon
/> :name="iconName"
</div> :size="32"
<div class="report-block-list-issue-description"> />
<div class="report-block-list-issue-description-text append-right-5"> </div>
<template v-if="isStatusSuccess && isTypeQuality">{{ fixedLabel }}</template> <div class="report-block-list-issue-description">
<template v-if="shouldRenderPriority(issue)">{{ issue.priority }}:</template> <div class="report-block-list-issue-description-text append-right-5">
<template v-if="isStatusSuccess && isTypeQuality">{{ fixedLabel }}</template>
<template v-if="shouldRenderPriority(issue)">{{ issue.priority }}:</template>
<template v-if="isTypeDocker"> <template v-if="isTypeDocker">
<a <a
v-if="issue.nameLink" v-if="issue.nameLink"
:href="issue.nameLink" :href="issue.nameLink"
target="_blank" target="_blank"
rel="noopener noreferrer nofollow" rel="noopener noreferrer nofollow"
>{{ issue.name }}</a> >{{ issue.name }}</a>
<template v-else>
{{ issue.name }}
</template>
</template>
<template v-else-if="isTypeDast">
<button
type="button"
@click="openDastModal(issue, index)"
data-toggle="modal"
class="js-modal-dast btn-link btn-blank btn-open-modal"
:data-target="modalTargetId"
>
{{ issue.name }}
</button>
</template>
<template v-else> <template v-else>
{{ issue.name }} {{ issue.name }}<template v-if="issue.score">:
<strong>{{ formatScore(issue.score) }}</strong></template>
</template> </template>
</template>
<template v-else-if="isTypeDast">
<button
type="button"
@click="openDastModal(issue, index)"
data-toggle="modal"
class="btn-link btn-blank btn-open-modal"
:data-target="modalTargetId"
>
{{ issue.name }}
</button>
</template>
<template v-else>
{{ issue.name }}<template v-if="issue.score">:
<strong>{{ formatScore(issue.score) }}</strong></template>
</template>
<template v-if="isTypePerformance && issue.delta != null"> <template v-if="isTypePerformance && issue.delta != null">
({{ issue.delta >= 0 ? '+' : '' }}{{ formatScore(issue.delta) }}) ({{ issue.delta >= 0 ? '+' : '' }}{{ formatScore(issue.delta) }})
</template> </template>
</div> </div>
<div class="report-block-list-issue-description-link"> <div class="report-block-list-issue-description-link">
<template v-if="issue.path"> <template v-if="issue.path">
in in
<a <a
v-if="issue.urlPath" v-if="issue.urlPath"
:href="issue.urlPath" :href="issue.urlPath"
target="_blank" target="_blank"
rel="noopener noreferrer nofollow" rel="noopener noreferrer nofollow"
class="break-link" class="break-link"
> >
{{ issue.path }}<template v-if="issue.line">:{{ issue.line }}</template> {{ issue.path }}<template v-if="issue.line">:{{ issue.line }}</template>
</a> </a>
<template v-else> <template v-else>
{{ issue.path }}<template v-if="issue.line">:{{ issue.line }}</template> {{ issue.path }}<template v-if="issue.line">:{{ issue.line }}</template>
</template>
</template> </template>
</template> </div>
</div> </div>
</div> </li>
</li> </ul>
<modal <modal
:target-id="modalId" v-if="isTypeDast"
:title="modalTitle" :id="modalId"
:hide-footer="true" :header-title-text="modalTitle"
:description="modalDesc" ref="modal"
:instances="modalInstances" class="modal-security-report-dast"
@clearData="clearModalData()" >
/>
</ul> <slot class="modal-lg">
{{ modalDesc }}
<h5 class="prepend-top-20">
{{ s__('ciReport|Instances') }}
</h5>
<ul
v-if="modalInstances"
class="report-block-list"
>
<li
v-for="(instance, i) in modalInstances"
:key="i"
class="report-block-list-issue"
>
<div class="report-block-list-icon append-right-5 failed">
<icon
name="status_failed_borderless"
:size="32"
/>
</div>
<div class="report-block-list-issue-description">
<div class="report-block-list-issue-description-text append-right-5">
{{ instance.method }}
</div>
<div class="report-block-list-issue-description-link">
<a
:href="instance.uri"
target="_blank"
rel="noopener noreferrer nofollow"
class="prepend-left-5"
>
{{ instance.uri }}
</a>
</div>
<div>
<expand-button v-if="instance.evidence">
<pre
slot="expanded"
class="block report-block-dast-code prepend-top-10"
>{{ instance.evidence }}</pre>
</expand-button>
</div>
</div>
</li>
</ul>
</slot>
<div slot="footer">
</div>
</modal>
</div>
</template> </template>
...@@ -64,3 +64,17 @@ ...@@ -64,3 +64,17 @@
text-align: left; text-align: left;
} }
} }
.report-block-issue-code {
width: 100%;
}
.modal-security-report-dast {
.modal-dialog {
width: $modal-lg;
}
// TODO remove this when gl_modal support not rendering the footer
.moda-footer {
display: none;
}
}
---
title: Improve security reports to handle big links and to work on mobile devices
merge_request: 4671
author:
type: fixed
import Vue from 'vue';
import modal from 'ee/vue_shared/security_reports/components/dast_modal.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('mr widget modal', () => {
let vm;
let Modal;
beforeEach(() => {
Modal = Vue.extend(modal);
vm = mountComponent(Modal, {
title: 'Title',
targetId: 'targetId',
instances: [{
uri: 'uri',
method: 'GET',
evidence: 'evidence',
}],
description: 'Description!',
});
});
afterEach(() => {
vm.$destroy();
});
it('renders a title', () => {
expect(vm.$el.querySelector('.modal-title').textContent.trim()).toEqual('Title');
});
it('renders the target id', () => {
expect(vm.$el.getAttribute('id')).toEqual('targetId');
});
it('renders the description', () => {
expect(vm.$el.querySelector('.modal-body').textContent).toContain('Description!');
});
it('renders list of instances', () => {
const instance = vm.$el.querySelector('.modal-body li').textContent;
expect(instance).toContain('uri');
expect(instance).toContain('GET');
expect(instance).toContain('evidence');
});
});
...@@ -159,5 +159,20 @@ describe('Report issues', () => { ...@@ -159,5 +159,20 @@ describe('Report issues', () => {
expect(vm.$el.textContent).toContain(parsedDast[0].name); expect(vm.$el.textContent).toContain(parsedDast[0].name);
expect(vm.$el.textContent).toContain(parsedDast[0].priority); expect(vm.$el.textContent).toContain(parsedDast[0].priority);
}); });
it('opens modal with more information and list of instances', (done) => {
vm.$el.querySelector('.js-modal-dast ').click();
Vue.nextTick(() => {
expect(vm.$el.querySelector('.modal-title').textContent.trim()).toEqual('Low (Medium): Absence of Anti-CSRF Tokens');
expect(vm.$el.querySelector('.modal-body').textContent).toContain('No Anti-CSRF tokens were found in a HTML submission form.');
const instance = vm.$el.querySelector('.modal-body li').textContent;
expect(instance).toContain('http://192.168.32.236:3001/explore?sort=latest_activity_desc');
expect(instance).toContain('GET');
done();
});
});
}); });
}); });
...@@ -192,7 +192,7 @@ describe('Report section', () => { ...@@ -192,7 +192,7 @@ describe('Report section', () => {
it('should show the report by default', () => { it('should show the report by default', () => {
expect( expect(
vm.$el.querySelectorAll('.report-block-list .report-block-list-item').length, vm.$el.querySelectorAll('.report-block-list .report-block-list-issue').length,
).toEqual(codequalityParsedIssues.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