Commit 542e8c90 authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

Merge branch 'tr-fix-escalation-policy-parsing' into 'master'

Convert minutes to seconds for escalation policies

See merge request gitlab-org/gitlab!64977
parents b8c70280 744fb186
...@@ -76,13 +76,13 @@ export default { ...@@ -76,13 +76,13 @@ export default {
this.rules = this.form.rules.map((rule) => { this.rules = this.form.rules.map((rule) => {
const { const {
status, status,
elapsedTimeSeconds, elapsedTimeMinutes,
oncallSchedule: { iid: oncallScheduleIid }, oncallSchedule: { iid: oncallScheduleIid },
} = rule; } = rule;
return { return {
status, status,
elapsedTimeSeconds, elapsedTimeMinutes,
action: DEFAULT_ACTION, action: DEFAULT_ACTION,
oncallScheduleIid, oncallScheduleIid,
key: uniqueId(), key: uniqueId(),
......
...@@ -9,7 +9,7 @@ import { ...@@ -9,7 +9,7 @@ import {
import createEscalationPolicyMutation from '../graphql/mutations/create_escalation_policy.mutation.graphql'; import createEscalationPolicyMutation from '../graphql/mutations/create_escalation_policy.mutation.graphql';
import updateEscalationPolicyMutation from '../graphql/mutations/update_escalation_policy.mutation.graphql'; import updateEscalationPolicyMutation from '../graphql/mutations/update_escalation_policy.mutation.graphql';
import getEscalationPoliciesQuery from '../graphql/queries/get_escalation_policies.query.graphql'; import getEscalationPoliciesQuery from '../graphql/queries/get_escalation_policies.query.graphql';
import { isNameFieldValid, getRulesValidationState } from '../utils'; import { isNameFieldValid, getRulesValidationState, serializeRule } from '../utils';
import AddEditEscalationPolicyForm from './add_edit_escalation_policy_form.vue'; import AddEditEscalationPolicyForm from './add_edit_escalation_policy_form.vue';
export const i18n = { export const i18n = {
...@@ -91,7 +91,7 @@ export default { ...@@ -91,7 +91,7 @@ export default {
}, },
requestParams() { requestParams() {
const id = this.isEditMode ? { id: this.escalationPolicy.id } : {}; const id = this.isEditMode ? { id: this.escalationPolicy.id } : {};
return { ...this.form, ...id, rules: this.getRules(this.form.rules) }; return { ...this.form, ...id, rules: this.getRules(this.form.rules).map(serializeRule) };
}, },
}, },
methods: { methods: {
...@@ -186,9 +186,9 @@ export default { ...@@ -186,9 +186,9 @@ export default {
}, },
getRules(rules) { getRules(rules) {
return rules.map( return rules.map(
({ status, elapsedTimeSeconds, oncallScheduleIid, oncallSchedule: { iid } = {} }) => ({ ({ status, elapsedTimeMinutes, oncallScheduleIid, oncallSchedule: { iid } = {} }) => ({
status, status,
elapsedTimeSeconds, elapsedTimeMinutes,
oncallScheduleIid: oncallScheduleIid || iid, oncallScheduleIid: oncallScheduleIid || iid,
}), }),
); );
......
...@@ -4,6 +4,7 @@ import * as Sentry from '@sentry/browser'; ...@@ -4,6 +4,7 @@ import * as Sentry from '@sentry/browser';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { addEscalationPolicyModalId } from '../constants'; import { addEscalationPolicyModalId } from '../constants';
import getEscalationPoliciesQuery from '../graphql/queries/get_escalation_policies.query.graphql'; import getEscalationPoliciesQuery from '../graphql/queries/get_escalation_policies.query.graphql';
import { parsePolicy } from '../utils';
import AddEscalationPolicyModal from './add_edit_escalation_policy_modal.vue'; import AddEscalationPolicyModal from './add_edit_escalation_policy_modal.vue';
import EscalationPolicy from './escalation_policy.vue'; import EscalationPolicy from './escalation_policy.vue';
...@@ -47,7 +48,7 @@ export default { ...@@ -47,7 +48,7 @@ export default {
}; };
}, },
update({ project }) { update({ project }) {
return project?.incidentManagementEscalationPolicies?.nodes ?? []; return project?.incidentManagementEscalationPolicies?.nodes.map(parsePolicy) ?? [];
}, },
error(error) { error(error) {
Sentry.captureException(error); Sentry.captureException(error);
......
...@@ -29,9 +29,9 @@ export const i18n = { ...@@ -29,9 +29,9 @@ export const i18n = {
minutes: s__('EscalationPolicies|mins'), minutes: s__('EscalationPolicies|mins'),
}; };
const isRuleValid = ({ status, elapsedTimeSeconds, oncallSchedule: { name } }) => const isRuleValid = ({ status, elapsedTimeMinutes, oncallSchedule: { name } }) =>
Object.keys(ALERT_STATUSES).includes(status) && Object.keys(ALERT_STATUSES).includes(status) &&
typeof elapsedTimeSeconds === 'number' && typeof elapsedTimeMinutes === 'number' &&
typeof name === 'string'; typeof name === 'string';
export default { export default {
...@@ -145,7 +145,7 @@ export default { ...@@ -145,7 +145,7 @@ export default {
</template> </template>
<template #minutes> <template #minutes>
<span class="gl-font-weight-bold"> <span class="gl-font-weight-bold">
{{ rule.elapsedTimeSeconds }} {{ $options.i18n.minutes }} {{ rule.elapsedTimeMinutes }} {{ $options.i18n.minutes }}
</span> </span>
</template> </template>
<template #then> <template #then>
......
...@@ -76,10 +76,10 @@ export default { ...@@ -76,10 +76,10 @@ export default {
}, },
}, },
data() { data() {
const { status, elapsedTimeSeconds, action, oncallScheduleIid } = this.rule; const { status, elapsedTimeMinutes, action, oncallScheduleIid } = this.rule;
return { return {
status, status,
elapsedTimeSeconds, elapsedTimeMinutes,
action, action,
oncallScheduleIid, oncallScheduleIid,
}; };
...@@ -119,7 +119,7 @@ export default { ...@@ -119,7 +119,7 @@ export default {
oncallScheduleIid: parseInt(this.oncallScheduleIid, 10), oncallScheduleIid: parseInt(this.oncallScheduleIid, 10),
action: this.action, action: this.action,
status: this.status, status: this.status,
elapsedTimeSeconds: parseInt(this.elapsedTimeSeconds, 10), elapsedTimeMinutes: this.elapsedTimeMinutes,
}, },
}); });
}, },
...@@ -169,9 +169,9 @@ export default { ...@@ -169,9 +169,9 @@ export default {
</template> </template>
<template #minutes> <template #minutes>
<gl-form-input <gl-form-input
v-model="elapsedTimeSeconds" v-model="elapsedTimeMinutes"
class="gl-mx-3 gl-inset-border-1-gray-200! gl-w-12" class="gl-mx-3 gl-inset-border-1-gray-200! gl-w-12"
type="number" number
min="0" min="0"
@input="emitUpdate" @input="emitUpdate"
/> />
......
...@@ -13,7 +13,7 @@ export const ACTIONS = { ...@@ -13,7 +13,7 @@ export const ACTIONS = {
export const DEFAULT_ESCALATION_RULE = { export const DEFAULT_ESCALATION_RULE = {
status: 'ACKNOWLEDGED', status: 'ACKNOWLEDGED',
elapsedTimeSeconds: 0, elapsedTimeMinutes: 0,
action: 'EMAIL_ONCALL_SCHEDULE_USER', action: 'EMAIL_ONCALL_SCHEDULE_USER',
oncallScheduleIid: null, oncallScheduleIid: null,
}; };
......
...@@ -17,8 +17,33 @@ export const isNameFieldValid = (name) => { ...@@ -17,8 +17,33 @@ export const isNameFieldValid = (name) => {
export const getRulesValidationState = (rules) => { export const getRulesValidationState = (rules) => {
return rules.map((rule) => { return rules.map((rule) => {
return { return {
isTimeValid: parseInt(rule.elapsedTimeSeconds, 10) >= 0, isTimeValid: parseInt(rule.elapsedTimeMinutes, 10) >= 0,
isScheduleValid: Boolean(rule.oncallScheduleIid), isScheduleValid: Boolean(rule.oncallScheduleIid),
}; };
}); });
}; };
/**
* Serializes a rule by converting elapsed minutes to seconds
* @param {Object} rule
*
* @returns {Object} rule
*/
export const serializeRule = ({ elapsedTimeMinutes, ...ruleParams }) => ({
...ruleParams,
elapsedTimeSeconds: elapsedTimeMinutes * 60,
});
/**
* Parses a policy by converting elapsed seconds to minutes
* @param {Object} policy
*
* @returns {Object} policy
*/
export const parsePolicy = (policy) => ({
...policy,
rules: policy.rules.map(({ elapsedTimeSeconds, ...ruleParams }) => ({
...ruleParams,
elapsedTimeMinutes: elapsedTimeSeconds / 60,
})),
});
...@@ -38,7 +38,7 @@ exports[`EscalationPolicy renders policy with rules 1`] = ` ...@@ -38,7 +38,7 @@ exports[`EscalationPolicy renders policy with rules 1`] = `
class="gl-font-weight-bold" class="gl-font-weight-bold"
> >
10 mins 1 mins
</span> </span>
...@@ -81,7 +81,7 @@ exports[`EscalationPolicy renders policy with rules 1`] = ` ...@@ -81,7 +81,7 @@ exports[`EscalationPolicy renders policy with rules 1`] = `
class="gl-font-weight-bold" class="gl-font-weight-bold"
> >
20 mins 2 mins
</span> </span>
......
...@@ -82,7 +82,7 @@ describe('AddEscalationPolicyForm', () => { ...@@ -82,7 +82,7 @@ describe('AddEscalationPolicyForm', () => {
it('on rule update emitted should update rules array and emit updates up', () => { it('on rule update emitted should update rules array and emit updates up', () => {
const updatedRule = { const updatedRule = {
status: 'TRIGGERED', status: 'TRIGGERED',
elapsedTimeSeconds: 30, elapsedTimeMinutes: 3,
oncallScheduleIid: 2, oncallScheduleIid: 2,
}; };
findRules().at(0).vm.$emit('update-escalation-rule', { index: 0, rule: updatedRule }); findRules().at(0).vm.$emit('update-escalation-rule', { index: 0, rule: updatedRule });
......
...@@ -23,7 +23,8 @@ describe('AddEditsEscalationPolicyModal', () => { ...@@ -23,7 +23,8 @@ describe('AddEditsEscalationPolicyModal', () => {
const mockEscalationPolicy = cloneDeep(mockPolicies[0]); const mockEscalationPolicy = cloneDeep(mockPolicies[0]);
const updatedName = 'Policy name'; const updatedName = 'Policy name';
const updatedDescription = 'Policy description'; const updatedDescription = 'Policy description';
const updatedRules = [{ status: 'RESOLVED', elapsedTimeSeconds: 10, oncallScheduleIid: 1 }]; const updatedRules = [{ status: 'RESOLVED', elapsedTimeMinutes: 1, oncallScheduleIid: 1 }];
const serializedRules = [{ status: 'RESOLVED', elapsedTimeSeconds: 60, oncallScheduleIid: 1 }];
const createComponent = ({ escalationPolicy, isEditMode = false, modalId, data } = {}) => { const createComponent = ({ escalationPolicy, isEditMode = false, modalId, data } = {}) => {
wrapper = shallowMount(AddEscalationPolicyModal, { wrapper = shallowMount(AddEscalationPolicyModal, {
...@@ -99,7 +100,7 @@ describe('AddEditsEscalationPolicyModal', () => { ...@@ -99,7 +100,7 @@ describe('AddEditsEscalationPolicyModal', () => {
projectPath, projectPath,
name: updatedName, name: updatedName,
description: updatedDescription, description: updatedDescription,
rules: updatedRules, rules: serializedRules,
}, },
}, },
update: expect.any(Function), update: expect.any(Function),
...@@ -168,7 +169,7 @@ describe('AddEditsEscalationPolicyModal', () => { ...@@ -168,7 +169,7 @@ describe('AddEditsEscalationPolicyModal', () => {
input: { input: {
name: updatedName, name: updatedName,
description: updatedDescription, description: updatedDescription,
rules: updatedRules, rules: serializedRules,
id: mockEscalationPolicy.id, id: mockEscalationPolicy.id,
}, },
}, },
...@@ -264,7 +265,7 @@ describe('AddEditsEscalationPolicyModal', () => { ...@@ -264,7 +265,7 @@ describe('AddEditsEscalationPolicyModal', () => {
}); });
form.vm.$emit('update-escalation-policy-form', { form.vm.$emit('update-escalation-policy-form', {
field: 'rules', field: 'rules',
value: [{ status: 'RESOLVED', elapsedTimeSeconds: 10, oncallScheduleIid: 1 }], value: [{ status: 'RESOLVED', elapsedTimeMinutes: 1, oncallScheduleIid: 1 }],
}); });
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
expect(findModal().props('actionPrimary').attributes).toContainEqual({ disabled: false }); expect(findModal().props('actionPrimary').attributes).toContainEqual({ disabled: false });
......
...@@ -9,11 +9,12 @@ import { ...@@ -9,11 +9,12 @@ import {
deleteEscalationPolicyModalId, deleteEscalationPolicyModalId,
editEscalationPolicyModalId, editEscalationPolicyModalId,
} from 'ee/escalation_policies/constants'; } from 'ee/escalation_policies/constants';
import { parsePolicy } from 'ee/escalation_policies/utils';
import mockPolicies from './mocks/mockPolicies.json'; import mockPolicies from './mocks/mockPolicies.json';
describe('EscalationPolicy', () => { describe('EscalationPolicy', () => {
let wrapper; let wrapper;
const escalationPolicy = cloneDeep(mockPolicies[0]); const escalationPolicy = parsePolicy(cloneDeep(mockPolicies[0]));
const createComponent = () => { const createComponent = () => {
wrapper = shallowMount(EscalationPolicy, { wrapper = shallowMount(EscalationPolicy, {
......
import { GlEmptyState, GlLoadingIcon } from '@gitlab/ui'; import { GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
import EscalationPoliciesWrapper from 'ee/escalation_policies/components/escalation_policies_wrapper.vue'; import EscalationPoliciesWrapper from 'ee/escalation_policies/components/escalation_policies_wrapper.vue';
import EscalationPolicy from 'ee/escalation_policies/components/escalation_policy.vue'; import EscalationPolicy from 'ee/escalation_policies/components/escalation_policy.vue';
import { parsePolicy } from 'ee/escalation_policies/utils';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import mockEscalationPolicies from './mocks/mockPolicies.json'; import mockEscalationPolicies from './mocks/mockPolicies.json';
...@@ -55,7 +56,7 @@ describe('Escalation Policies Wrapper', () => { ...@@ -55,7 +56,7 @@ describe('Escalation Policies Wrapper', () => {
beforeEach(() => { beforeEach(() => {
mountComponent({ mountComponent({
loading, loading,
escalationPolicies, escalationPolicies: escalationPolicies.map(parsePolicy),
}); });
}); });
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
{ {
"id": "gid://gitlab/IncidentManagement::EscalationRule/22", "id": "gid://gitlab/IncidentManagement::EscalationRule/22",
"status": "ACKNOWLEDGED", "status": "ACKNOWLEDGED",
"elapsedTimeSeconds": 10, "elapsedTimeSeconds": 60,
"oncallSchedule": { "oncallSchedule": {
"iid": "3", "iid": "3",
"name": "Schedule to fill in" "name": "Schedule to fill in"
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
{ {
"id": "gid://gitlab/IncidentManagement::EscalationRule/23", "id": "gid://gitlab/IncidentManagement::EscalationRule/23",
"status": "RESOLVED", "status": "RESOLVED",
"elapsedTimeSeconds": 20, "elapsedTimeSeconds": 120,
"oncallSchedule": { "oncallSchedule": {
"iid": "4", "iid": "4",
"name": "Monitor schedule" "name": "Monitor schedule"
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
{ {
"id": "gid://gitlab/IncidentManagement::EscalationRule/48", "id": "gid://gitlab/IncidentManagement::EscalationRule/48",
"status": "ACKNOWLEDGED", "status": "ACKNOWLEDGED",
"elapsedTimeSeconds": 30, "elapsedTimeSeconds": 180,
"oncallSchedule": { "oncallSchedule": {
"iid": "3", "iid": "3",
"name": "Schedule to fill in" "name": "Schedule to fill in"
......
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