Commit 4cb0e362 authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '230574-make-alert-payload-clickable' into 'master'

Make Alert details table attributes clickable

See merge request gitlab-org/gitlab!63593
parents 47e78292 976d9cf0
<script> <script>
import { GlLoadingIcon, GlTable } from '@gitlab/ui'; import { GlLink, GlLoadingIcon, GlTable } from '@gitlab/ui';
import { reduce } from 'lodash'; import { reduce } from 'lodash';
import { import {
capitalizeFirstCharacter, capitalizeFirstCharacter,
convertToSentenceCase, convertToSentenceCase,
splitCamelCase, splitCamelCase,
} from '~/lib/utils/text_utility'; } from '~/lib/utils/text_utility';
import { isSafeURL } from '~/lib/utils/url_utility';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { PAGE_CONFIG } from '~/vue_shared/alert_details/constants'; import { PAGE_CONFIG } from '~/vue_shared/alert_details/constants';
...@@ -30,6 +31,7 @@ const allowedFields = [ ...@@ -30,6 +31,7 @@ const allowedFields = [
export default { export default {
components: { components: {
GlLink,
GlLoadingIcon, GlLoadingIcon,
GlTable, GlTable,
}, },
...@@ -94,6 +96,9 @@ export default { ...@@ -94,6 +96,9 @@ export default {
isAllowed(fieldName) { isAllowed(fieldName) {
return allowedFields.includes(fieldName); return allowedFields.includes(fieldName);
}, },
isValidLink(value) {
return typeof value === 'string' && isSafeURL(value);
},
}, },
}; };
</script> </script>
...@@ -109,5 +114,11 @@ export default { ...@@ -109,5 +114,11 @@ export default {
<template #table-busy> <template #table-busy>
<gl-loading-icon size="lg" color="dark" class="gl-mt-5" /> <gl-loading-icon size="lg" color="dark" class="gl-mt-5" />
</template> </template>
<template #cell(value)="{ item: { value } }">
<span v-if="!isValidLink(value)">{{ value }}</span>
<gl-link v-else :href="value" target="_blank">
{{ value }}
</gl-link>
</template>
</gl-table> </gl-table>
</template> </template>
import { GlLoadingIcon, GlTable } from '@gitlab/ui'; import { GlLink, GlLoadingIcon, GlTable } from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue'; import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
...@@ -7,6 +7,9 @@ const mockAlert = { ...@@ -7,6 +7,9 @@ const mockAlert = {
title: 'SyntaxError: Invalid or unexpected token', title: 'SyntaxError: Invalid or unexpected token',
severity: 'CRITICAL', severity: 'CRITICAL',
eventCount: 7, eventCount: 7,
service: 'https://gitlab.com',
// eslint-disable-next-line no-script-url
description: 'javascript:alert("XSS")',
createdAt: '2020-04-17T23:18:14.996Z', createdAt: '2020-04-17T23:18:14.996Z',
startedAt: '2020-04-17T23:18:14.996Z', startedAt: '2020-04-17T23:18:14.996Z',
endedAt: '2020-04-17T23:18:14.996Z', endedAt: '2020-04-17T23:18:14.996Z',
...@@ -43,7 +46,7 @@ describe('AlertDetails', () => { ...@@ -43,7 +46,7 @@ describe('AlertDetails', () => {
wrapper = null; wrapper = null;
}); });
const findTableComponent = () => wrapper.find(GlTable); const findTableComponent = () => wrapper.findComponent(GlTable);
const findTableKeys = () => findTableComponent().findAll('tbody td:first-child'); const findTableKeys = () => findTableComponent().findAll('tbody td:first-child');
const findTableFieldValueByKey = (fieldKey) => const findTableFieldValueByKey = (fieldKey) =>
findTableComponent() findTableComponent()
...@@ -52,6 +55,7 @@ describe('AlertDetails', () => { ...@@ -52,6 +55,7 @@ describe('AlertDetails', () => {
.at(0) .at(0)
.find('td:nth-child(2)'); .find('td:nth-child(2)');
const findTableField = (fields, fieldName) => fields.filter((row) => row.text() === fieldName); const findTableField = (fields, fieldName) => fields.filter((row) => row.text() === fieldName);
const findTableLinks = () => wrapper.findAllComponents(GlLink);
describe('Alert details', () => { describe('Alert details', () => {
describe('empty state', () => { describe('empty state', () => {
...@@ -88,7 +92,16 @@ describe('AlertDetails', () => { ...@@ -88,7 +92,16 @@ describe('AlertDetails', () => {
it('should show allowed alert fields', () => { it('should show allowed alert fields', () => {
const fields = findTableKeys(); const fields = findTableKeys();
['Iid', 'Title', 'Severity', 'Status', 'Hosts', 'Environment'].forEach((field) => { [
'Iid',
'Title',
'Severity',
'Status',
'Hosts',
'Environment',
'Service',
'Description',
].forEach((field) => {
expect(findTableField(fields, field).exists()).toBe(true); expect(findTableField(fields, field).exists()).toBe(true);
}); });
}); });
...@@ -99,6 +112,12 @@ describe('AlertDetails', () => { ...@@ -99,6 +112,12 @@ describe('AlertDetails', () => {
expect(findTableField(fields, field).exists()).toBe(false); expect(findTableField(fields, field).exists()).toBe(false);
}); });
}); });
it('should render a clickable URL if safe', () => {
expect(findTableLinks().wrappers).toHaveLength(1);
expect(findTableLinks().at(0).props('isUnsafeLink')).toBe(false);
expect(findTableLinks().at(0).attributes('href')).toBe(mockAlert.service);
});
}); });
describe('environment', () => { describe('environment', () => {
......
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