Commit 0b3b9637 authored by Evan Read's avatar Evan Read

Refactor compliance framework UI and documentation

Changelog: other
EE: true
parent 86541261
...@@ -81,8 +81,8 @@ export default { ...@@ -81,8 +81,8 @@ export default {
}, },
}, },
i18n: { i18n: {
fullDescription: __('Choose any color. Or you can choose one of the suggested colors below'), fullDescription: __('Enter any color or choose one of the suggested colors below.'),
shortDescription: __('Choose any color'), shortDescription: __('Enter any color.'),
}, },
}; };
</script> </script>
......
...@@ -39,17 +39,19 @@ You can use [emphasis](../../markdown.md#emphasis), [links](../../markdown.md#li ...@@ -39,17 +39,19 @@ You can use [emphasis](../../markdown.md#emphasis), [links](../../markdown.md#li
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276221) in GitLab 13.9. > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276221) in GitLab 13.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/287779) in GitLab 13.12. > - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/287779) in GitLab 13.12.
You can create a framework label to identify that your project has certain compliance requirements You can create a compliance framework label to identify that your project has certain compliance
or needs additional oversight. requirements or needs additional oversight. The label can optionally apply
[compliance pipeline configuration](#compliance-pipeline-configuration).
Group owners can create, edit, and delete compliance frameworks: Group owners can create, edit, and delete compliance frameworks:
1. Go to the group's **Settings** > **General**. 1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Settings** > **General**.
1. Expand the **Compliance frameworks** section. 1. Expand the **Compliance frameworks** section.
Compliance frameworks created can then be assigned to any number of projects using: Compliance frameworks created can then be assigned to projects within the group using:
- The project settings page inside the group or subgroups. - The GitLab UI, using the project settings page.
- In [GitLab 14.2](https://gitlab.com/gitlab-org/gitlab/-/issues/333249) and later, using the - In [GitLab 14.2](https://gitlab.com/gitlab-org/gitlab/-/issues/333249) and later, using the
[GraphQL API](../../../api/graphql/reference/index.md#mutationprojectsetcomplianceframework). [GraphQL API](../../../api/graphql/reference/index.md#mutationprojectsetcomplianceframework).
...@@ -64,24 +66,32 @@ read-only view to discourage this behavior. ...@@ -64,24 +66,32 @@ read-only view to discourage this behavior.
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300324) in GitLab 13.11. > - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300324) in GitLab 13.11.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/331231) in GitLab 14.2. > - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/331231) in GitLab 14.2.
Group owners can use the compliance pipeline configuration to define compliance requirements Group owners can use compliance pipeline configuration to add additional pipeline configuration to
such as scans or tests, and enforce them in individual projects. projects to define compliance requirements such as scans or tests.
The [custom compliance framework](#compliance-frameworks) feature allows group owners to specify the location [Compliance frameworks](#compliance-frameworks) allow group owners to specify the location of
of a compliance pipeline configuration stored and managed in a dedicated project, distinct from a developer's project. compliance pipeline configuration stored and managed in dedicated projects, separate from regular
projects.
When you set up the compliance pipeline configuration field, use the When you set up the compliance framework, use the **Compliance pipeline configuration** box to link
`file@group/project` format. For example, you can configure the compliance framework to specific CI/CD configuration. Use the
`.compliance-gitlab-ci.yml@compliance-group/compliance-project`. `path/file.y[a]ml@group-name/project-name` format. For example:
This field is inherited by projects where the compliance framework label is applied. The result
forces the project to run the compliance configurations.
When a project with a custom label executes a pipeline, it begins by evaluating the compliance pipeline configuration. - `.compliance-ci.yml@gitlab-org/gitlab`.
The custom pipeline configuration can then execute any included individual project configuration. - `.compliance-ci.yaml@gitlab-org/gitlab`.
The user running the pipeline in the project should at least have Reporter access to the compliance project. This configuration is inherited by projects where the compliance framework label is applied. The
result forces projects with the label to run the compliance CI/CD configuration in addition to
the project's own CI/CD configuration. When a project with a compliance framework label executes a
pipeline, it evaluates configuration in the following order:
Example `.compliance-gitlab-ci.yml` 1. Compliance pipeline configuration.
1. Project-specific pipeline configuration.
The user running the pipeline in the project must at least have the Reporter role on the compliance
project.
Example `.compliance-gitlab-ci.yml`:
```yaml ```yaml
# Allows compliance team to control the ordering and interweaving of stages/jobs. # Allows compliance team to control the ordering and interweaving of stages/jobs.
...@@ -94,10 +104,10 @@ stages: ...@@ -94,10 +104,10 @@ stages:
- deploy - deploy
- post-compliance - post-compliance
variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml
FOO: sast FOO: sast
sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml
variables: variables:
FOO: sast FOO: sast
image: ruby:2.6 image: ruby:2.6
...@@ -144,10 +154,10 @@ audit trail: ...@@ -144,10 +154,10 @@ audit trail:
after_script: after_script:
- "# No after scripts." - "# No after scripts."
include: # Execute individual project's configuration (if project contains .gitlab-ci.yml) include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
project: '$CI_PROJECT_PATH' project: '$CI_PROJECT_PATH'
file: '$CI_CONFIG_PATH' file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_REF_NAME' # Must be defined or MR pipelines always use the use default branch. ref: '$CI_COMMIT_REF_NAME' # Must be defined or MR pipelines always use the use default branch.
``` ```
##### Ensure compliance jobs are always run ##### Ensure compliance jobs are always run
......
...@@ -19,10 +19,8 @@ export default { ...@@ -19,10 +19,8 @@ export default {
}, },
}, },
i18n: { i18n: {
heading: s__('ComplianceFrameworks|There are no compliance frameworks set up yet'), heading: s__('ComplianceFrameworks|No compliance frameworks are configured'),
description: s__( description: s__('ComplianceFrameworks|Configured compliance frameworks appear here.'),
'ComplianceFrameworks|Once a compliance framework is added it will appear here.',
),
addButton: s__('ComplianceFrameworks|Add framework'), addButton: s__('ComplianceFrameworks|Add framework'),
}, },
}; };
......
...@@ -4,7 +4,7 @@ import { debounce } from 'lodash'; ...@@ -4,7 +4,7 @@ import { debounce } from 'lodash';
import { helpPagePath } from '~/helpers/help_page_helper'; import { helpPagePath } from '~/helpers/help_page_helper';
import { validateHexColor } from '~/lib/utils/color_utils'; import { validateHexColor } from '~/lib/utils/color_utils';
import { __, s__ } from '~/locale'; import { s__ } from '~/locale';
import ColorPicker from '~/vue_shared/components/color_picker/color_picker.vue'; import ColorPicker from '~/vue_shared/components/color_picker/color_picker.vue';
import { DEBOUNCE_DELAY } from '../constants'; import { DEBOUNCE_DELAY } from '../constants';
import { fetchPipelineConfigurationFileExists, validatePipelineConfirmationFormat } from '../utils'; import { fetchPipelineConfigurationFileExists, validatePipelineConfirmationFormat } from '../utils';
...@@ -102,8 +102,10 @@ export default { ...@@ -102,8 +102,10 @@ export default {
return this.$options.i18n.pipelineConfigurationInputUnknownFile; return this.$options.i18n.pipelineConfigurationInputUnknownFile;
}, },
scopedLabelsHelpPath() { compliancePipelineConfigurationHelpPath() {
return helpPagePath('user/project/labels.md', { anchor: 'scoped-labels' }); return helpPagePath('user/project/settings/index.md', {
anchor: 'compliance-pipeline-configuration',
});
}, },
}, },
async created() { async created() {
...@@ -127,30 +129,20 @@ export default { ...@@ -127,30 +129,20 @@ export default {
}, DEBOUNCE_DELAY), }, DEBOUNCE_DELAY),
}, },
i18n: { i18n: {
titleInputLabel: __('Title'), titleInputLabel: s__('ComplianceFrameworks|Name'),
titleInputDescription: s__( titleInputInvalid: s__('ComplianceFrameworks|Name is required'),
'ComplianceFrameworks|Use %{codeStart}::%{codeEnd} to create a %{linkStart}scoped set%{linkEnd} (eg. %{codeStart}SOX::AWS%{codeEnd})', descriptionInputLabel: s__('ComplianceFrameworks|Description'),
), descriptionInputInvalid: s__('ComplianceFrameworks|Description is required'),
titleInputInvalid: __('A title is required'),
descriptionInputLabel: __('Description'),
descriptionInputInvalid: __('A description is required'),
pipelineConfigurationInputLabel: s__( pipelineConfigurationInputLabel: s__(
'ComplianceFrameworks|Compliance pipeline configuration location (optional)', 'ComplianceFrameworks|Compliance pipeline configuration (optional)',
),
pipelineConfigurationInputSubLabel: s__(
'ComplianceFrameworks|Combines with the CI configuration at runtime.',
), ),
pipelineConfigurationInputDescription: s__( pipelineConfigurationInputDescription: s__(
'ComplianceFrameworks|e.g. include-gitlab.ci.yml@group-name/project-name', 'ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}Learn more.%{linkEnd}',
),
pipelineConfigurationInputInvalidFormat: s__(
'ComplianceFrameworks|Invalid format: it should follow the format [PATH].y(a)ml@[GROUP]/[PROJECT]',
), ),
pipelineConfigurationInputUnknownFile: s__( pipelineConfigurationInputInvalidFormat: s__('ComplianceFrameworks|Invalid format'),
'ComplianceFrameworks|Could not find this configuration location, please try a different location', pipelineConfigurationInputUnknownFile: s__('ComplianceFrameworks|Configuration not found'),
), colorInputLabel: s__('ComplianceFrameworks|Background color'),
colorInputLabel: __('Background color'), cancelBtnText: s__('ComplianceFrameworks|Cancel'),
cancelBtnText: __('Cancel'),
}, },
}; };
</script> </script>
...@@ -162,18 +154,6 @@ export default { ...@@ -162,18 +154,6 @@ export default {
:state="isValidName" :state="isValidName"
data-testid="name-input-group" data-testid="name-input-group"
> >
<template #description>
<gl-sprintf :message="$options.i18n.titleInputDescription">
<template #code="{ content }">
<code>{{ content }}</code>
</template>
<template #link="{ content }">
<gl-link :href="scopedLabelsHelpPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</template>
<gl-form-input <gl-form-input
:value="name" :value="name"
:state="isValidName" :state="isValidName"
...@@ -199,14 +179,24 @@ export default { ...@@ -199,14 +179,24 @@ export default {
<gl-form-group <gl-form-group
v-if="pipelineConfigurationFullPathEnabled" v-if="pipelineConfigurationFullPathEnabled"
:label="$options.i18n.pipelineConfigurationInputLabel" :label="$options.i18n.pipelineConfigurationInputLabel"
:description="$options.i18n.pipelineConfigurationInputDescription"
:invalid-feedback="pipelineConfigurationFeedbackMessage" :invalid-feedback="pipelineConfigurationFeedbackMessage"
:state="isValidPipelineConfiguration" :state="isValidPipelineConfiguration"
data-testid="pipeline-configuration-input-group" data-testid="pipeline-configuration-input-group"
> >
<p class="col-form-label gl-font-weight-normal!"> <template #description>
{{ $options.i18n.pipelineConfigurationInputSubLabel }} <gl-sprintf :message="$options.i18n.pipelineConfigurationInputDescription">
</p> <template #code="{ content }">
<code>{{ content }}</code>
</template>
<template #link="{ content }">
<gl-link :href="compliancePipelineConfigurationHelpPath" target="_blank">{{
content
}}</gl-link>
</template>
</gl-sprintf>
</template>
<gl-form-input <gl-form-input
:value="pipelineConfigurationFullPath" :value="pipelineConfigurationFullPath"
:state="isValidPipelineConfiguration" :state="isValidPipelineConfiguration"
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
.settings-header .settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Compliance framework') %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') %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }= expanded ? _('Collapse') : _('Expand')
%p= html_escape(_('Select a framework that applies to this project. %{linkStart}How are these added?%{linkEnd}')) % { linkStart: compliance_framework_doc_link, linkEnd: '</a>'.html_safe } %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 }
.settings-content .settings-content
= form_for @project, html: { multipart: true, class: "compliance-framework-form" }, authenticity_token: true do |f| = form_for @project, html: { multipart: true, class: "compliance-framework-form" }, authenticity_token: true do |f|
......
- expanded = expanded_by_default? - expanded = expanded_by_default?
- compliance_framework_doc_link = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/settings/index.md', anchor: 'compliance-frameworks') }
- if show_compliance_frameworks?(@group) - if show_compliance_frameworks?(@group)
%section.settings.no-animate#js-compliance-frameworks-settings{ class: ('expanded' if expanded) } %section.settings.no-animate#js-compliance-frameworks-settings{ class: ('expanded' if expanded) }
...@@ -8,6 +9,6 @@ ...@@ -8,6 +9,6 @@
%button.btn.gl-button.js-settings-toggle{ type: 'button' } %button.btn.gl-button.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand') = expanded ? _('Collapse') : _('Expand')
%p %p
= s_('GroupSettings|Configure frameworks to apply enforceable rules to projects.') = html_escape(s_('GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}Learn more.%{linkEnd}')) % { linkStart: compliance_framework_doc_link, linkEnd: '</a>'.html_safe }
.settings-content .settings-content
#js-compliance-frameworks-list{ data: compliance_frameworks_list_data(@group) } #js-compliance-frameworks-list{ data: compliance_frameworks_list_data(@group) }
- add_to_breadcrumbs _('General Settings'), edit_group_path(@group) - add_to_breadcrumbs _('General Settings'), edit_group_path(@group)
- title = s_('ComplianceFramework|Edit Compliance Framework') - title = s_('ComplianceFramework|Edit compliance framework')
- page_title title - page_title title
%h3.page-title= title %h3.page-title= title
......
- add_to_breadcrumbs _('General Settings'), edit_group_path(@group) - add_to_breadcrumbs _('General Settings'), edit_group_path(@group)
- title = s_('ComplianceFramework|New Compliance Framework') - title = s_('ComplianceFramework|New compliance framework')
- page_title title - page_title title
%h3.page-title= title %h3.page-title= title
......
...@@ -25,8 +25,8 @@ describe('ListEmptyState', () => { ...@@ -25,8 +25,8 @@ describe('ListEmptyState', () => {
createComponent(); createComponent();
expect(findEmptyState().props()).toMatchObject({ expect(findEmptyState().props()).toMatchObject({
title: 'There are no compliance frameworks set up yet', title: 'No compliance frameworks are configured',
description: 'Once a compliance framework is added it will appear here.', description: 'Configured compliance frameworks appear here.',
svgPath: 'dir/image.svg', svgPath: 'dir/image.svg',
primaryButtonLink: 'group/framework/new', primaryButtonLink: 'group/framework/new',
primaryButtonText: 'Add framework', primaryButtonText: 'Add framework',
......
...@@ -63,12 +63,6 @@ describe('SharedForm', () => { ...@@ -63,12 +63,6 @@ describe('SharedForm', () => {
expect(findCancelBtn()).toExist(); expect(findCancelBtn()).toExist();
}); });
it('shows the name input description', () => {
wrapper = createComponent();
expect(findNameGroup().text()).toContain('Use :: to create a scoped set (eg. SOX::AWS)');
});
it('sets the submit button text from the property', () => { it('sets the submit button text from the property', () => {
wrapper = createComponent(); wrapper = createComponent();
...@@ -112,8 +106,8 @@ describe('SharedForm', () => { ...@@ -112,8 +106,8 @@ describe('SharedForm', () => {
it.each` it.each`
pipelineConfigurationFullPath | message pipelineConfigurationFullPath | message
${'foobar'} | ${'Invalid format: it should follow the format [PATH].y(a)ml@[GROUP]/[PROJECT]'} ${'foobar'} | ${'Invalid format'}
${'foo.yml@bar/baz'} | ${'Could not find this configuration location, please try a different location'} ${'foo.yml@bar/baz'} | ${'Configuration not found'}
`( `(
'sets the correct invalid message to the group', 'sets the correct invalid message to the group',
async ({ pipelineConfigurationFullPath, message }) => { async ({ pipelineConfigurationFullPath, message }) => {
......
...@@ -18,7 +18,7 @@ RSpec.describe 'compliance_management/compliance_framework/_project_settings.htm ...@@ -18,7 +18,7 @@ RSpec.describe 'compliance_management/compliance_framework/_project_settings.htm
it 'shows the section description' do it 'shows the section description' do
render render
expect(rendered).to have_text 'Select a framework that applies to this project. How are these added?' expect(rendered).to have_text 'Select a compliance framework to apply to this project. Learn more.'
end end
context 'group has compliance frameworks' do context 'group has compliance frameworks' do
......
...@@ -6,7 +6,7 @@ RSpec.describe 'groups/_compliance_frameworks.html.haml' do ...@@ -6,7 +6,7 @@ RSpec.describe 'groups/_compliance_frameworks.html.haml' do
let_it_be(:group) { build(:group) } let_it_be(:group) { build(:group) }
let(:title) { 'Compliance frameworks' } let(:title) { 'Compliance frameworks' }
let(:description) { 'Configure frameworks to apply enforceable rules to projects.' } let(:description) { 'Configure compliance frameworks to make them available to projects in this group.' }
before do before do
assign(:group, group) assign(:group, group)
......
...@@ -18,7 +18,7 @@ RSpec.describe 'groups/compliance_frameworks/edit.html.haml' do ...@@ -18,7 +18,7 @@ RSpec.describe 'groups/compliance_frameworks/edit.html.haml' do
it 'shows the compliance frameworks form', :aggregate_failures do it 'shows the compliance frameworks form', :aggregate_failures do
render render
expect(rendered).to have_content('Edit Compliance Framework') expect(rendered).to have_content('Edit compliance framework')
expect(rendered).to have_css('#js-compliance-frameworks-form') expect(rendered).to have_css('#js-compliance-frameworks-form')
expect(rendered).to have_css('[data-framework-id="1"]') expect(rendered).to have_css('[data-framework-id="1"]')
end end
......
...@@ -17,7 +17,7 @@ RSpec.describe 'groups/compliance_frameworks/new.html.haml' do ...@@ -17,7 +17,7 @@ RSpec.describe 'groups/compliance_frameworks/new.html.haml' do
it 'shows the compliance frameworks form', :aggregate_failures do it 'shows the compliance frameworks form', :aggregate_failures do
render render
expect(rendered).to have_content('New Compliance Framework') expect(rendered).to have_content('New compliance framework')
expect(rendered).to have_css('#js-compliance-frameworks-form') expect(rendered).to have_css('#js-compliance-frameworks-form')
end end
end end
...@@ -1439,9 +1439,6 @@ msgstr "" ...@@ -1439,9 +1439,6 @@ msgstr ""
msgid "A deleted user" msgid "A deleted user"
msgstr "" msgstr ""
msgid "A description is required"
msgstr ""
msgid "A different reason" msgid "A different reason"
msgstr "" msgstr ""
...@@ -6838,15 +6835,9 @@ msgstr "" ...@@ -6838,15 +6835,9 @@ msgstr ""
msgid "Choose a type..." msgid "Choose a type..."
msgstr "" msgstr ""
msgid "Choose any color"
msgstr ""
msgid "Choose any color." msgid "Choose any color."
msgstr "" msgstr ""
msgid "Choose any color. Or you can choose one of the suggested colors below"
msgstr ""
msgid "Choose file…" msgid "Choose file…"
msgstr "" msgstr ""
...@@ -8493,16 +8484,22 @@ msgstr "" ...@@ -8493,16 +8484,22 @@ msgstr ""
msgid "ComplianceFrameworks|Add framework" msgid "ComplianceFrameworks|Add framework"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|Combines with the CI configuration at runtime." msgid "ComplianceFrameworks|Background color"
msgstr ""
msgid "ComplianceFrameworks|Cancel"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|Compliance framework deleted successfully" msgid "ComplianceFrameworks|Compliance framework deleted successfully"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|Compliance pipeline configuration location (optional)" msgid "ComplianceFrameworks|Compliance pipeline configuration (optional)"
msgstr ""
msgid "ComplianceFrameworks|Configuration not found"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|Could not find this configuration location, please try a different location" msgid "ComplianceFrameworks|Configured compliance frameworks appear here."
msgstr "" msgstr ""
msgid "ComplianceFrameworks|Delete compliance framework %{framework}" msgid "ComplianceFrameworks|Delete compliance framework %{framework}"
...@@ -8511,6 +8508,12 @@ msgstr "" ...@@ -8511,6 +8508,12 @@ msgstr ""
msgid "ComplianceFrameworks|Delete framework" msgid "ComplianceFrameworks|Delete framework"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|Description"
msgstr ""
msgid "ComplianceFrameworks|Description is required"
msgstr ""
msgid "ComplianceFrameworks|Edit framework" msgid "ComplianceFrameworks|Edit framework"
msgstr "" msgstr ""
...@@ -8523,31 +8526,31 @@ msgstr "" ...@@ -8523,31 +8526,31 @@ msgstr ""
msgid "ComplianceFrameworks|Error fetching compliance frameworks data. Please refresh the page or try a different framework" msgid "ComplianceFrameworks|Error fetching compliance frameworks data. Please refresh the page or try a different framework"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|Invalid format: it should follow the format [PATH].y(a)ml@[GROUP]/[PROJECT]" msgid "ComplianceFrameworks|Invalid format"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|Once a compliance framework is added it will appear here." msgid "ComplianceFrameworks|Name"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|There are no compliance frameworks set up yet" msgid "ComplianceFrameworks|Name is required"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again" msgid "ComplianceFrameworks|No compliance frameworks are configured"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|Use %{codeStart}::%{codeEnd} to create a %{linkStart}scoped set%{linkEnd} (eg. %{codeStart}SOX::AWS%{codeEnd})" msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}Learn more.%{linkEnd}"
msgstr "" 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." msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again"
msgstr "" msgstr ""
msgid "ComplianceFrameworks|e.g. include-gitlab.ci.yml@group-name/project-name" 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 "" msgstr ""
msgid "ComplianceFramework|Edit Compliance Framework" msgid "ComplianceFramework|Edit compliance framework"
msgstr "" msgstr ""
msgid "ComplianceFramework|New Compliance Framework" msgid "ComplianceFramework|New compliance framework"
msgstr "" msgstr ""
msgid "Component" msgid "Component"
...@@ -12823,6 +12826,12 @@ msgstr "" ...@@ -12823,6 +12826,12 @@ msgstr ""
msgid "Enter an integer number number between 0 and 100" msgid "Enter an integer number number between 0 and 100"
msgstr "" msgstr ""
msgid "Enter any color or choose one of the suggested colors below."
msgstr ""
msgid "Enter any color."
msgstr ""
msgid "Enter at least three characters to search" msgid "Enter at least three characters to search"
msgstr "" msgstr ""
...@@ -16408,7 +16417,7 @@ msgstr "" ...@@ -16408,7 +16417,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks" msgid "GroupSettings|Compliance frameworks"
msgstr "" msgstr ""
msgid "GroupSettings|Configure frameworks to apply enforceable rules to projects." msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}Learn more.%{linkEnd}"
msgstr "" msgstr ""
msgid "GroupSettings|Custom project templates" msgid "GroupSettings|Custom project templates"
...@@ -30535,10 +30544,10 @@ msgstr "" ...@@ -30535,10 +30544,10 @@ msgstr ""
msgid "Select a branch" msgid "Select a branch"
msgstr "" msgstr ""
msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes." msgid "Select a compliance framework to apply to this project. %{linkStart}Learn more.%{linkEnd}"
msgstr "" msgstr ""
msgid "Select a framework that applies to this project. %{linkStart}How are these added?%{linkEnd}" msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes."
msgstr "" msgstr ""
msgid "Select a group to invite" msgid "Select a group to invite"
......
...@@ -111,15 +111,13 @@ describe('ColorPicker', () => { ...@@ -111,15 +111,13 @@ describe('ColorPicker', () => {
gon.suggested_label_colors = {}; gon.suggested_label_colors = {};
createComponent(shallowMount); createComponent(shallowMount);
expect(description()).toBe('Choose any color'); expect(description()).toBe('Enter any color.');
expect(presetColors().exists()).toBe(false); expect(presetColors().exists()).toBe(false);
}); });
it('shows the suggested colors', () => { it('shows the suggested colors', () => {
createComponent(shallowMount); createComponent(shallowMount);
expect(description()).toBe( expect(description()).toBe('Enter any color or choose one of the suggested colors below.');
'Choose any color. Or you can choose one of the suggested colors below',
);
expect(presetColors()).toHaveLength(4); expect(presetColors()).toHaveLength(4);
}); });
......
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