Skip to content

Commit

Permalink
feat: apply escalation policy API (#5304)
Browse files Browse the repository at this point in the history
* feat: apply escalation policy create API

Signed-off-by: NaYeong,Kim <[email protected]>

* feat: create update / delete / state modal

Signed-off-by: NaYeong,Kim <[email protected]>

* chore: fixed minor issue (note, props name)

Signed-off-by: NaYeong,Kim <[email protected]>

* chore: update translations

Signed-off-by: NaYeong,Kim <[email protected]>

---------

Signed-off-by: NaYeong,Kim <[email protected]>
  • Loading branch information
skdud4659 authored Dec 23, 2024
1 parent 3d9ca7f commit fd2758d
Show file tree
Hide file tree
Showing 17 changed files with 938 additions and 612 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
PButton,
PSelectDropdown,
PHeadingLayout,
PBadge,
PI,
} from '@cloudforet/mirinae';
import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/type';
import { iso8601Formatter } from '@cloudforet/utils';
Expand All @@ -26,8 +28,14 @@ import { useUserStore } from '@/store/user/user-store';
import ErrorHandler from '@/common/composables/error/errorHandler';
import { useQueryTags } from '@/common/composables/query-tags';
import { green } from '@/styles/colors';
import ServiceDetailTabsSettingsEscalationPolicyDeleteModal
from '@/services/alert-manager-v2/components/ServiceDetailTabsSettingsEscalationPolicyDeleteModal.vue';
import ServiceDetailTabsSettingsEscalationPolicyFormModal
from '@/services/alert-manager-v2/components/ServiceDetailTabsSettingsEscalationPolicyFormModal.vue';
import ServiceDetailTabsSettingsEscalationPolicyStateModal
from '@/services/alert-manager-v2/components/ServiceDetailTabsSettingsEscalationPolicyStateModal.vue';
import {
ESCALATION_POLICY_MANAGEMENT_TABLE_FIELDS, ESCALATION_POLICY_MANAGEMENT_TABLE_HANDLER,
} from '@/services/alert-manager-v2/constants/escalation-policy-table-constant';
Expand All @@ -43,19 +51,21 @@ const tableState = reactive({
actionMenu: computed<MenuItem[]>(() => ([
{
type: 'item',
name: 'use',
name: 'STATE',
label: _i18n.t('ALERT_MANAGER.ESCALATION_POLICY.IN_USE'),
disabled: state.selectedItem?.escalation_policy_id === storeState.defaultEscalationPolicyId,
},
{
type: 'item',
name: 'delete',
name: 'DELETE',
label: _i18n.t('ALERT_MANAGER.DELETE'),
},
])),
fields: ESCALATION_POLICY_MANAGEMENT_TABLE_FIELDS,
});
const storeState = reactive({
serviceId: computed<string>(() => serviceDetailPageState.serviceInfo.service_id),
defaultEscalationPolicyId: computed<string>(() => serviceDetailPageState.serviceInfo.escalation_policy_id),
timezone: computed<string>(() => userState.timezone || ''),
});
const state = reactive({
Expand All @@ -80,13 +90,10 @@ const getConnectChannelCount = (rules: EscalationPolicyRulesType[]) => {
const uniqueChannels = new Set(allChannels);
return uniqueChannels.size;
};
const handleClickCreateButton = (type: EscalationPolicyModalType) => {
const handleActionModal = (type: EscalationPolicyModalType) => {
modalState.visible = true;
modalState.type = type;
};
const handleSelectDropdownItem = (name) => {
console.log('TODO: handleSelectDropdownItem', name);
};
const handleChangeToolbox = async (options: any = {}) => {
if (options.queryTags !== undefined) queryTagHelper.setQueryTags(options.queryTags);
if (options.pageStart !== undefined) escalationPolicyListApiQueryHelper.setPageStart(options.pageStart);
Expand All @@ -99,6 +106,10 @@ const handleExportExcel = () => {
const handleSelectTableRow = (selectedItems: number[]) => {
state.selectIndex = selectedItems[0];
};
const handleCloseModal = () => {
handleChangeToolbox();
state.selectIndex = undefined;
};
const fetchEscalationPolicyList = async () => {
state.loading = true;
Expand Down Expand Up @@ -139,7 +150,7 @@ watch(() => storeState.serviceId, (id) => {
:total-count="state.totalCount"
:items="state.items"
:fields="tableState.fields"
:select-index="state.selectIndex"
:select-index="[state.selectIndex]"
:query-tags="queryTags"
:key-item-sets="ESCALATION_POLICY_MANAGEMENT_TABLE_HANDLER.keyItemSets"
:value-handler-map="ESCALATION_POLICY_MANAGEMENT_TABLE_HANDLER.valueHandlerMap"
Expand All @@ -161,14 +172,15 @@ watch(() => storeState.serviceId, (id) => {
<p-button style-type="tertiary"
icon-left="ic_settings-filled"
size="sm"
@click="handleClickCreateButton('SET')"
:disabled="!state.selectedItem"
@click="handleActionModal('UPDATE')"
>
{{ $t('ALERT_MANAGER.ESCALATION_POLICY.SET_POLICY') }}
</p-button>
<p-button style-type="primary"
icon-left="ic_plus_bold"
size="sm"
@click="handleClickCreateButton('CREATE')"
@click="handleActionModal('CREATE')"
>
{{ $t('ALERT_MANAGER.CREATE') }}
</p-button>
Expand All @@ -177,14 +189,32 @@ watch(() => storeState.serviceId, (id) => {
</template>
<template #toolbox-left>
<p-select-dropdown :menu="tableState.actionMenu"
:disabled="!state.selectIndex"
:disabled="!state.selectedItem"
reset-selection-on-menu-close
:placeholder="$t('ALERT_MANAGER.ACTION')"
@select="handleSelectDropdownItem"
@select="handleActionModal"
/>
</template>
<template #col-name-format="{value, item}">
<div>
<span>{{ value }}</span>
<p-badge v-if="item.escalation_policy_id === storeState.defaultEscalationPolicyId"
style-type="safe"
badge-type="solid-outline"
class="ml-2"
>
<p-i name="ic_circle"
width="0.75rem"
height="0.75rem"
:color="green[500]"
class="mr-1"
/>
{{ $t('ALERT_MANAGER.ESCALATION_POLICY.IN_USE') }}
</p-badge>
</div>
</template>
<template #col-repeat-format="{value}">
{{ value || 0 }}
{{ value?.count || 0 }}
</template>
<template #col-rules-format="{value}">
{{ getConnectChannelCount(value) }}
Expand All @@ -193,9 +223,24 @@ watch(() => storeState.serviceId, (id) => {
{{ iso8601Formatter(value, storeState.timezone) }}
</template>
</p-toolbox-table>
<service-detail-tabs-settings-escalation-policy-form-modal :visible="modalState.visible"
:type="modalState.type"
/>
<div v-if="modalState.visible">
<service-detail-tabs-settings-escalation-policy-form-modal v-if="modalState.type === 'CREATE' || modalState.type === 'UPDATE'"
:visible.sync="modalState.visible"
:type="modalState.type"
:selected-item="state.selectedItem"
@close="handleCloseModal"
/>
<service-detail-tabs-settings-escalation-policy-state-modal v-if="modalState.type === 'STATE'"
:visible.sync="modalState.visible"
:selected-item="state.selectedItem"
@close="handleCloseModal"
/>
<service-detail-tabs-settings-escalation-policy-delete-modal v-if="modalState.type === 'DELETE'"
:visible.sync="modalState.visible"
:selected-item="state.selectedItem"
@close="handleCloseModal"
/>
</div>
</div>
</template>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<script lang="ts" setup>
import {
reactive,
} from 'vue';
import { SpaceConnector } from '@cloudforet/core-lib/space-connector';
import {
PButtonModal,
} from '@cloudforet/mirinae';
import type { EscalationPolicyDeleteParameters } from '@/schema/alert-manager/escalation-policy/api-verbs/delete';
import type { EscalationPolicyModel } from '@/schema/alert-manager/escalation-policy/model';
import ErrorHandler from '@/common/composables/error/errorHandler';
import { useProxyValue } from '@/common/composables/proxy-state';
interface Props {
visible: boolean;
selectedItem: EscalationPolicyModel;
}
const props = withDefaults(defineProps<Props>(), {
visible: false,
selectedItem: undefined,
});
const emit = defineEmits<{(e: 'update:visible'): void;
(e: 'close'): void;
}>();
const state = reactive({
loading: false,
proxyVisible: useProxyValue<boolean>('visible', props, emit),
});
const handleClose = () => {
state.proxyVisible = false;
emit('close');
};
const handleConfirm = async () => {
state.loading = true;
try {
await SpaceConnector.clientV2.alertManager.escalationPolicy.delete<EscalationPolicyDeleteParameters>({
escalation_policy_id: props.selectedItem.escalation_policy_id,
});
handleClose();
} catch (e) {
ErrorHandler.handleError(e, true);
} finally {
state.loading = false;
}
};
</script>
<template>
<p-button-modal class="service-detail-tabs-settings-escalation-policy-delete-modal"
:visible="state.proxyVisible"
:header-title="$t('ALERT_MANAGER.ESCALATION_POLICY.MODAL_DELETE_TITLE')"
:loading="state.loading"
theme-color="alert"
size="sm"
@confirm="handleConfirm"
@cancel="handleClose"
@close="handleClose"
>
<template #confirm-button>
{{ $t('ALERT_MANAGER.ESCALATION_POLICY.MODAL_DELETE_BUTTON') }}
</template>
</p-button-modal>
</template>
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script setup lang="ts">
import { reactive } from 'vue';
import { cloneDeep } from 'lodash';
import {
Expand All @@ -7,69 +9,50 @@ import {
import type { EscalationPolicyRulesType } from '@/schema/alert-manager/escalation-policy/type';
import { useFormValidator } from '@/common/composables/form-validator';
import { useProxyValue } from '@/common/composables/proxy-state';
import { gray } from '@/styles/colors';
import ServiceDetailTabsSettingsEscalationPolicyFormChannelDropdown
from '@/services/alert-manager-v2/components/ServiceDetailTabsSettingsEscalationPolicyFormChannelDropdown.vue';
const {
forms: {
repeatCount,
rules,
},
setForm,
invalidState,
invalidTexts,
} = useFormValidator({
interface Props {
rules: EscalationPolicyRulesType[];
repeatCount: number;
}
const props = withDefaults(defineProps<Props>(), {
rules: undefined,
repeatCount: 0,
rules: [{
channels: [],
escalate_minutes: 30,
}] as EscalationPolicyRulesType[],
}, {
repeatCount(value) {
if (value === undefined) return true;
if (Number.isNaN(value) || typeof value !== 'number') return 'Only numbers are allowed.';
if (value < 0) return 'Must be 0 or greater.';
return true;
},
rules(value: EscalationPolicyRulesType[]) {
let result = '';
value.forEach((d, idx) => {
if (!repeatCount.value && idx === value.length - 1) return;
if (d?.escalate_minutes === undefined) result = 'Only numbers are allowed.';
else if (d?.escalate_minutes < 0) result = 'Must be 0 or greater.';
});
return result;
},
});
const emit = defineEmits<{(event: 'update:rules', rules: EscalationPolicyRulesType[]): void;
(event: 'update:repeat-count', rules: EscalationPolicyRulesType[]): void;
}>();
const state = reactive({
proxyRules: useProxyValue('rules', props, emit),
proxyRepeatCount: useProxyValue('repeatCount', props, emit),
});
const handleSelectChannelDropdown = (idx: number, ids: string[]) => {
state.proxyRules[idx].channels = ids;
};
const handleDeleteRule = (idx: number) => {
const _rules = cloneDeep(rules.value);
const _rules = cloneDeep(state.proxyRules);
_rules.splice(idx, 1);
if (_rules.length > 0 && !repeatCount.value) _rules[_rules.length - 1].escalate_minutes = 30;
setForm('rules', _rules);
state.proxyRules = _rules;
};
const handleAddStep = () => {
const _rules = cloneDeep(rules.value);
if (_rules.length > 0 && !repeatCount.value) _rules[_rules.length - 1].escalate_minutes = 30;
const _rules = cloneDeep(state.proxyRules);
_rules.push({
channels: [],
escalate_minutes: 30,
});
setForm('rules', _rules);
state.proxyRules = _rules;
};
const handleUpdateRepeatCount = (_repeatCount: number) => {
const _after = Number(_repeatCount);
const _before = repeatCount.value;
const _rules = cloneDeep(rules.value);
//
if (!_before && _after > 0) _rules[_rules.length - 1].escalate_minutes = 30;
if (!_after) _rules[_rules.length - 1].escalate_minutes = 30;
setForm('rules', _rules);
setForm('repeatCount', _after);
const handleUpdateRepeatCount = (_repeatCount: string) => {
state.proxyRepeatCount = Number(_repeatCount);
};
</script>
Expand All @@ -82,12 +65,10 @@ const handleUpdateRepeatCount = (_repeatCount: number) => {
height="1.25rem"
/>
<p-field-group required
:invalid="invalidState.repeatCount"
:invalid-text="invalidTexts.repeatCount"
class="repeat-form"
>
<template #default="{invalid}">
<p-text-input :value="repeatCount"
<p-text-input :value="state.proxyRepeatCount"
type="number"
:min="0"
block
Expand All @@ -107,12 +88,12 @@ const handleUpdateRepeatCount = (_repeatCount: number) => {
shape="square"
name="ic_plus_bold"
style-type="tertiary"
:disabled="rules.length >= 5"
:disabled="state.proxyRules.length >= 5"
@click="handleAddStep"
/>
</div>
<div class="py-4 px-6">
<p-card v-for="(rule, idx) in rules"
<p-card v-for="(rule, idx) in state.proxyRules"
:key="`rule-${idx}`"
class="card"
>
Expand All @@ -129,7 +110,7 @@ const handleUpdateRepeatCount = (_repeatCount: number) => {
>
{{ $t('ALERT_MANAGER.ESCALATION_POLICY.STEP', { step: idx + 1}) }}
</p-badge>
<p-icon-button v-if="rules.length > 1"
<p-icon-button v-if="state.proxyRules.length > 1"
class="ml-auto"
name="ic_delete"
size="sm"
Expand All @@ -156,7 +137,10 @@ const handleUpdateRepeatCount = (_repeatCount: number) => {
</p-field-group>
</template>
</i18n>
<service-detail-tabs-settings-escalation-policy-form-channel-dropdown class="mt-2" />
<service-detail-tabs-settings-escalation-policy-form-channel-dropdown class="mt-2"
:selected-ids="rule.channels"
@update:selected-ids="handleSelectChannelDropdown(idx, $event)"
/>
</p-card>
<p-text-button class="add-rule-button mt-4 mx-auto "
icon-left="ic_plus_bold"
Expand Down
Loading

0 comments on commit fd2758d

Please sign in to comment.