Commit b08d32d3 authored by Mark Florian's avatar Mark Florian

Merge branch '207322-easy-and-quick-way-to-turn-network-policies-on-off' into 'master'

Update header and table for security config page

See merge request gitlab-org/gitlab!31471
parents fd11fe1c e61e29a0
<script> <script>
import { GlLink } from '@gitlab/ui'; import { GlLink, GlSprintf, GlTable } from '@gitlab/ui';
import { s__, __, sprintf } from '~/locale'; import { s__, __, sprintf } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import AutoFixSettings from './auto_fix_settings.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import AutoFixSettings from './auto_fix_settings.vue';
export default { export default {
components: { components: {
GlLink, GlLink,
Icon, GlSprintf,
GlTable,
AutoFixSettings, AutoFixSettings,
}, },
mixins: [glFeatureFlagsMixin()], mixins: [glFeatureFlagsMixin()],
...@@ -41,33 +41,40 @@ export default { ...@@ -41,33 +41,40 @@ export default {
}, },
}, },
computed: { computed: {
headerContent() { devopsMessage() {
const body = __('Configure Security %{wordBreakOpportunity}and Compliance'); return this.autoDevopsEnabled
const wordBreakOpportunity = '<wbr />'; ? __(
'All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project',
return sprintf(body, { wordBreakOpportunity }, false); )
: __(
`The status of the table below only applies to the default branch and is based on the %{linkStart}latest pipeline%{linkEnd}. Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan.`,
);
}, },
callOutLink() { devopsUrl() {
return this.autoDevopsEnabled ? this.autoDevopsHelpPagePath : this.latestPipelinePath; return this.autoDevopsEnabled ? this.autoDevopsHelpPagePath : this.latestPipelinePath;
}, },
calloutContent() { fields() {
const bodyDefault = __(`The status of the table below only applies to the default branch and return [
is based on the %{linkStart}latest pipeline%{linkEnd}. {
Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan.`); key: 'feature',
label: s__('SecurityConfiguration|Security Control'),
const bodyAutoDevopsEnabled = __( thClass: 'gl-text-gray-900 bg-transparent border-bottom',
'All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project', },
); {
key: 'configured',
const body = this.autoDevopsEnabled ? bodyAutoDevopsEnabled : bodyDefault; label: s__('SecurityConfiguration|Status'),
thClass: 'gl-text-gray-900 bg-transparent border-bottom',
const linkStart = `<a href="${this.callOutLink}" target="_blank" rel="noopener">`; formatter: this.getStatusText,
const linkEnd = '</a>'; },
];
return sprintf(body, { linkStart, linkEnd }, false);
}, },
}, },
methods: { methods: {
getStatusText(value) {
return value
? s__('SecurityConfiguration|Enabled')
: s__('SecurityConfiguration|Not yet enabled');
},
getFeatureDocumentationLinkLabel(featureName) { getFeatureDocumentationLinkLabel(featureName) {
return sprintf(s__('SecurityConfiguration|Feature documentation for %{featureName}'), { return sprintf(s__('SecurityConfiguration|Feature documentation for %{featureName}'), {
featureName, featureName,
...@@ -80,73 +87,32 @@ export default { ...@@ -80,73 +87,32 @@ export default {
<template> <template>
<article> <article>
<header> <header>
<h2 class="h4 my-3"> <h4 class="my-3">{{ __('Security Configuration') }}</h4>
<span v-html="headerContent"></span> <h5 class="gl-font-lg mt-5">{{ s__('SecurityConfiguration|Testing & Compliance') }}</h5>
<gl-link <p>
target="_blank" <gl-sprintf :message="devopsMessage">
:href="helpPagePath" <template #link="{ content }">
:aria-label="__('Security configuration help link')" <gl-link ref="pipelinesLink" :href="devopsUrl" target="_blank">{{ content }}</gl-link>
> </template>
<icon name="question" /> </gl-sprintf>
</gl-link> </p>
</h2>
</header> </header>
<section
ref="callout" <gl-table ref="securityControlTable" :items="features" :fields="fields" stacked="md">
class="bs-callout bs-callout-info mb-3 m-md-1 text-secondary" <template #cell(feature)="{ item }">
v-html="calloutContent" <div class="gl-text-gray-900">{{ item.name }}</div>
></section> <div>
<section ref="featuresTable" class="mt-0"> {{ item.description }}
<div <gl-link
class="gl-responsive-table-row table-row-header text-2 font-weight-bold px-2 gl-text-gray-900" target="_blank"
role="row" :href="item.link"
> :aria-label="getFeatureDocumentationLinkLabel(item.name)"
<div class="table-section section-80"> >
{{ s__('SecurityConfiguration|Secure features') }} {{ __('More information') }}
</div> </gl-link>
<div class="table-section section-20">{{ s__('SecurityConfiguration|Status') }}</div>
</div>
<div
v-for="feature in features"
ref="featureRow"
:key="feature.name"
class="gl-responsive-table-row flex-md-column align-items-md-stretch px-2"
>
<div class="d-md-flex align-items-center">
<div class="table-section section-80 section-wrap pr-md-3">
<div role="rowheader" class="table-mobile-header">
{{ s__('SecurityConfiguration|Feature') }}
</div>
<div class="table-mobile-content">
<div class="d-flex align-items-center justify-content-end justify-content-md-start">
<div class="text-2 gl-text-gray-900">{{ feature.name }}</div>
</div>
<div class="text-secondary">
{{ feature.description }}
<gl-link
target="_blank"
:href="feature.link"
:aria-label="getFeatureDocumentationLinkLabel(feature.name)"
>{{ __('More information') }}</gl-link
>
</div>
</div>
</div>
<div class="table-section section-20 section-wrap pr-md-3">
<div role="rowheader" class="table-mobile-header">
{{ s__('SecurityConfiguration|Status') }}
</div>
<div ref="featureConfigStatus" class="table-mobile-content">
{{
feature.configured
? s__('SecurityConfiguration|Enabled')
: s__('SecurityConfiguration|Not yet enabled')
}}
</div>
</div>
</div> </div>
</div> </template>
</section> </gl-table>
<auto-fix-settings v-if="glFeatures.securityAutoFix" v-bind="autoFixSettingsProps" /> <auto-fix-settings v-if="glFeatures.securityAutoFix" v-bind="autoFixSettingsProps" />
</article> </article>
</template> </template>
---
title: Update header for security config page and change to GlTable
merge_request: 31471
author:
type: changed
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Security Configuration App features table displays a given feature 1`] = `
<section
class="mt-0"
>
<div
class="gl-responsive-table-row table-row-header text-2 font-weight-bold px-2 gl-text-gray-900"
role="row"
>
<div
class="table-section section-80"
>
Secure features
</div>
<div
class="table-section section-20"
>
Status
</div>
</div>
<div
class="gl-responsive-table-row flex-md-column align-items-md-stretch px-2"
>
<div
class="d-md-flex align-items-center"
>
<div
class="table-section section-80 section-wrap pr-md-3"
>
<div
class="table-mobile-header"
role="rowheader"
>
Feature
</div>
<div
class="table-mobile-content"
>
<div
class="d-flex align-items-center justify-content-end justify-content-md-start"
>
<div
class="text-2 gl-text-gray-900"
>
name-feature-0
</div>
</div>
<div
class="text-secondary"
>
description-feature-0
<gl-link-stub
aria-label="Feature documentation for name-feature-0"
href="link-feature-0"
target="_blank"
>
More information
</gl-link-stub>
</div>
</div>
</div>
<div
class="table-section section-20 section-wrap pr-md-3"
>
<div
class="table-mobile-header"
role="rowheader"
>
Status
</div>
<div
class="table-mobile-content"
>
Not yet enabled
</div>
</div>
</div>
</div>
</section>
`;
import { shallowMount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui'; import { GlLink } from '@gitlab/ui';
import SecurityConfigurationApp from 'ee/security_configuration/components/app.vue'; import SecurityConfigurationApp from 'ee/security_configuration/components/app.vue';
import stubChildren from 'helpers/stub_children';
describe('Security Configuration App', () => { describe('Security Configuration App', () => {
let wrapper; let wrapper;
const createComponent = (props = {}) => { const createComponent = (props = {}) => {
wrapper = shallowMount(SecurityConfigurationApp, { wrapper = mount(SecurityConfigurationApp, {
stubs: {
...stubChildren(SecurityConfigurationApp),
GlTable: false,
GlSprintf: false,
},
propsData: { propsData: {
features: [], features: [],
autoDevopsEnabled: false, autoDevopsEnabled: false,
...@@ -23,28 +28,19 @@ describe('Security Configuration App', () => { ...@@ -23,28 +28,19 @@ describe('Security Configuration App', () => {
wrapper.destroy(); wrapper.destroy();
}); });
const generateFeatures = n => const generateFeatures = n => {
[...Array(n).keys()].map(i => ({ return [...Array(n).keys()].map(i => ({
name: `name-feature-${i}`, name: `name-feature-${i}`,
description: `description-feature-${i}`, description: `description-feature-${i}`,
link: `link-feature-${i}`, link: `link-feature-${i}`,
configured: i % 2 === 0,
})); }));
};
const getHelpLink = () => wrapper.find('header').find(GlLink); const getPipelinesLink = () => wrapper.find({ ref: 'pipelinesLink' });
const getNotification = () => wrapper.find({ ref: 'callout' }); const getFeaturesTable = () => wrapper.find({ ref: 'securityControlTable' });
const getPipelinesLink = () => getNotification().find('a');
const getFeaturesTable = () => wrapper.find({ ref: 'featuresTable' });
const getFeatureConfigStatus = () => wrapper.find({ ref: 'featureConfigStatus' });
describe('header', () => { describe('header', () => {
it('displays a link to the given help page', () => {
const helpPagePath = 'http://foo';
createComponent({ helpPagePath });
expect(getHelpLink().attributes('href')).toBe(helpPagePath);
});
it.each` it.each`
autoDevopsEnabled | expectedUrl autoDevopsEnabled | expectedUrl
${true} | ${'http://autoDevopsHelpPagePath'} ${true} | ${'http://autoDevopsHelpPagePath'}
...@@ -55,41 +51,28 @@ describe('Security Configuration App', () => { ...@@ -55,41 +51,28 @@ describe('Security Configuration App', () => {
createComponent({ autoDevopsEnabled }); createComponent({ autoDevopsEnabled });
expect(getPipelinesLink().attributes('href')).toBe(expectedUrl); expect(getPipelinesLink().attributes('href')).toBe(expectedUrl);
expect(getPipelinesLink().attributes('rel')).toBe('noopener'); expect(getPipelinesLink().attributes('target')).toBe('_blank');
}, },
); );
}); });
describe('features table', () => { describe('features table', () => {
it('displays a row for each given feature', () => { it('passes the expected data to the GlTable', () => {
const features = generateFeatures(5); const features = generateFeatures(5);
createComponent({ features }); createComponent({ features });
expect(wrapper.findAll({ ref: 'featureRow' })).toHaveLength(5); expect(getFeaturesTable().classes('b-table-stacked-md')).toBeTruthy();
const rows = getFeaturesTable().findAll('tbody tr');
expect(rows).toHaveLength(5);
for (let i = 0; i < features.length; i += 1) {
const [feature, status] = rows.at(i).findAll('td').wrappers;
expect(feature.text()).toMatch(features[i].name);
expect(feature.text()).toMatch(features[i].description);
expect(feature.find(GlLink).attributes('href')).toBe(features[i].link);
expect(status.text()).toMatch(features[i].configured ? 'Enabled' : 'Not yet enabled');
}
}); });
it('displays a given feature', () => {
const features = generateFeatures(1);
createComponent({ features });
expect(getFeaturesTable().element).toMatchSnapshot();
});
it.each`
configured | statusText
${true} | ${'Enabled'}
${false} | ${'Not yet enabled'}
`(
`displays "$statusText" if the given feature's configuration status is: "$configured"`,
({ configured, statusText }) => {
const features = [{ configured }];
createComponent({ features });
expect(getFeatureConfigStatus().text()).toBe(statusText);
},
);
}); });
}); });
...@@ -5699,9 +5699,6 @@ msgstr "" ...@@ -5699,9 +5699,6 @@ msgstr ""
msgid "Configure Prometheus" msgid "Configure Prometheus"
msgstr "" msgstr ""
msgid "Configure Security %{wordBreakOpportunity}and Compliance"
msgstr ""
msgid "Configure Tracing" msgid "Configure Tracing"
msgstr "" msgstr ""
...@@ -18991,9 +18988,6 @@ msgstr "" ...@@ -18991,9 +18988,6 @@ msgstr ""
msgid "Security Dashboard" msgid "Security Dashboard"
msgstr "" msgstr ""
msgid "Security configuration help link"
msgstr ""
msgid "Security dashboard" msgid "Security dashboard"
msgstr "" msgstr ""
...@@ -19006,21 +19000,21 @@ msgstr "" ...@@ -19006,21 +19000,21 @@ msgstr ""
msgid "SecurityConfiguration|Enabled" msgid "SecurityConfiguration|Enabled"
msgstr "" msgstr ""
msgid "SecurityConfiguration|Feature"
msgstr ""
msgid "SecurityConfiguration|Feature documentation for %{featureName}" msgid "SecurityConfiguration|Feature documentation for %{featureName}"
msgstr "" msgstr ""
msgid "SecurityConfiguration|Not yet enabled" msgid "SecurityConfiguration|Not yet enabled"
msgstr "" msgstr ""
msgid "SecurityConfiguration|Secure features" msgid "SecurityConfiguration|Security Control"
msgstr "" msgstr ""
msgid "SecurityConfiguration|Status" msgid "SecurityConfiguration|Status"
msgstr "" msgstr ""
msgid "SecurityConfiguration|Testing & Compliance"
msgstr ""
msgid "SecurityReports|%{firstProject} and %{secondProject}" msgid "SecurityReports|%{firstProject} and %{secondProject}"
msgstr "" msgstr ""
......
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