Add on-demands scans index page header

This leverages the ConfigurationPageLayout component to add a header to
the on-demand scans index page. The header contains a help text and a
link to the on-demands scans form.
To make room for the link, ConfigurationPageLayout has been extended
with a new actions slot.
parent dc21858e
<script>
import { GlTabs } from '@gitlab/ui';
import { GlButton, GlLink, GlSprintf, GlTabs } from '@gitlab/ui';
import { s__ } from '~/locale';
import ConfigurationPageLayout from 'ee/security_configuration/components/configuration_page_layout.vue';
import AllTab from './tabs/all.vue';
import RunningTab from './tabs/running.vue';
import FinishedTab from './tabs/finished.vue';
......@@ -24,13 +26,18 @@ const TABS = {
export default {
TABS,
components: {
GlButton,
GlLink,
GlSprintf,
GlTabs,
ConfigurationPageLayout,
AllTab,
RunningTab,
FinishedTab,
ScheduledTab,
EmptyState,
},
inject: ['newDastScanPath', 'helpPagePath'],
data() {
return {
activeTabIndex: 0,
......@@ -57,12 +64,41 @@ export default {
this.activeTabIndex = tabIndex;
}
},
i18n: {
title: s__('OnDemandScans|On-demand scans'),
newScanButtonLabel: s__('OnDemandScans|New DAST scan'),
description: s__(
'OnDemandScans|On-demand scans run outside of DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Lean more%{learnMoreLinkEnd}.',
),
},
};
</script>
<template>
<gl-tabs v-if="hasData" v-model="activeTab">
<component :is="tab.component" v-for="(tab, key) in $options.TABS" :key="key" :item-count="0" />
</gl-tabs>
<configuration-page-layout v-if="hasData">
<template #heading>
{{ $options.i18n.title }}
</template>
<template #actions>
<gl-button variant="confirm" :href="newDastScanPath" data-testid="new-scan-link">
{{ $options.i18n.newScanButtonLabel }}
</gl-button>
</template>
<template #description>
<gl-sprintf :message="$options.i18n.description">
<template #learnMoreLink="{ content }">
<gl-link :href="helpPagePath" data-testid="help-page-link">{{ content }}</gl-link>
</template>
</gl-sprintf>
</template>
<gl-tabs v-model="activeTab">
<component
:is="tab.component"
v-for="(tab, key) in $options.TABS"
:key="key"
:item-count="0"
/>
</gl-tabs>
</configuration-page-layout>
<empty-state v-else />
</template>
<template>
<article>
<slot name="alert"></slot>
<header class="gl-my-5 gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid">
<h4>
<slot name="heading"></slot>
</h4>
<p>
<slot name="description"></slot>
</p>
<header
class="gl-my-5 gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-display-flex gl-justify-content-space-between"
>
<div>
<h4 class="gl-mt-0">
<slot name="heading"></slot>
</h4>
<p>
<slot name="description"></slot>
</p>
</div>
<div>
<slot name="actions"></slot>
</div>
</header>
<slot></slot>
</article>
......
import { shallowMount } from '@vue/test-utils';
import { GlTabs } from '@gitlab/ui';
import { GlTabs, GlSprintf } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import OnDemandScans from 'ee/on_demand_scans/components/on_demand_scans.vue';
import ConfigurationPageLayout from 'ee/security_configuration/components/configuration_page_layout.vue';
import { createRouter } from 'ee/on_demand_scans/router';
import AllTab from 'ee/on_demand_scans/components/tabs/all.vue';
import RunningTab from 'ee/on_demand_scans/components/tabs/running.vue';
......@@ -12,7 +13,13 @@ describe('OnDemandScans', () => {
let wrapper;
let router;
// Props
const newDastScanPath = '/on_demand_scans/new';
const helpPagePath = '/help/page/path';
// Finders
const findNewScanLink = () => wrapper.findByTestId('new-scan-link');
const findHelpPageLink = () => wrapper.findByTestId('help-page-link');
const findTabs = () => wrapper.findComponent(GlTabs);
const findAllTab = () => wrapper.findComponent(AllTab);
const findRunningTab = () => wrapper.findComponent(RunningTab);
......@@ -21,8 +28,16 @@ describe('OnDemandScans', () => {
const findEmptyState = () => wrapper.findComponent(EmptyState);
const createComponent = () => {
wrapper = shallowMount(OnDemandScans, {
wrapper = shallowMountExtended(OnDemandScans, {
router,
provide: {
newDastScanPath,
helpPagePath,
},
stubs: {
ConfigurationPageLayout,
GlSprintf,
},
});
};
......@@ -46,6 +61,20 @@ describe('OnDemandScans', () => {
wrapper.setData({ hasData: true });
});
it('renders a link to the docs', () => {
const link = findHelpPageLink();
expect(link.exists()).toBe(true);
expect(link.attributes('href')).toBe(helpPagePath);
});
it('renders a link to create a new scan', () => {
const link = findNewScanLink();
expect(link.exists()).toBe(true);
expect(link.attributes('href')).toBe(newDastScanPath);
});
it('renders the tabs if there is data', async () => {
expect(findAllTab().exists()).toBe(true);
expect(findRunningTab().exists()).toBe(true);
......
......@@ -4,15 +4,23 @@ exports[`Security Configuration Page Layout component matches the snapshot 1`] =
<article>
Page alert
<header
class="gl-my-5 gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid"
class="gl-my-5 gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-display-flex gl-justify-content-space-between"
>
<h4>
Page title
</h4>
<div>
<h4
class="gl-mt-0"
>
Page title
</h4>
<p>
Scanner description
</p>
</div>
<p>
Scanner description
</p>
<div>
Action
</div>
</header>
<div>
......
......@@ -9,6 +9,7 @@ describe('Security Configuration Page Layout component', () => {
slots: {
alert: 'Page alert',
heading: 'Page title',
actions: 'Action',
description: 'Scanner description',
default: '<div>form</div>',
},
......
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