Skip to content

Commit

Permalink
feat: create alert creation modal (#5241)
Browse files Browse the repository at this point in the history
* refactor: move the API call function to the store action

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

* feat: create alert creation modal

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

* refactor: apply the service dropdown list in the store

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

* chore: update translations

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

* refactor: refactor alert management table code

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

---------

Signed-off-by: NaYeong,Kim <[email protected]>
  • Loading branch information
skdud4659 authored Dec 17, 2024
1 parent 47dcd0c commit bf9bbdf
Show file tree
Hide file tree
Showing 11 changed files with 339 additions and 122 deletions.
175 changes: 175 additions & 0 deletions apps/web/src/services/alert-manager-v2/components/AlertCreateModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<script setup lang="ts">
import { computed, onMounted, reactive } from 'vue';
import { SpaceConnector } from '@cloudforet/core-lib/space-connector';
import {
PButtonModal, PFieldGroup, PTextInput, PTextarea, PSelectDropdown, PRadioGroup, PRadio,
} from '@cloudforet/mirinae';
import type { SelectDropdownMenuItem } from '@cloudforet/mirinae/types/controls/dropdown/select-dropdown/type';
import type { AlertCreateParameters } from '@/schema/alert-manager/alert/api-verbs/create';
import { ALERT_URGENCY } from '@/schema/alert-manager/alert/constants';
import type { AlertModel } from '@/schema/alert-manager/alert/model';
import { i18n } from '@/translations';
import ErrorHandler from '@/common/composables/error/errorHandler';
import { useFormValidator } from '@/common/composables/form-validator';
import { useProxyValue } from '@/common/composables/proxy-state';
import { useAlertPageStore } from '@/services/alert-manager-v2/stores/alert-page-store';
import type { AlertUrgencyRadioType } from '@/services/alert-manager-v2/types/alert-manager-type';
interface Props {
visible: boolean;
}
const props = withDefaults(defineProps<Props>(), {
visible: false,
});
const alertPageStore = useAlertPageStore();
const alertPageState = alertPageStore.state;
const emit = defineEmits<{(e: 'update:visible'): void; }>();
const storeState = reactive({
serviceDropdownList: computed<SelectDropdownMenuItem[]>(() => alertPageState.serviceList),
});
const state = reactive({
loading: false,
proxyVisible: useProxyValue('visible', props, emit),
alertList: [] as AlertModel[],
selectedServiceId: '',
radioMenuList: computed<AlertUrgencyRadioType[]>(() => [
{
label: i18n.t('ALERT_MANAGER.ALERTS.HIGH'),
name: ALERT_URGENCY.HIGH,
},
{
label: i18n.t('ALERT_MANAGER.ALERTS.LOW'),
name: ALERT_URGENCY.HIGH,
},
]),
selectedRadioIdx: 0,
});
const {
forms: {
name,
description,
},
setForm,
invalidState,
invalidTexts,
isAllValid,
} = useFormValidator({
name: '',
description: '',
}, {
name(value: string) {
if (!value) return ' ';
const duplicatedName = state.alertList?.find((item) => item.title === value);
if (duplicatedName) {
return i18n.t('ALERT_MANAGER.ALERTS.VALIDATION_NAME_UNIQUE');
}
return '';
},
});
const handleConfirm = async () => {
state.loading = true;
try {
await SpaceConnector.clientV2.alertManager.alert.create<AlertCreateParameters, AlertModel>({
title: name.value,
description: description.value,
service_id: state.selectedServiceId,
urgency: state.radioMenuList[state.selectedRadioIdx].name,
});
} finally {
state.loading = false;
handleClose();
}
};
const handleClose = () => {
state.proxyVisible = false;
};
const fetchAlertsList = async () => {
try {
state.alertList = await alertPageStore.fetchAlertsList();
} catch (e) {
ErrorHandler.handleError(e, true);
state.alertList = [];
}
};
onMounted(() => {
fetchAlertsList();
});
</script>

<template>
<p-button-modal class="alert-create-modal"
:header-title="$t('ALERT_MANAGER.ALERTS.CREATE_ALERT')"
size="sm"
:fade="true"
:backdrop="true"
:visible="state.proxyVisible"
:disabled="!isAllValid || !state.selectedServiceId"
:loading="state.loading"
@confirm="handleConfirm"
@cancel="handleClose"
@close="handleClose"
>
<template #body>
<div class="form-contents">
<p-field-group :label="$t('ALERT_MANAGER.ALERTS.LABEL_NAME')"
:invalid="invalidState.name"
:invalid-text="invalidTexts.name"
class="input-form"
required
>
<p-text-input :value="name"
:invalid="invalidState.name"
block
@update:value="setForm('name', $event)"
/>
</p-field-group>
<p-field-group :label="$t('ALERT_MANAGER.ALERTS.LABEL_URGENCY')"
required
>
<p-radio-group>
<p-radio v-for="(item, idx) in state.radioMenuList"
:key="`bookmark-scope-${idx}`"
v-model="state.selectedRadioIdx"
:value="idx"
>
<span class="radio-item">
{{ item.label }}
</span>
</p-radio>
</p-radio-group>
</p-field-group>
<p-field-group :label="$t('ALERT_MANAGER.ALERTS.SERVICE')"
required
>
<p-select-dropdown :menu="storeState.serviceDropdownList"
use-fixed-menu-style
block
show-delete-all-button
:selected.sync="state.selectedServiceId"
/>
</p-field-group>
<p-field-group :label="$t('ALERT_MANAGER.ALERTS.DESC')"
class="input-form"
>
<p-textarea :value="description"
block
@update:value="setForm('description', $event)"
/>
</p-field-group>
</div>
</template>
</p-button-modal>
</template>
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
<script setup lang="ts">
import { computed, onMounted, reactive } from 'vue';
import {
makeDistinctValueHandler,
makeEnumValueHandler,
} from '@cloudforet/core-lib/component-util/query-search';
import type { ConsoleFilter } from '@cloudforet/core-lib/query/type';
import { SpaceConnector } from '@cloudforet/core-lib/space-connector';
import { ApiQueryHelper } from '@cloudforet/core-lib/space-connector/helper';
import {
PToolboxTable, PSelectDropdown, PLink, PBadge, PI, PSelectStatus,
} from '@cloudforet/mirinae';
import type { DataTableFieldType } from '@cloudforet/mirinae/src/data-display/tables/data-table/type';
import { ACTION_ICON } from '@cloudforet/mirinae/src/navigation/link/type';
import type { SelectDropdownMenuItem } from '@cloudforet/mirinae/types/controls/dropdown/select-dropdown/type';
import type { KeyItemSet, ValueHandlerMap } from '@cloudforet/mirinae/types/controls/search/query-search/type';
import type { ListResponse } from '@/schema/_common/api-verbs/list';
import type { AlertListParameters } from '@/schema/alert-manager/alert/api-verbs/list';
import { ALERT_URGENCY } from '@/schema/alert-manager/alert/constants';
import type { AlertModel } from '@/schema/alert-manager/alert/model';
import type { ServiceListParameters } from '@/schema/alert-manager/service/api-verbs/list';
import type { ServiceModel } from '@/schema/alert-manager/service/model';
import { i18n } from '@/translations';
import { referenceRouter } from '@/lib/reference/referenceRouter';
Expand All @@ -32,54 +21,31 @@ import { useProperRouteLocation } from '@/common/composables/proper-route-locati
import { red } from '@/styles/colors';
import { getAlertStateI18n, getAlertUrgencyI18n } from '@/services/alert-manager-v2/composables/alert-table-data';
import { ALERT_STATUS_FILTERS } from '@/services/alert-manager-v2/constants/alert-manager-constant';
import {
ALERT_MANAGEMENT_TABLE_FIELDS,
ALERT_MANAGEMENT_TABLE_HANDLER,
ALERT_STATUS_FILTERS,
} from '@/services/alert-manager-v2/constants/alert-management-table-constant';
import { alertStateBadgeStyleTypeFormatter } from '@/services/alert-manager-v2/helpers/alert-badge-helper';
import { ALERT_MANAGER_ROUTE_V2 } from '@/services/alert-manager-v2/routes/route-constant';
import { useAlertPageStore } from '@/services/alert-manager-v2/stores/alert-page-store';
import type { AlertFilterType } from '@/services/alert-manager-v2/types/alert-manager-type';
const alertPageStore = useAlertPageStore();
const alertPageState = alertPageStore.state;
const { getProperRouteLocation } = useProperRouteLocation();
const tableState = reactive({
fields: computed<DataTableFieldType[]>(() => ([
{ name: 'alert_number', label: 'No' },
{ name: 'title', label: 'Title', width: '20rem' },
{ name: 'state', label: 'Status' },
{ name: 'service_id', label: 'Service' },
{ name: 'urgency', label: 'Urgency' },
{ name: 'category', label: 'Category' },
{ name: 'resources', label: 'Resource', width: '20rem' },
{ name: 'updated_by', label: 'Updated by' },
{ name: 'resolved_by', label: 'Resolved by' },
{ name: 'acknowledged by', label: 'Acknowledged by' },
])),
keyItemSets: computed<KeyItemSet[]>(() => [{
title: 'Properties',
items: [
{ name: 'alert_id', label: 'Alert ID' },
{ name: 'title', label: 'Title' },
{ name: 'state', label: 'Status' },
{ name: 'service_id', label: 'Service' },
{ name: 'category', label: 'Category' },
{ name: 'resource.resource_type', label: 'Resource Name' },
],
}]),
valueHandlerMap: computed<ValueHandlerMap>(() => ({
alert_id: makeDistinctValueHandler('alertManager.Alert', 'alert_id'),
title: makeDistinctValueHandler('alertManager.Alert', 'title'),
state: makeEnumValueHandler(ALERT_URGENCY),
service: makeDistinctValueHandler('alertManager.Alert', 'service_id'),
category: makeDistinctValueHandler('alertManager.Alert', 'category'),
'resource.resource_type': makeDistinctValueHandler('alertManager.Alert', 'resource.resource_type'),
})),
const storeState = reactive({
serviceDropdownList: computed<SelectDropdownMenuItem[]>(() => alertPageState.serviceList),
});
const state = reactive({
loading: false,
items: [] as AlertModel[],
alertList: [] as AlertModel[],
alertStateLabels: getAlertStateI18n(),
urgencyLabels: getAlertUrgencyI18n(),
});
const filterState = reactive({
serviceDropdownList: [] as SelectDropdownMenuItem[],
selectedServiceId: '',
statusFields: computed<AlertFilterType[]>(() => ([
{ label: i18n.t('ALERT_MANAGER.ALERTS.ALL'), name: 'ALL' },
Expand All @@ -100,7 +66,7 @@ const filterState = reactive({
const handleSelectServiceDropdownItem = (id: string) => {
filterState.selectedServiceId = id;
fetchServiceList();
fetchAlertsList();
};
const handleSelectFilter = (type: 'status' | 'urgency', value: string) => {
if (type === 'status') {
Expand All @@ -120,21 +86,6 @@ const handleExportToExcel = () => {
console.log('TODO: handleExportToExcel');
};
const fetchServiceList = async () => {
try {
const { results } = await SpaceConnector.clientV2.alertManager.service.list<ServiceListParameters, ListResponse<ServiceModel>>({
service_id: filterState.selectedServiceId === '' ? undefined : filterState.selectedServiceId,
});
filterState.serviceDropdownList = (results || []).map((i) => ({
name: i.service_id,
label: i.name,
}));
} catch (e) {
ErrorHandler.handleError(e, true);
filterState.serviceDropdownList = [];
}
};
const alertListApiQuery = new ApiQueryHelper().setSort('created_at', true);
const fetchAlertsList = async () => {
try {
Expand All @@ -149,6 +100,7 @@ const fetchAlertsList = async () => {
alertListApiQuery.setFilters([
...stateFilter,
...urgencyFilter,
{ k: 'service_id', v: filterState.selectedServiceId, o: '=' },
]);
if (filterState.selectedStatusFilter === ALERT_STATUS_FILTERS.OPEN) {
alertListApiQuery.setOrFilters([
Expand All @@ -158,20 +110,19 @@ const fetchAlertsList = async () => {
} else {
alertListApiQuery.setOrFilters([]);
}
const { results } = await SpaceConnector.clientV2.alertManager.alert.list<AlertListParameters, ListResponse<AlertModel>>({
state.alertList = await alertPageStore.fetchAlertsList({
query: alertListApiQuery.data,
});
state.items = results || [];
} catch (e) {
ErrorHandler.handleError(e, true);
state.items = [];
state.alertList = [];
}
};
onMounted(async () => {
try {
state.loading = true;
await fetchServiceList();
await alertPageStore.fetchServiceList();
await fetchAlertsList();
} finally {
state.loading = false;
Expand All @@ -189,18 +140,18 @@ onMounted(async () => {
sort-by="created_at"
:sort-desc="true"
:loading="state.loading"
:fields="tableState.fields"
:items="state.items"
:key-item-sets="tableState.keyItemSets"
:value-handler-map="tableState.valueHandlerMap"
:fields="ALERT_MANAGEMENT_TABLE_FIELDS"
:items="state.alertList"
:key-item-sets="ALERT_MANAGEMENT_TABLE_HANDLER.keyItemSets"
:value-handler-map="ALERT_MANAGEMENT_TABLE_HANDLER.valueHandlerMap"
settings-visible
@change="handleChange"
@click-settings="handleClickSettings"
@refresh="fetchAlertsList"
@export="handleExportToExcel"
>
<template #toolbox-top>
<p-select-dropdown :menu="filterState.serviceDropdownList"
<p-select-dropdown :menu="storeState.serviceDropdownList"
:selection-label="$t('ALERT_MANAGER.ALERTS.SERVICE')"
style-type="rounded"
use-fixed-menu-style
Expand Down
Loading

0 comments on commit bf9bbdf

Please sign in to comment.