diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
index 0807756bc897ad39121828c7509dc7c73a3360a3..0e02863bb9f6bf4ffdd6ee88b5ba9ef216f71e5f 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
@@ -33,6 +33,10 @@ export default {
environmentsHelpText: s__(
'ProjectSettings|Every project can make deployments to environments either via CI/CD or API calls. Non-project members have read-only access.',
),
+ featureFlagsLabel: s__('ProjectSettings|Feature flags'),
+ featureFlagsHelpText: s__(
+ 'ProjectSettings|Roll out new features without redeploying with feature flags.',
+ ),
packagesHelpText: s__(
'ProjectSettings|Every project can have its own space to store its packages. Note: The Package Registry is always visible when a project is public.',
),
@@ -131,6 +135,16 @@ export default {
required: false,
default: '',
},
+ environmentsHelpPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ featureFlagsHelpPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
lfsHelpPath: {
type: String,
required: false,
@@ -214,6 +228,7 @@ export default {
securityAndComplianceAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
operationsAccessLevel: featureAccessLevel.EVERYONE,
environmentsAccessLevel: featureAccessLevel.EVERYONE,
+ featureFlagsAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
containerRegistryAccessLevel: featureAccessLevel.EVERYONE,
warnAboutPotentiallyUnwantedCharacters: true,
lfsEnabled: true,
@@ -290,6 +305,7 @@ export default {
environmentsEnabled() {
return this.environmentsAccessLevel > featureAccessLevel.NOT_ENABLED;
},
+
repositoryEnabled() {
return this.repositoryAccessLevel > featureAccessLevel.NOT_ENABLED;
},
@@ -389,6 +405,10 @@ export default {
featureAccessLevel.PROJECT_MEMBERS,
this.environmentsAccessLevel,
);
+ this.featureFlagsAccessLevel = Math.min(
+ featureAccessLevel.PROJECT_MEMBERS,
+ this.featureFlagsAccessLevel,
+ );
this.containerRegistryAccessLevel = Math.min(
featureAccessLevel.PROJECT_MEMBERS,
this.containerRegistryAccessLevel,
@@ -879,6 +899,7 @@ export default {
ref="environments-settings"
:label="$options.i18n.environmentsLabel"
:help-text="$options.i18n.environmentsHelpText"
+ :help-path="environmentsHelpPath"
>
+
+
+
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index dfc270adf8b644dc802d768e947db4e66d36df8c..a65dd6703f28a4886b239dadcc92bd21e5348dbd 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -389,7 +389,9 @@ def project_permissions_panel_data(project)
pagesAccessControlForced: ::Gitlab::Pages.access_control_is_forced?,
pagesHelpPath: help_page_path('user/project/pages/introduction', anchor: 'gitlab-pages-access-control'),
issuesHelpPath: help_page_path('user/project/issues/index'),
- membersPagePath: project_project_members_path(project)
+ membersPagePath: project_project_members_path(project),
+ environmentsHelpPath: help_page_path('ci/environments/index'),
+ featureFlagsHelpPath: help_page_path('operations/feature_flags')
}
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 2b606d2683b627834131fb6454ee27cd4fc1ff60..48934a0b3d034151b8fdeb2dbdb113136f309d6a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -30859,6 +30859,9 @@ msgstr ""
msgid "ProjectSettings|Fast-forward merges only."
msgstr ""
+msgid "ProjectSettings|Feature flags"
+msgstr ""
+
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
@@ -31000,6 +31003,9 @@ msgstr ""
msgid "ProjectSettings|Requirements management system."
msgstr ""
+msgid "ProjectSettings|Roll out new features without redeploying with feature flags."
+msgstr ""
+
msgid "ProjectSettings|Search for topic"
msgstr ""
diff --git a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
index f908508c4b5d3d9b8b278f5eee5e48ecedbf9e6c..b65f2c8020d861e080fdcd195a5b850f2c442747 100644
--- a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
+++ b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
@@ -128,6 +128,7 @@ describe('Settings Panel', () => {
findOperationsSettings().findComponent(ProjectFeatureSetting);
const findConfirmDangerButton = () => wrapper.findComponent(ConfirmDanger);
const findEnvironmentsSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
+ const findFeatureFlagsSettings = () => wrapper.findComponent({ ref: 'feature-flags-settings' });
afterEach(() => {
wrapper.destroy();
@@ -806,4 +807,22 @@ describe('Settings Panel', () => {
});
});
});
+ describe('Feature Flags', () => {
+ describe('with feature flag', () => {
+ it('should show the feature flags toggle', () => {
+ wrapper = mountComponent({
+ glFeatures: { splitOperationsVisibilityPermissions: true },
+ });
+
+ expect(findFeatureFlagsSettings().exists()).toBe(true);
+ });
+ });
+ describe('without feature flag', () => {
+ it('should not show the feature flags toggle', () => {
+ wrapper = mountComponent({});
+
+ expect(findFeatureFlagsSettings().exists()).toBe(false);
+ });
+ });
+ });
});