Commit c1aec2f8 authored by Jiaan Louw's avatar Jiaan Louw Committed by Jose Ivan Vargas

Update project compliance frameworks settings

Depending on a user's permission, it can be unclear what compliance
frameworks are or how they are added. This change helps clarify
what frameworks are, where they can be added.

Changelog: changed
EE: true
parent 1cb08250
......@@ -5,6 +5,7 @@ import mountApprovals from 'ee/approvals/mount_project_settings';
import { initMergeOptionSettings } from 'ee/pages/projects/edit/merge_options';
import { initServicePingSettingsClickTracking } from 'ee/registration_features_discovery_message';
import initProjectAdjournedDeleteButton from 'ee/projects/project_adjourned_delete_button';
import initProjectComplianceFrameworkEmptyState from 'ee/projects/project_compliance_framework_empty_state';
import mountStatusChecks from 'ee/status_checks/mount';
import groupsSelect from '~/groups_select';
import UserCallout from '~/user_callout';
......@@ -19,5 +20,6 @@ mountApprovals(document.getElementById('js-mr-approvals-settings'));
mountStatusChecks(document.getElementById('js-status-checks-settings'));
initProjectAdjournedDeleteButton();
initProjectComplianceFrameworkEmptyState();
initMergeOptionSettings();
initServicePingSettingsClickTracking();
<script>
import { GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui';
import { sprintf } from '~/locale';
import { PROJECT_COMPLIANCE_FRAMEWORK_I18N } from '../constants';
export default {
components: {
GlEmptyState,
GlSprintf,
GlLink,
},
props: {
groupName: {
type: String,
required: true,
},
groupPath: {
type: String,
required: true,
},
addFrameworkPath: {
type: String,
required: false,
default: '',
},
emptyStateSvgPath: {
type: String,
required: true,
},
},
computed: {
canEdit() {
return this.addFrameworkPath !== '';
},
description() {
return this.canEdit
? PROJECT_COMPLIANCE_FRAMEWORK_I18N.ownerDescription
: PROJECT_COMPLIANCE_FRAMEWORK_I18N.maintainerDescription;
},
buttonText() {
return this.canEdit
? sprintf(PROJECT_COMPLIANCE_FRAMEWORK_I18N.buttonText, { groupName: this.groupName })
: null;
},
buttonLink() {
return this.canEdit ? this.addFrameworkPath : null;
},
},
i18n: {
title: PROJECT_COMPLIANCE_FRAMEWORK_I18N.title,
},
};
</script>
<template>
<gl-empty-state
:description="$options.i18n.description"
:primary-button-text="buttonText"
:primary-button-link="buttonLink"
:svg-path="emptyStateSvgPath"
:svg-height="100"
compact
>
<template #title>
<h5 class="gl-mt-0">{{ $options.i18n.title }}</h5>
</template>
<template #description>
<gl-sprintf :message="description">
<template #link>
<gl-link :href="groupPath">{{ groupName }}</gl-link>
</template>
</gl-sprintf>
</template>
</gl-empty-state>
</template>
import { s__ } from '~/locale';
export const PROJECT_COMPLIANCE_FRAMEWORK_I18N = {
title: s__('ComplianceFramework|No compliance frameworks are set up yet'),
ownerDescription: s__(
'ComplianceFramework|Add a framework to %{linkStart}%{groupName}%{linkEnd} and it will appear here.',
),
maintainerDescription: s__(
'ComplianceFramework|After a framework is added to %{linkStart}%{groupName}%{linkEnd}, it will appear here.',
),
buttonText: s__('ComplianceFramework|Add framework in %{groupName}'),
};
import Vue from 'vue';
import ProjectComplianceFrameworkEmptyState from './components/project_compliance_framework_empty_state.vue';
export default (selector = '#js-project-compliance-framework-empty-state') => {
const el = document.querySelector(selector);
if (!el) return;
const { groupName, groupPath, addFrameworkPath, emptyStateSvgPath } = el.dataset;
// eslint-disable-next-line no-new
new Vue({
el,
render(createElement) {
return createElement(ProjectComplianceFrameworkEmptyState, {
props: {
groupName,
groupPath,
addFrameworkPath,
emptyStateSvgPath,
},
});
},
});
};
......@@ -258,6 +258,19 @@ module EE
project.marked_for_deletion_at.present?
end
def project_compliance_framework_app_data(project, can_edit)
group = project.root_ancestor
{
group_name: group.name,
group_path: group_path(group),
empty_state_svg_path: image_path('illustrations/welcome/ee_trial.svg')
}.tap do |data|
if can_edit
data[:add_framework_path] = "#{edit_group_path(group)}#js-compliance-frameworks-settings"
end
end
end
private
def remove_message_data(project)
......
......@@ -6,32 +6,25 @@
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Compliance framework')
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }= expanded ? _('Collapse') : _('Expand')
%p= html_escape(_('Select a compliance framework to apply to this project. %{linkStart}Learn more.%{linkEnd}')) % { linkStart: compliance_framework_doc_link, linkEnd: '</a>'.html_safe }
%p= html_escape(_('Select a compliance framework to apply to this project. %{linkStart}How are these added?%{linkEnd}')) % { linkStart: compliance_framework_doc_link, linkEnd: '</a>'.html_safe }
.settings-content
= form_for @project, html: { multipart: true, class: "compliance-framework-form" }, authenticity_token: true do |f|
- frameworks = @project.namespace.root_ancestor.compliance_management_frameworks
.form-group
= f.fields_for :compliance_framework_setting, ComplianceManagement::ComplianceFramework::ProjectSettings.new do |cf|
= cf.label :framework, class: 'gl-font-weight-bold' do
= _('Compliance framework')
- if user_has_edit_permissions
- if frameworks.any?
- frameworks = @project.root_ancestor.compliance_management_frameworks
- if frameworks.any?
= form_for @project, html: { multipart: true, class: "compliance-framework-form" }, authenticity_token: true do |f|
.form-group
= f.fields_for :compliance_framework_setting, ComplianceManagement::ComplianceFramework::ProjectSettings.new do |cf|
= cf.label :framework, class: 'gl-font-weight-bold' do
= _('Compliance framework')
- if user_has_edit_permissions
- selected_default_framework = @project.compliance_framework_setting&.compliance_management_framework&.id
= cf.select :framework, options_for_select(frameworks.map { |fw| [fw.name.truncate(88), fw.id] }, selected_default_framework), { selected: '', prompt: _('Choose your framework'), include_blank: _('None') }, { class: 'form-control', disabled: false }
= cf.select :framework, options_for_select(frameworks.map { |fw| [fw.name.truncate(88), fw.id] }, selected_default_framework), { selected: '', prompt: _('Choose your framework'), include_blank: _('None') }, { class: 'form-control gl-w-full', disabled: false }
- else
%p.form-text.text-muted
= _("No compliance frameworks are in use. Create one from the %{link} section in Group Settings.").html_safe % { link: link_to('Compliance frameworks', edit_group_path(@project.namespace.root_ancestor)).html_safe }
- else
- if frameworks.any?
- selected_framework = @project.compliance_framework_setting&.compliance_management_framework&.name&.truncate(88) || _('None')
= cf.text_field :framework, value: selected_framework, class: 'form-control read-only', disabled: true
%p.form-text.text-muted
= _("Customizable by owners.")
- else
%p.form-text.text-muted
= _("No compliance frameworks are in use.")
- if user_has_edit_permissions && frameworks.any?
= f.submit _('Save changes'), class: "btn gl-button btn-confirm"
= _("Owners can modify this selection.")
- if user_has_edit_permissions
= f.submit _('Save changes'), class: "btn gl-button btn-confirm"
- else
#js-project-compliance-framework-empty-state{ data: project_compliance_framework_app_data(@project, user_has_edit_permissions) }
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Project compliance framework empty state it matches the snapshot when "addFrameworkPath" is a string path 1`] = `
<gl-empty-state-stub
compact="true"
primarybuttonlink="/edit-group"
primarybuttontext="Add framework in group-name"
svgheight="100"
svgpath="/image.svg"
>
<h5
class="gl-mt-0"
>
No compliance frameworks are set up yet
</h5>
Add a framework to
<gl-link-stub
href="/group-path"
>
group-name
</gl-link-stub>
and it will appear here.
</gl-empty-state-stub>
`;
exports[`Project compliance framework empty state it matches the snapshot when "addFrameworkPath" is undefined 1`] = `
<gl-empty-state-stub
compact="true"
svgheight="100"
svgpath="/image.svg"
>
<h5
class="gl-mt-0"
>
No compliance frameworks are set up yet
</h5>
After a framework is added to
<gl-link-stub
href="/group-path"
>
group-name
</gl-link-stub>
, it will appear here.
</gl-empty-state-stub>
`;
import { shallowMount } from '@vue/test-utils';
import { GlSprintf } from '@gitlab/ui';
import ProjectComplianceFrameworkEmptyState from 'ee/projects/components/project_compliance_framework_empty_state.vue';
describe('Project compliance framework empty state', () => {
let wrapper;
const defaultProps = {
groupName: 'group-name',
groupPath: '/group-path',
emptyStateSvgPath: '/image.svg',
};
const createComponent = (props = {}) => {
wrapper = shallowMount(ProjectComplianceFrameworkEmptyState, {
propsData: {
...defaultProps,
...props,
},
stubs: {
GlSprintf,
},
});
};
afterEach(() => {
wrapper.destroy();
});
it.each`
addFrameworkPath | description
${undefined} | ${'undefined'}
${'/edit-group'} | ${'a string path'}
`('it matches the snapshot when "addFrameworkPath" is $description', ({ addFrameworkPath }) => {
createComponent({ addFrameworkPath });
expect(wrapper.element).toMatchSnapshot();
});
});
......@@ -462,4 +462,42 @@ RSpec.describe ProjectsHelper do
})
end
end
describe '#project_compliance_framework_app_data' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let(:can_edit) { false }
subject { helper.project_compliance_framework_app_data(project, can_edit) }
before do
allow(helper).to receive(:image_path).and_return('#empty_state_svg_path')
end
context 'when the user cannot edit' do
let(:can_edit) { false }
it 'returns the correct data' do
expect(subject).to eq({
group_name: group.name,
group_path: group_path(group),
empty_state_svg_path: '#empty_state_svg_path'
})
end
end
context 'when the user can edit' do
let(:can_edit) { true }
it 'includes the framework edit path' do
expect(subject).to eq({
group_name: group.name,
group_path: group_path(group),
empty_state_svg_path: '#empty_state_svg_path',
add_framework_path: "#{edit_group_path(group)}#js-compliance-frameworks-settings"
})
end
end
end
end
......@@ -18,7 +18,7 @@ RSpec.describe 'compliance_management/compliance_framework/_project_settings.htm
it 'shows the section description' do
render
expect(rendered).to have_text 'Select a compliance framework to apply to this project. Learn more.'
expect(rendered).to have_text 'Select a compliance framework to apply to this project. How are these added?'
end
context 'group has compliance frameworks' do
......@@ -47,7 +47,7 @@ RSpec.describe 'compliance_management/compliance_framework/_project_settings.htm
it 'shows the no permissions text' do
render
expect(rendered).to have_text('Customizable by owners.')
expect(rendered).to have_text('Owners can modify this selection.')
end
it 'disables the dropdown' do
......@@ -67,10 +67,16 @@ RSpec.describe 'compliance_management/compliance_framework/_project_settings.htm
group.compliance_management_frameworks.delete_all
end
it 'shows the empty text' do
it 'renders the empty state' do
render
expect(rendered).to match /No compliance frameworks are in use. Create one from the .* section in Group Settings./
expect(rendered).to have_css(
'#js-project-compliance-framework-empty-state'\
"[data-add-framework-path=\"#{edit_group_path(group)}#js-compliance-frameworks-settings\"]"\
"[data-empty-state-svg-path]"\
"[data-group-name=\"#{group.name}\"]"\
"[data-group-path=\"#{group_path(group)}\"]"
)
end
it 'hides the submit button' do
......@@ -85,10 +91,15 @@ RSpec.describe 'compliance_management/compliance_framework/_project_settings.htm
allow(view).to receive(:current_user).and_return(maintainer)
end
it 'shows the empty text' do
it 'renders the empty state' do
render
expect(rendered).to have_text('No compliance frameworks are in use.')
expect(rendered).to have_css(
'#js-project-compliance-framework-empty-state'\
"[data-empty-state-svg-path]"\
"[data-group-name=\"#{group.name}\"]"\
"[data-group-path=\"#{group_path(group)}\"]"
)
end
it 'hides the submit button' do
......
......@@ -9092,12 +9092,24 @@ msgstr ""
msgid "ComplianceFrameworks|You are about to permanently delete the compliance framework %{framework} from all projects which currently have it applied, which may remove other functionality. This cannot be undone."
msgstr ""
msgid "ComplianceFramework|Add a framework to %{linkStart}%{groupName}%{linkEnd} and it will appear here."
msgstr ""
msgid "ComplianceFramework|Add framework in %{groupName}"
msgstr ""
msgid "ComplianceFramework|After a framework is added to %{linkStart}%{groupName}%{linkEnd}, it will appear here."
msgstr ""
msgid "ComplianceFramework|Edit compliance framework"
msgstr ""
msgid "ComplianceFramework|New compliance framework"
msgstr ""
msgid "ComplianceFramework|No compliance frameworks are set up yet"
msgstr ""
msgid "ComplianceReport|Approved by author"
msgstr ""
......@@ -10766,9 +10778,6 @@ msgstr ""
msgid "Customer relations"
msgstr ""
msgid "Customizable by owners."
msgstr ""
msgid "Customize CI/CD settings, including Auto DevOps, shared runners, and job artifacts."
msgstr ""
......@@ -24660,12 +24669,6 @@ msgstr ""
msgid "No committers"
msgstr ""
msgid "No compliance frameworks are in use."
msgstr ""
msgid "No compliance frameworks are in use. Create one from the %{link} section in Group Settings."
msgstr ""
msgid "No confirmation email received? Check your spam folder or %{request_link_start}request new confirmation email%{request_link_end}."
msgstr ""
......@@ -25872,6 +25875,9 @@ msgstr ""
msgid "Owner"
msgstr ""
msgid "Owners can modify this selection."
msgstr ""
msgid "PQL|An error occurred while sending hand raise lead."
msgstr ""
......@@ -33145,7 +33151,7 @@ msgstr ""
msgid "Select a branch"
msgstr ""
msgid "Select a compliance framework to apply to this project. %{linkStart}Learn more.%{linkEnd}"
msgid "Select a compliance framework to apply to this project. %{linkStart}How are these added?%{linkEnd}"
msgstr ""
msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes."
......
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