Commit b74d155c authored by Peter Hegman's avatar Peter Hegman

Merge branch '341356-dast-view-scans-index-page' into 'master'

Create on-demand scans index page

See merge request gitlab-org/gitlab!71725
parents 02d813df 6706185b
<script>
import { GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui';
import { s__ } from '~/locale';
export default {
components: {
GlEmptyState,
GlSprintf,
GlLink,
},
inject: ['newDastScanPath', 'helpPagePath', 'emptyStateSvgPath'],
i18n: {
title: s__('OnDemandScans|On-demand scans'),
primaryButtonText: s__('OnDemandScans|New DAST scan'),
text: s__(
'OnDemandScans|On-demand scans run outside of DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Lean more%{learnMoreLinkEnd}.',
),
},
};
</script>
<template>
<gl-empty-state
:title="$options.i18n.title"
:svg-path="emptyStateSvgPath"
:primary-button-text="$options.i18n.primaryButtonText"
:primary-button-link="newDastScanPath"
>
<template #description>
<gl-sprintf :message="$options.i18n.text">
<template #learnMoreLink="{ content }">
<gl-link :href="helpPagePath">{{ content }}</gl-link>
</template>
</gl-sprintf>
</template>
</gl-empty-state>
</template>
<script>
import EmptyState from './empty_state.vue';
export default {
components: {
EmptyState,
},
};
</script>
<template>
<empty-state />
</template>
import Vue from 'vue';
import OnDemandScans from './components/on_demand_scans.vue';
export default () => {
const el = document.querySelector('#js-on-demand-scans');
if (!el) {
return null;
}
const { newDastScanPath, helpPagePath, emptyStateSvgPath } = el.dataset;
return new Vue({
el,
provide: {
newDastScanPath,
helpPagePath,
emptyStateSvgPath,
},
render(h) {
return h(OnDemandScans);
},
});
};
import initOnDemanScansForm from 'ee/on_demand_scans_form';
import initOnDemanScans from 'ee/on_demand_scans/on_demand_scans_bundle';
initOnDemanScansForm();
initOnDemanScans();
......@@ -15,6 +15,7 @@ module Projects
feature_category :dynamic_application_security_testing
def index
redirect_to new_project_on_demand_scan_path(project) unless Feature.enabled?(:dast_view_scans, @project, default_enabled: :yaml)
end
def new
......
# frozen_string_literal: true
module Projects::OnDemandScansHelper
def on_demand_scans_data(project)
base_data.merge({
'new-dast-scan-path' => new_project_on_demand_scan_path(project),
'empty-state-svg-path' => image_path('illustrations/empty-state/ondemand-scan-empty.svg')
})
end
def on_demand_scans_form_data(project)
{
'help-page-path' => help_page_path('user/application_security/dast/index', anchor: 'on-demand-scans'),
'empty-state-svg-path' => image_path('illustrations/empty-state/ondemand-scan-empty.svg'),
base_data.merge({
'default-branch' => project.default_branch,
'project-path' => project.path_with_namespace,
'profiles-library-path' => project_security_configuration_dast_scans_path(project),
......@@ -13,6 +18,14 @@ module Projects::OnDemandScansHelper
'new-scanner-profile-path' => new_project_security_configuration_dast_scans_dast_scanner_profile_path(project),
'new-site-profile-path' => new_project_security_configuration_dast_scans_dast_site_profile_path(project),
'timezones' => timezone_data(format: :full).to_json
})
end
private
def base_data
{
'help-page-path' => help_page_path('user/application_security/dast/index', anchor: 'on-demand-scans')
}
end
end
- breadcrumb_title s_('OnDemandScans|On-demand Scans')
- page_title s_('OnDemandScans|On-demand Scans')
#js-on-demand-scans-form{ data: on_demand_scans_form_data(@project) }
#js-on-demand-scans{ data: on_demand_scans_data(@project) }
......@@ -91,9 +91,15 @@ module EE
return ::Sidebars::NilMenuItem.new(item_id: :on_demand_scans)
end
link = if ::Feature.enabled?(:dast_view_scans, context.project, default_enabled: :yaml)
project_on_demand_scans_path(context.project)
else
new_project_on_demand_scan_path(context.project)
end
::Sidebars::MenuItem.new(
title: s_('OnDemandScans|On-demand Scans'),
link: new_project_on_demand_scan_path(context.project),
link: link,
item_id: :on_demand_scans,
active_routes: { path: %w[
projects/on_demand_scans#index
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EmptyState renders properly 1`] = `
<section
class="row empty-state text-center"
>
<div
class="col-12"
>
<div
class="svg-250 svg-content"
>
<img
alt=""
class="gl-max-w-full"
role="img"
src="/empty/state/svg/path"
/>
</div>
</div>
<div
class="col-12"
>
<div
class="text-content gl-mx-auto gl-my-0 gl-p-5"
>
<h1
class="h4"
>
On-demand scans
</h1>
<p>
On-demand scans run outside of DevOps cycle and find vulnerabilities in your projects.
<a
class="gl-link"
href="/help/page/path"
>
Lean more
</a>
.
</p>
<div
class="gl-display-flex gl-flex-wrap gl-justify-content-center"
>
<a
class="btn gl-mb-3 btn-confirm btn-md gl-button gl-mx-2"
href="/on_demand_scans/new"
>
<!---->
<!---->
<span
class="gl-button-text"
>
New DAST scan
</span>
</a>
<!---->
</div>
</div>
</div>
</section>
`;
import { mount } from '@vue/test-utils';
import EmptyState from 'ee/on_demand_scans/components/empty_state.vue';
describe('EmptyState', () => {
let wrapper;
const createComponent = () => {
wrapper = mount(EmptyState, {
provide: {
newDastScanPath: '/on_demand_scans/new',
helpPagePath: '/help/page/path',
emptyStateSvgPath: '/empty/state/svg/path',
},
});
};
afterEach(() => {
wrapper.destroy();
});
it('renders properly', () => {
createComponent();
expect(wrapper.element).toMatchSnapshot();
});
});
import { shallowMount } from '@vue/test-utils';
import OnDemandScans from 'ee/on_demand_scans/components/on_demand_scans.vue';
import EmptyState from 'ee/on_demand_scans/components/empty_state.vue';
describe('OnDemandScans', () => {
let wrapper;
// Finders
const findEmptyState = () => wrapper.findComponent(EmptyState);
const createComponent = () => {
wrapper = shallowMount(OnDemandScans);
};
afterEach(() => {
wrapper.destroy();
});
it('renders an empty state', () => {
createComponent();
expect(findEmptyState().exists()).toBe(true);
});
});
......@@ -3,8 +3,19 @@
require 'spec_helper'
RSpec.describe Projects::OnDemandScansHelper do
describe '#on_demand_scans_form_data' do
let_it_be(:project) { create(:project) }
describe '#on_demand_scans_data' do
it 'returns proper data' do
expect(helper.on_demand_scans_data(project)).to match(
'new-dast-scan-path' => "/#{project.full_path}/-/on_demand_scans/new",
'help-page-path' => "/help/user/application_security/dast/index#on-demand-scans",
'empty-state-svg-path' => match_asset_path('/assets/illustrations/empty-state/ondemand-scan-empty.svg')
)
end
end
describe '#on_demand_scans_form_data' do
let_it_be(:timezones) { [{ identifier: "Europe/Paris" }] }
before do
......@@ -16,7 +27,6 @@ RSpec.describe Projects::OnDemandScansHelper do
it 'returns proper data' do
expect(helper.on_demand_scans_form_data(project)).to match(
'help-page-path' => "/help/user/application_security/dast/index#on-demand-scans",
'empty-state-svg-path' => match_asset_path('/assets/illustrations/empty-state/ondemand-scan-empty.svg'),
'default-branch' => "default-branch",
'project-path' => "foo/bar",
'profiles-library-path' => "/#{project.full_path}/-/security/configuration/dast_scans",
......
......@@ -73,6 +73,20 @@ RSpec.describe Projects::OnDemandScansController, type: :request do
it_behaves_like 'on-demand scans page' do
let(:path) { project_on_demand_scans_path(project) }
end
context 'when dast_view_scans feature flag is disabled' do
before do
stub_licensed_features(security_on_demand_scans: true)
stub_feature_flags(dast_view_scans: false)
project.add_developer(user)
login_as(user)
get project_on_demand_scans_path(project)
end
it 'redirects to new on-demands scans form' do
expect(response).to redirect_to(new_project_on_demand_scan_path(project))
end
end
end
describe 'GET #new' do
......
......@@ -188,7 +188,7 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
it 'security on demand scans link is visible' do
expect(rendered).to have_link('On-demand Scans', href: new_project_on_demand_scan_path(project))
expect(rendered).to have_link('On-demand Scans', href: project_on_demand_scans_path(project))
end
it 'dependency list link is visible' do
......@@ -215,6 +215,22 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
expect(rendered).to have_link('Audit Events', href: project_audit_events_path(project))
end
end
context 'when dast_view_scans feature flag is disabled' do
before do
allow(view).to receive(:current_user).and_return(user)
stub_feature_flags(dast_view_scans: false)
stub_licensed_features(
security_on_demand_scans: true
)
render
end
it 'links to on-demand scans form instead of index page' do
expect(rendered).to have_link('On-demand Scans', href: new_project_on_demand_scan_path(project))
end
end
end
describe 'Operations' do
......
......@@ -9,7 +9,7 @@ RSpec.describe "projects/on_demand_scans/index", type: :view do
end
it 'renders Vue app root' do
expect(rendered).to have_selector('#js-on-demand-scans-form')
expect(rendered).to have_selector('#js-on-demand-scans')
end
it 'passes on-demand scans docs page URL' do
......
......@@ -23687,6 +23687,9 @@ msgstr ""
msgid "OnDemandScans|My daily scan"
msgstr ""
msgid "OnDemandScans|New DAST scan"
msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
msgstr ""
......@@ -23699,6 +23702,12 @@ msgstr ""
msgid "OnDemandScans|On-demand Scans"
msgstr ""
msgid "OnDemandScans|On-demand scans"
msgstr ""
msgid "OnDemandScans|On-demand scans run outside of DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Lean more%{learnMoreLinkEnd}."
msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
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