Skip to content

Commit

Permalink
feat: apply API at notification create page (#5266)
Browse files Browse the repository at this point in the history
* fix: fixed type error

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

* feat: create notification protocol list at notification create page

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

* feat: apply API at notification create page

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 19, 2024
1 parent 8dedae3 commit f9d7b50
Show file tree
Hide file tree
Showing 13 changed files with 512 additions and 127 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<script setup lang="ts">
import { computed, reactive, watch } from 'vue';
import { zipObject } from 'lodash';
import {
PFieldGroup, PLazyImg, PTextInput, PRadioGroup, PRadio, PPaneLayout,
} from '@cloudforet/mirinae';
import type { NotificationProtocolModel } from '@/schema/alert-manager/notification-protocol/model';
import type { ServiceChannelScheduleDayType } from '@/schema/alert-manager/service-channel/type';
import { i18n } from '@/translations';
import { assetUrlConverter } from '@/lib/helper/asset-helper';
import ScheduleSettingForm from '@/common/components/schedule-setting-form/ScheduleSettingForm.vue';
import { useFormValidator } from '@/common/composables/form-validator';
import type { SelectedUserDropdownIdsType } from '@/common/modules/user/typte';
import UserSelectDropdown from '@/common/modules/user/UserSelectDropdown.vue';
import { useServiceCreateFormStore } from '@/services/alert-manager-v2/stores/service-create-form-store';
import type { CreatedNotificationInfoType, UserRadioType } from '@/services/alert-manager-v2/types/alert-manager-type';
import type { ScheduleDayType, ScheduleForm } from '@/services/alert-manager-v2/types/schedule-setting-form';
const serviceFormStore = useServiceCreateFormStore();
const serviceFormState = serviceFormStore.state;
const storeState = reactive({
selectedProtocolType: computed<NotificationProtocolModel|undefined>(() => serviceFormState.selectedProtocol),
});
const state = reactive({
scheduleForm: {} as ScheduleForm,
radioMenuList: computed<UserRadioType[]>(() => ([
{
label: i18n.t('BILLING.COST_MANAGEMENT.BUDGET.DETAIL.MODAL.ALL_MEMBER'),
name: 'ALL_MEMBER',
},
{
label: i18n.t('BILLING.COST_MANAGEMENT.BUDGET.DETAIL.MODAL.USER_GROUP'),
name: 'USER_GROUP',
},
{
label: i18n.t('BILLING.COST_MANAGEMENT.BUDGET.DETAIL.MODAL.SPECIFIC_USER'),
name: 'USER',
},
])),
selectedRadioIdx: 0,
selectedMemberItems: [] as SelectedUserDropdownIdsType[],
});
const emit = defineEmits<{(e: 'change-form', form: CreatedNotificationInfoType): void}>();
const {
forms: {
name,
},
setForm,
invalidState,
invalidTexts,
} = useFormValidator({
name: '',
}, {
name(value: string) {
if (value.length >= 40) {
return i18n.t('ALERT_MANAGER.WEBHOOK.VALIDATION_NAME_MAX');
}
return '';
},
});
const handleScheduleForm = (form: ScheduleForm) => {
state.scheduleForm = form;
};
const handleChangeRadio = () => {
state.selectedMemberItems = [];
};
const createScheduleMap = (scheduleForm: ScheduleForm): Record<ScheduleDayType, ServiceChannelScheduleDayType> => {
const allDays: ScheduleDayType[] = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'];
const { days, start, end } = scheduleForm;
const refinedDays = allDays.map((day) => ({
is_schedule: days.includes(day),
start,
end,
}));
return zipObject(allDays, refinedDays) as Record<ScheduleDayType, ServiceChannelScheduleDayType>;
};
watch([() => name.value, () => state.scheduleForm, () => state.selectedRadioIdx, () => state.selectedMemberItems], ([nameVal, scheduleForm, selectedRadioIdx, selectedMemberItems]) => {
emit('change-form', {
name: nameVal,
schedule: {
SCHEDULE_TYPE: scheduleForm.type,
...createScheduleMap(scheduleForm),
},
data: {
FORWARD_TYPE: state.radioMenuList[selectedRadioIdx].name,
USER_GROUP: selectedRadioIdx === 1 ? selectedMemberItems.map((item) => item.value) : undefined,
USER: selectedRadioIdx === 2 ? selectedMemberItems.map((item) => item.value) : undefined,
},
});
});
</script>

<template>
<div class="notification-schedule-form">
<div v-if="storeState.selectedProtocolType"
class="protocol-item"
>
<p-lazy-img :src="assetUrlConverter(storeState.selectedProtocolType?.tags?.icon || '')"
width="4rem"
height="4rem"
error-icon="ic_webhook"
/>
<div class="info">
<p class="text-label-xl">
{{ storeState.selectedProtocolType?.name }}
</p>
<p class="text-label-sm text-gray-600">
{{ storeState.selectedProtocolType?.tags?.long_description || storeState.selectedProtocolType?.tags?.description }}
</p>
</div>
</div>
<p-field-group :label="$t('ALERT_MANAGER.NOTIFICATIONS.CHANNEL_NAME')"
class="pt-2"
:invalid-text="invalidTexts.name"
:invalid="invalidState.name"
required
>
<template #default="{invalid}">
<p-text-input :value="name"
block
:invalid="invalid"
class="mb-2"
@update:value="setForm('name', $event)"
/>
</template>
</p-field-group>
<p-field-group :label="$t('ALERT_MANAGER.NOTIFICATIONS.USER')"
required
>
<template #default>
<div class="flex flex-col mt-1 gap-2">
<p-radio-group>
<p-radio v-for="(item, idx) in state.radioMenuList"
:key="`notification-scope-${idx}`"
v-model="state.selectedRadioIdx"
:value="idx"
@change="handleChangeRadio"
>
<span class="radio-item">
{{ item.label }}
</span>
</p-radio>
</p-radio-group>
<user-select-dropdown v-if="state.selectedRadioIdx !== 0"
selection-type="multiple"
appearance-type="stack"
use-fixed-menu-style
:show-category-title="false"
:show-user-group-list="state.selectedRadioIdx === 1"
:show-user-list="state.selectedRadioIdx === 2"
:selected-ids.sync="state.selectedMemberItems"
/>
</div>
</template>
</p-field-group>
<div class="pt-2">
<p-pane-layout class="pt-8 px-4 pb-4">
<p class="pb-4 text-display-md">
{{ $t('ALERT_MANAGER.NOTIFICATIONS.SCHEDULE') }}
</p>
<schedule-setting-form @schedule-form="handleScheduleForm" />
</p-pane-layout>
</div>
</div>
</template>

<style lang="postcss" scoped>
.notification-schedule-form {
.protocol-item {
@apply flex items-center w-full;
margin-bottom: 1.5rem;
gap: 1rem;
.info {
@apply flex flex-col;
gap: 0.125rem;
flex: 1;
}
}
}
</style>
Original file line number Diff line number Diff line change
@@ -1,67 +1,110 @@
<script setup lang="ts">
import { reactive } from 'vue';
import { computed, onMounted, reactive } from 'vue';
import { SpaceConnector } from '@cloudforet/core-lib/space-connector';
import {
PSelectCard, PLazyImg,
PSelectCard, PLazyImg, PDataLoader,
} from '@cloudforet/mirinae';
import type { ListResponse } from '@/schema/_common/api-verbs/list';
import type { NotificationProtocolListParameters } from '@/schema/alert-manager/notification-protocol/api-verbs/list';
import type { NotificationProtocolModel } from '@/schema/alert-manager/notification-protocol/model';
import { useAllReferenceStore } from '@/store/reference/all-reference-store';
import type { PluginReferenceMap } from '@/store/reference/plugin-reference-store';
import { assetUrlConverter } from '@/lib/helper/asset-helper';
import ErrorHandler from '@/common/composables/error/errorHandler';
import { useServiceCreateFormStore } from '@/services/alert-manager-v2/stores/service-create-form-store';
interface ProtocolCardItemType extends NotificationProtocolModel {
icon: string;
}
const serviceFormStore = useServiceCreateFormStore();
const allReferenceStore = useAllReferenceStore();
const allReferenceGetters = allReferenceStore.getters;
const storeState = reactive({
plugins: computed<PluginReferenceMap>(() => allReferenceGetters.plugin),
});
const state = reactive({
// TODO: temp data
protocolList: [
{
icon: 'ic_notification-protocol_envelope',
label: 'email',
},
],
selectedProtocol: {},
loading: false,
protocolList: [] as NotificationProtocolModel[],
protocolCardList: computed<ProtocolCardItemType>(() => state.protocolList.map((item) => ({
...item,
icon: storeState.plugins[item.plugin_id]?.icon || '',
}))),
selectedProtocol: {} as NotificationProtocolModel,
});
const handleSelectProtocol = () => {
serviceFormStore.setSelectedProtocol({ protocol_id: 'temp_id' });
serviceFormStore.setSelectedProtocol(state.selectedProtocol);
};
const fetchNotificationProtocolList = async () => {
state.loading = true;
try {
const { results } = await SpaceConnector.clientV2.alertManager.notificationProtocol.list<NotificationProtocolListParameters, ListResponse<NotificationProtocolModel>>();
state.protocolList = results || [];
} catch (e) {
ErrorHandler.handleError(e, true);
state.protocolList = [];
} finally {
state.loading = false;
}
};
onMounted(() => {
fetchNotificationProtocolList();
});
</script>

<template>
<div class="service-create-step3-select-protocol">
<p-select-card v-for="(item, index) in state.protocolList"
:key="`protocol-${index}`"
v-model="state.selectedProtocol"
:value="item"
class="card"
@change="handleSelectProtocol"
>
<div class="card-item">
<p-lazy-img :src="assetUrlConverter(item.icon)"
width="2.5rem"
height="2.5rem"
error-icon="ic_notification-protocol_envelope"
class="image"
/>
<p>{{ item.label }}</p>
</div>
</p-select-card>
</div>
<p-data-loader class="service-create-step3-select-protocol"
:loading="state.loading"
:data="state.protocolList"
>
<div class="contents">
<p-select-card v-for="(item, index) in state.protocolCardList"
:key="`protocol-${index}`"
v-model="state.selectedProtocol"
:value="item"
:show-select-marker="false"
class="card"
@change="handleSelectProtocol"
>
<div class="card-item">
<p-lazy-img :src="assetUrlConverter(item.icon)"
width="2.5rem"
height="2.5rem"
class="image"
/>
<p class="text-label-md font-bold">
{{ item.name }}
</p>
</div>
</p-select-card>
</div>
</p-data-loader>
</template>

<style scoped lang="postcss">
.service-create-step3-select-protocol {
@apply grid grid-cols-3;
gap: 0.5rem;
.card {
width: 19.5rem;
padding: 1rem;
.card-item {
@apply flex items-center w-full;
gap: 0.75rem;
.image {
margin-bottom: 0;
.contents {
@apply grid grid-cols-3;
gap: 0.5rem;
.card {
width: 19.5rem;
padding: 1rem;
.card-item {
@apply flex items-center w-full;
gap: 0.75rem;
.image {
margin-bottom: 0;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const storeState = reactive({
});
const state = reactive({
selectedWebhook: undefined,
selectedNotifications: [],
selectedNotifications: undefined,
});
watch(() => tabState.activeTab, (activeTab) => {
Expand Down Expand Up @@ -88,10 +88,10 @@ onUnmounted(() => {
</template>
</p-horizontal-layout>
<service-detail-tabs-webhook-detail-tabs v-if="state.selectedWebhook"
:selected-webhook="state.selectedWebhook"
:selected-id="state.selectedWebhook"
/>
<service-detail-tabs-notifications-detail-tabs v-else-if="state.selectedNotifications[0]"
:selected-notifications="state.selectedNotifications[0]"
<service-detail-tabs-notifications-detail-tabs v-else-if="state.selectedNotifications"
:selected-id="state.selectedNotifications"
/>
</div>
<p-tab v-else
Expand Down
Loading

0 comments on commit f9d7b50

Please sign in to comment.