Commit e8893853 authored by Tristan Read's avatar Tristan Read Committed by Illya Klymov

Add help link for escalation status dropdown

Changelog: changed
EE: true
parent 0d52bf56
...@@ -21,6 +21,11 @@ export default { ...@@ -21,6 +21,11 @@ export default {
return [...STATUS_LIST, null].includes(value); return [...STATUS_LIST, null].includes(value);
}, },
}, },
preventDropdownClose: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
currentStatusLabel() { currentStatusLabel() {
...@@ -35,6 +40,11 @@ export default { ...@@ -35,6 +40,11 @@ export default {
this.$refs.dropdown.hide(); this.$refs.dropdown.hide();
}, },
getStatusLabel, getStatusLabel,
hideDropdown(event) {
if (this.preventDropdownClose) {
event.preventDefault();
}
},
}, },
}; };
</script> </script>
...@@ -45,6 +55,7 @@ export default { ...@@ -45,6 +55,7 @@ export default {
block block
:text="currentStatusLabel" :text="currentStatusLabel"
toggle-class="dropdown-menu-toggle gl-mb-2" toggle-class="dropdown-menu-toggle gl-mb-2"
@hide="hideDropdown"
> >
<slot name="header"> </slot> <slot name="header"> </slot>
<gl-dropdown-item <gl-dropdown-item
......
...@@ -20,4 +20,6 @@ export const i18nStatusText = { ...@@ -20,4 +20,6 @@ export const i18nStatusText = {
dropdownInfo: s__( dropdownInfo: s__(
'IncidentManagement|Setting the status to Acknowledged or Resolved stops paging when escalation policies are selected for the incident.', 'IncidentManagement|Setting the status to Acknowledged or Resolved stops paging when escalation policies are selected for the incident.',
), ),
learnMoreShort: __('Learn More.'),
learnMoreFull: s__('IncidentManagement|Learn more about incident statuses'),
}; };
<script> <script>
import { GlDropdownDivider, GlDropdownSectionHeader, GlIcon, GlPopover } from '@gitlab/ui'; import { GlDropdownDivider, GlDropdownSectionHeader, GlIcon, GlLink, GlPopover } from '@gitlab/ui';
import EscalationStatus from '~/sidebar/components/incidents/escalation_status.vue'; import EscalationStatus from '~/sidebar/components/incidents/escalation_status.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { helpPagePath } from '~/helpers/help_page_helper';
import { i18nStatusText } from './constants'; import { i18nStatusText } from './constants';
export default { export default {
i18n: i18nStatusText, i18n: i18nStatusText,
docsPath: helpPagePath('operations/incident_management/incidents.html', {
anchor: 'change-incident-status',
}),
components: { components: {
EscalationStatus, EscalationStatus,
GlDropdownDivider, GlDropdownDivider,
GlDropdownSectionHeader, GlDropdownSectionHeader,
GlIcon, GlIcon,
GlPopover, GlPopover,
GlLink,
}, },
mixins: [glFeatureFlagMixin()], mixins: [glFeatureFlagMixin()],
data() {
return { isHelpVisible: false };
},
computed: { computed: {
showHeader() { showHeader() {
return this.glFeatures.escalationPolicies; return this.glFeatures.escalationPolicies;
...@@ -28,24 +36,48 @@ export default { ...@@ -28,24 +36,48 @@ export default {
hide() { hide() {
this.$refs.escalationStatus.hide(); this.$refs.escalationStatus.hide();
}, },
showPopover() {
this.isHelpVisible = true;
},
hidePopover() {
this.isHelpVisible = false;
},
}, },
}; };
</script> </script>
<template> <template>
<escalation-status ref="escalationStatus" v-bind="$attrs" v-on="$listeners"> <escalation-status
ref="escalationStatus"
v-bind="$attrs"
:prevent-dropdown-close="isHelpVisible"
v-on="$listeners"
>
<template v-if="showHeader" #header> <template v-if="showHeader" #header>
<gl-dropdown-section-header class="gl-mt-n2"> <gl-dropdown-section-header id="escalation-status-dropdown" class="gl-mt-n2">
<div class="gl-text-center"> <div class="gl-text-center">
{{ $options.i18n.dropdownHeader }} {{ $options.i18n.dropdownHeader }}
<gl-icon id="escalation-status-help" class="gl-ml-2 gl-text-blue-600" name="question-o" /> <gl-icon id="escalation-status-help" class="gl-ml-2 gl-text-blue-600" name="question-o" />
<gl-popover <gl-popover
:content="$options.i18n.dropdownInfo" ref="popover"
:title="$options.i18n.dropdownHeader" :title="$options.i18n.dropdownHeader"
boundary="viewport"
placement="left" placement="left"
target="escalation-status-help" target="escalation-status-help"
/> boundary="viewport"
@show="showPopover"
@hide="hidePopover"
>
<p @click.stop.prevent>{{ $options.i18n.dropdownInfo }}</p>
<gl-link
ref="link"
:aria-label="$options.i18n.learnMoreFull"
class="gl-font-sm"
:href="$options.docsPath"
target="_blank"
>
{{ $options.i18n.learnMoreShort }}
</gl-link>
</gl-popover>
</div> </div>
</gl-dropdown-section-header> </gl-dropdown-section-header>
<gl-dropdown-divider /> <gl-dropdown-divider />
......
import { GlDropdownSectionHeader, GlPopover } from '@gitlab/ui'; import { GlDropdownSectionHeader, GlPopover, GlLink } from '@gitlab/ui';
import { nextTick } from 'vue';
import { mountExtended } from 'helpers/vue_test_utils_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper';
import EscalationStatus from 'ee/sidebar/components/incidents/escalation_status.vue'; import EscalationStatus from 'ee/sidebar/components/incidents/escalation_status.vue';
import { STATUS_TRIGGERED } from '~/sidebar/components/incidents/constants'; import { STATUS_TRIGGERED } from '~/sidebar/components/incidents/constants';
...@@ -28,16 +29,49 @@ describe('EscalationStatus', () => { ...@@ -28,16 +29,49 @@ describe('EscalationStatus', () => {
const findDropdownHeaderComponent = () => wrapper.findComponent(GlDropdownSectionHeader); const findDropdownHeaderComponent = () => wrapper.findComponent(GlDropdownSectionHeader);
const findPopover = () => wrapper.findComponent(GlPopover); const findPopover = () => wrapper.findComponent(GlPopover);
const findLearnMoreLink = () => wrapper.findComponent(GlLink);
const findInnerStatusComponent = () => wrapper.findComponent({ ref: 'escalationStatus' }); const findInnerStatusComponent = () => wrapper.findComponent({ ref: 'escalationStatus' });
const openPopover = async () => {
describe('popover', () => { await findPopover().vm.$emit('show');
it('renders a popover', () => { await nextTick();
};
const closePopover = async () => {
await findPopover().vm.$emit('hide');
await nextTick();
};
describe('help popover', () => {
beforeEach(() => {
createComponent(); createComponent();
});
it('renders a popover', () => {
expect(findPopover().props('title')).toBe('Assign paging status'); expect(findPopover().props('title')).toBe('Assign paging status');
expect(findPopover().attributes('content')).toContain('Setting the status'); expect(findPopover().text()).toContain('Setting the status');
});
it('shows the Learn More link', () => {
expect(findLearnMoreLink().text()).toBe('Learn More.');
expect(findLearnMoreLink().attributes('href')).toContain(
'incidents.html#change-incident-status',
);
});
it('prevents self from being removed from DOM when open', async () => {
await openPopover();
expect(findInnerStatusComponent().props('preventDropdownClose')).toBe(true);
});
it('allows self to be removed from DOM when closed', async () => {
await openPopover();
await closePopover();
expect(findInnerStatusComponent().props('preventDropdownClose')).toBe(false);
});
}); });
describe('dropdown', () => {
it('forwards `show` calls to the child', () => { it('forwards `show` calls to the child', () => {
createComponent(); createComponent();
......
...@@ -19784,6 +19784,9 @@ msgstr "" ...@@ -19784,6 +19784,9 @@ msgstr ""
msgid "IncidentManagement|Incidents" msgid "IncidentManagement|Incidents"
msgstr "" msgstr ""
msgid "IncidentManagement|Learn more about incident statuses"
msgstr ""
msgid "IncidentManagement|Low - S4" msgid "IncidentManagement|Low - S4"
msgstr "" msgstr ""
......
import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import waitForPromises from 'helpers/wait_for_promises';
import { mountExtended } from 'helpers/vue_test_utils_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper';
import EscalationStatus from '~/sidebar/components/incidents/escalation_status.vue'; import EscalationStatus from '~/sidebar/components/incidents/escalation_status.vue';
import { import {
...@@ -25,6 +26,11 @@ describe('EscalationStatus', () => { ...@@ -25,6 +26,11 @@ describe('EscalationStatus', () => {
const findDropdownComponent = () => wrapper.findComponent(GlDropdown); const findDropdownComponent = () => wrapper.findComponent(GlDropdown);
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem); const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
const findDropdownMenu = () => findDropdownComponent().find('.dropdown-menu');
const toggleDropdown = async () => {
await findDropdownComponent().findComponent('button').trigger('click');
await waitForPromises();
};
describe('status', () => { describe('status', () => {
it('shows the current status', () => { it('shows the current status', () => {
...@@ -49,4 +55,32 @@ describe('EscalationStatus', () => { ...@@ -49,4 +55,32 @@ describe('EscalationStatus', () => {
expect(wrapper.emitted().input[0][0]).toBe(STATUS_ACKNOWLEDGED); expect(wrapper.emitted().input[0][0]).toBe(STATUS_ACKNOWLEDGED);
}); });
}); });
describe('close behavior', () => {
it('allows the dropdown to be closed by default', async () => {
createComponent();
// Open dropdown
await toggleDropdown();
expect(findDropdownMenu().classes('show')).toBe(true);
// Attempt to close dropdown
await toggleDropdown();
expect(findDropdownMenu().classes('show')).toBe(false);
});
it('preventDropdownClose prevents the dropdown from closing', async () => {
createComponent({ preventDropdownClose: true });
// Open dropdown
await toggleDropdown();
expect(findDropdownMenu().classes('show')).toBe(true);
// Attempt to close dropdown
await toggleDropdown();
expect(findDropdownMenu().classes('show')).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