Commit 835412a0 authored by David O'Regan's avatar David O'Regan

Merge branch '224698-fe-operations' into 'master'

Add toggle to disable Operations in settings

See merge request gitlab-org/gitlab!49919
parents 8d0a8a47 f88f9e92
......@@ -33,6 +33,11 @@ export default {
required: false,
default: false,
},
showToggle: {
type: Boolean,
required: false,
default: true,
},
},
computed: {
featureEnabled() {
......@@ -74,6 +79,7 @@ export default {
>
<input v-if="name" :name="name" :value="value" type="hidden" />
<project-feature-toggle
v-if="showToggle"
class="gl-flex-grow-0 gl-mr-3"
:value="featureEnabled"
:disabled-input="disabledInput"
......
......@@ -12,6 +12,7 @@ import {
featureAccessLevelMembers,
featureAccessLevelEveryone,
featureAccessLevel,
featureAccessLevelNone,
} from '../constants';
import { toggleHiddenClassBySelector } from '../external';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
......@@ -140,6 +141,7 @@ export default {
metricsDashboardAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
analyticsAccessLevel: featureAccessLevel.EVERYONE,
requirementsAccessLevel: featureAccessLevel.EVERYONE,
operationsAccessLevel: featureAccessLevel.EVERYONE,
containerRegistryEnabled: true,
lfsEnabled: true,
requestAccessEnabled: true,
......@@ -167,6 +169,14 @@ export default {
);
},
operationsFeatureAccessLevelOptions() {
if (!this.operationsEnabled) return [featureAccessLevelNone];
return this.featureAccessLevelOptions.filter(
([value]) => value <= this.operationsAccessLevel,
);
},
pagesFeatureAccessLevelOptions() {
const options = [featureAccessLevelMembers];
......@@ -186,8 +196,12 @@ export default {
return options;
},
metricsOptionsDropdownEnabled() {
return this.featureAccessLevelOptions.length < 2;
metricsOptionsDropdownDisabled() {
return this.operationsFeatureAccessLevelOptions.length < 2 || !this.operationsEnabled;
},
operationsEnabled() {
return this.operationsAccessLevel > featureAccessLevel.NOT_ENABLED;
},
repositoryEnabled() {
......@@ -250,6 +264,10 @@ export default {
featureAccessLevel.PROJECT_MEMBERS,
this.requirementsAccessLevel,
);
this.operationsAccessLevel = Math.min(
featureAccessLevel.PROJECT_MEMBERS,
this.operationsAccessLevel,
);
if (this.pagesAccessLevel === featureAccessLevel.EVERYONE) {
// When from Internal->Private narrow access for only members
this.pagesAccessLevel = featureAccessLevel.PROJECT_MEMBERS;
......@@ -277,6 +295,8 @@ export default {
this.metricsDashboardAccessLevel = featureAccessLevel.EVERYONE;
if (this.requirementsAccessLevel === featureAccessLevel.PROJECT_MEMBERS)
this.requirementsAccessLevel = featureAccessLevel.EVERYONE;
if (this.operationsAccessLevel === featureAccessLevel.PROJECT_MEMBERS)
this.operationsAccessLevel = featureAccessLevel.EVERYONE;
this.highlightChanges();
}
......@@ -561,6 +581,18 @@ export default {
name="project[project_feature_attributes][pages_access_level]"
/>
</project-setting-row>
<project-setting-row
ref="operations-settings"
:label="s__('ProjectSettings|Operations')"
:help-text="s__('ProjectSettings|Environments, logs, cluster management, and more')"
>
<project-feature-setting
v-model="operationsAccessLevel"
:options="featureAccessLevelOptions"
name="project[project_feature_attributes][operations_access_level]"
/>
</project-setting-row>
<div class="project-feature-setting-group gl-pl-7 gl-sm-pl-5">
<project-setting-row
ref="metrics-visibility-settings"
:label="__('Metrics Dashboard')"
......@@ -570,34 +602,15 @@ export default {
)
"
>
<div class="project-feature-controls gl-display-flex gl-align-items-center gl-my-3 gl-mx-0">
<div class="select-wrapper gl-flex-fill-1">
<select
<project-feature-setting
v-model="metricsDashboardAccessLevel"
:disabled="metricsOptionsDropdownEnabled"
:show-toggle="false"
:options="operationsFeatureAccessLevelOptions"
name="project[project_feature_attributes][metrics_dashboard_access_level]"
class="form-control project-repo-select select-control"
>
<option
:value="featureAccessLevelMembers[0]"
:disabled="!visibilityAllowed(visibilityOptions.INTERNAL)"
>{{ featureAccessLevelMembers[1] }}</option
>
<option
:value="featureAccessLevelEveryone[0]"
:disabled="!visibilityAllowed(visibilityOptions.PUBLIC)"
>{{ featureAccessLevelEveryone[1] }}</option
>
</select>
<gl-icon
name="chevron-down"
data-hidden="true"
class="gl-absolute gl-top-3 gl-right-3 gl-text-gray-500"
/>
</div>
</div>
</project-setting-row>
</div>
</div>
<project-setting-row v-if="canDisableEmails" ref="email-settings" class="mb-3">
<label class="js-emails-disabled">
<input :value="emailsDisabled" type="hidden" name="project[emails_disabled]" />
......
---
title: Add toggle to disable Operations in settings
merge_request: 49919
author:
type: added
......@@ -21862,6 +21862,9 @@ msgstr ""
msgid "ProjectSettings|Encourage"
msgstr ""
msgid "ProjectSettings|Environments, logs, cluster management, and more"
msgstr ""
msgid "ProjectSettings|Every merge creates a merge commit"
msgstr ""
......@@ -21946,6 +21949,9 @@ msgstr ""
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
msgid "ProjectSettings|Operations"
msgstr ""
msgid "ProjectSettings|Packages"
msgstr ""
......
......@@ -9,6 +9,7 @@ describe('Project Feature Settings', () => {
options: [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]],
value: 1,
disabledInput: false,
showToggle: true,
};
let wrapper;
......@@ -40,6 +41,14 @@ describe('Project Feature Settings', () => {
});
describe('Feature toggle', () => {
it('should be hidden if "showToggle" is passed false', async () => {
wrapper.setProps({ showToggle: false });
await wrapper.vm.$nextTick();
expect(wrapper.find(projectFeatureToggle).element).toBeUndefined();
});
it('should enable the feature toggle if the value is not 0', () => {
expect(wrapper.find(projectFeatureToggle).props().value).toBe(true);
});
......
......@@ -20,6 +20,7 @@ const defaultProps = {
buildsAccessLevel: 20,
wikiAccessLevel: 20,
snippetsAccessLevel: 20,
operationsAccessLevel: 20,
pagesAccessLevel: 10,
analyticsAccessLevel: 20,
containerRegistryEnabled: true,
......@@ -68,8 +69,12 @@ describe('Settings Panel', () => {
});
};
const overrideCurrentSettings = (currentSettingsProps, extraProps = {}) => {
return mountComponent({ ...extraProps, currentSettings: currentSettingsProps });
const overrideCurrentSettings = (
currentSettingsProps,
extraProps = {},
mountFn = shallowMount,
) => {
return mountComponent({ ...extraProps, currentSettings: currentSettingsProps }, mountFn);
};
const findLFSSettingsRow = () => wrapper.find({ ref: 'git-lfs-settings' });
......@@ -523,28 +528,30 @@ describe('Settings Panel', () => {
});
});
it('should set the visibility level description based upon the selected visibility level', () => {
wrapper
.find('[name="project[project_feature_attributes][metrics_dashboard_access_level]"]')
.setValue(visibilityOptions.PUBLIC);
expect(wrapper.vm.metricsDashboardAccessLevel).toBe(visibilityOptions.PUBLIC);
});
it('should contain help text', () => {
expect(wrapper.find({ ref: 'metrics-visibility-settings' }).props().helpText).toBe(
'With Metrics Dashboard you can visualize this project performance metrics',
);
});
it('should disable the metrics visibility dropdown when the project visibility level changes to private', () => {
wrapper = overrideCurrentSettings({ visibilityLevel: visibilityOptions.PRIVATE });
it.each`
scenario | selectedOption | selectedOptionLabel
${{ visibilityLevel: visibilityOptions.PRIVATE }} | ${String(featureAccessLevel.PROJECT_MEMBERS)} | ${'Only Project Members'}
${{ operationsAccessLevel: featureAccessLevel.NOT_ENABLED }} | ${String(featureAccessLevel.NOT_ENABLED)} | ${'Enable feature to choose access level'}
`(
'should disable the metrics visibility dropdown when #scenario',
({ scenario, selectedOption, selectedOptionLabel }) => {
wrapper = overrideCurrentSettings(scenario, {}, mount);
const metricsSettingsRow = wrapper.find({ ref: 'metrics-visibility-settings' });
const select = wrapper.find({ ref: 'metrics-visibility-settings' }).find('select');
const option = select.find('option');
expect(wrapper.vm.metricsOptionsDropdownEnabled).toBe(true);
expect(metricsSettingsRow.find('select').attributes('disabled')).toBe('disabled');
});
expect(select.attributes('disabled')).toBe('disabled');
expect(select.element.value).toBe(selectedOption);
expect(option.attributes('value')).toBe(selectedOption);
expect(option.text()).toBe(selectedOptionLabel);
},
);
});
describe('Settings panel with feature flags', () => {
......@@ -568,4 +575,12 @@ describe('Settings Panel', () => {
expect(findAnalyticsRow().exists()).toBe(true);
});
});
describe('Operations', () => {
it('should show the operations toggle', async () => {
await wrapper.vm.$nextTick();
expect(wrapper.find({ ref: 'operations-settings' }).exists()).toBe(true);
});
});
});
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