Skip to content
Snippets Groups Projects
Commit 99d1de2b authored by Lorenz van Herwaarden's avatar Lorenz van Herwaarden
Browse files

Show rule button tooltip for merge request approval policy

This makes sure the Add rule button in the merge request approval
policy editor is not hidden when hitting the limit, but instead
disabled, with a tooltip.

Changelog: changed
EE: true
parent eb9602ca
No related branches found
No related tags found
1 merge request!174036Show rule button tooltip for merge request approval policy
<script>
import { isEmpty } from 'lodash';
import { GlAlert, GlEmptyState, GlButton } from '@gitlab/ui';
import { GlAlert, GlTooltipDirective, GlEmptyState, GlButton } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { setUrlFragment } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
import { __, s__, n__, sprintf } from '~/locale';
import {
extractPolicyContent,
isGroup,
......@@ -97,6 +97,9 @@ export default {
botActionTooltip: s__(
'SecurityOrchestration|Merge request approval policies allow a maximum 1 bot message action.',
),
exceedingRulesMessage: s__(
'SecurityOrchestration|You can add a maximum of %{rulesCount} %{rules}.',
),
},
components: {
ActionSection,
......@@ -111,6 +114,7 @@ export default {
ScanFilterSelector,
SettingsSection,
},
directives: { GlTooltip: GlTooltipDirective },
apollo: {
linkedSppGroups: {
query: getSppLinkedProjectsGroups,
......@@ -257,6 +261,13 @@ export default {
isWithinLimit() {
return this.policy.rules?.length < MAX_ALLOWED_RULES_LENGTH;
},
addRuleTitle() {
const rules = n__('rule', 'rules', this.policy.rules?.length);
return sprintf(this.$options.i18n.exceedingRulesMessage, {
rulesCount: MAX_ALLOWED_RULES_LENGTH,
rules,
});
},
hasRequireApprovalAction() {
return this.policy.actions?.some(({ type }) => type === REQUIRE_APPROVAL_TYPE);
},
......@@ -535,13 +546,23 @@ export default {
@remove="removeRule(index)"
/>
<div
v-if="isWithinLimit"
class="security-policies-bg-subtle gl-mb-5 gl-rounded-base gl-p-5"
>
<gl-button variant="link" data-testid="add-rule" @click="addRule">
{{ $options.ADD_RULE_LABEL }}
</gl-button>
<div class="security-policies-bg-subtle gl-mb-5 gl-rounded-base gl-p-5">
<span
v-gl-tooltip="{
disabled: isWithinLimit,
title: addRuleTitle,
}"
data-testid="add-rule-wrapper"
>
<gl-button
variant="link"
data-testid="add-rule"
:disabled="!isWithinLimit"
@click="addRule"
>
{{ $options.ADD_RULE_LABEL }}
</gl-button>
</span>
</div>
</dim-disable-container>
</template>
......
......@@ -3,6 +3,7 @@ import VueApollo from 'vue-apollo';
import { GlEmptyState } from '@gitlab/ui';
import { uniqueId } from 'lodash';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'helpers/mock_apollo_helper';
import getSppLinkedProjectsGroups from 'ee/security_orchestration/graphql/queries/get_spp_linked_projects_groups.graphql';
......@@ -97,6 +98,9 @@ describe('EditorComponent', () => {
handler = mockLinkedSppItemsResponse(),
} = {}) => {
wrapper = shallowMountExtended(EditorComponent, {
directives: {
GlTooltip: createMockDirective('gl-tooltip'),
},
apolloProvider: createMockApolloProvider(handler),
propsData: {
assignedPolicyProject: DEFAULT_ASSIGNED_POLICY_PROJECT,
......@@ -148,6 +152,8 @@ describe('EditorComponent', () => {
const findActionSection = () => wrapper.findComponent(ActionSection);
const findAllActionSections = () => wrapper.findAllComponents(ActionSection);
const findAddRuleButton = () => wrapper.findByTestId('add-rule');
const findTooltip = () =>
getBinding(wrapper.findByTestId('add-rule-wrapper').element, 'gl-tooltip');
const findAllDisabledComponents = () => wrapper.findAllComponents(DimDisableContainer);
const findAllRuleSections = () => wrapper.findAllComponents(RuleSection);
const findSettingsSection = () => wrapper.findComponent(SettingsSection);
......@@ -278,13 +284,23 @@ describe('EditorComponent', () => {
expect(findAllRuleSections()).toHaveLength(rulesCount + 1);
});
it('hides add button when the limit of five rules has been reached', () => {
it('shows correct label for add rule button', () => {
factory();
expect(findAddRuleButton().text()).toBe('Add new rule');
expect(findAddRuleButton().props('disabled')).toBe(false);
expect(findTooltip().value.disabled).toBe(true);
});
it('disables add button when the limit of 5 rules has been reached', () => {
const limit = 5;
const { id, ...rule } = mockDefaultBranchesScanResultObject.rules[0];
uniqueId.mockRestore();
factoryWithExistingPolicy({ policy: { rules: [rule, rule, rule, rule, rule] } });
expect(findAllRuleSections()).toHaveLength(limit);
expect(findAddRuleButton().exists()).toBe(false);
expect(findAddRuleButton().props('disabled')).toBe(true);
expect(findTooltip().value).toMatchObject({
disabled: false,
title: 'You can add a maximum of 5 rules.',
});
});
it('updates an existing rule', async () => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment