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,6 +124,7 @@ ...@@ -117,6 +124,7 @@
}; };
</script> </script>
<template> <template>
<div>
<ul class="report-block-list"> <ul class="report-block-list">
<li <li
class="report-block-list-issue" class="report-block-list-issue"
...@@ -128,8 +136,9 @@ ...@@ -128,8 +136,9 @@
:class="{ :class="{
failed: isStatusFailed, failed: isStatusFailed,
success: isStatusSuccess, success: isStatusSuccess,
neutral: isStatusNeutral neutral: isStatusNeutral,
}"> }"
>
<icon <icon
:name="iconName" :name="iconName"
:size="32" :size="32"
...@@ -156,7 +165,7 @@ ...@@ -156,7 +165,7 @@
type="button" type="button"
@click="openDastModal(issue, index)" @click="openDastModal(issue, index)"
data-toggle="modal" data-toggle="modal"
class="btn-link btn-blank btn-open-modal" class="js-modal-dast btn-link btn-blank btn-open-modal"
:data-target="modalTargetId" :data-target="modalTargetId"
> >
{{ issue.name }} {{ issue.name }}
...@@ -191,14 +200,66 @@ ...@@ -191,14 +200,66 @@
</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()" >
<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> </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