Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
62686a9
ci: add check for PR author organization membership and assign them (…
WANZARGEN Jan 14, 2025
650544b
chore: ci test (#5522)
WANZARGEN Jan 14, 2025
cb18f69
fix(reference-store): correct logic for selecting fetcher based on ve…
sulmoJ Jan 16, 2025
62a23c5
Merge remote-tracking branch 'cloudforet-io/develop' into feature-pro…
sulmoJ Jan 16, 2025
e4a1654
chore: changed css (#5537)
skdud4659 Jan 16, 2025
5b89589
Merge branch 'develop' into feature-project-alert-manager
skdud4659 Jan 16, 2025
c7713fa
Merge branch 'develop' into feature-project-alert-manager
skdud4659 Jan 16, 2025
8c8be52
feat: apply qa and additional requests (#5552)
skdud4659 Jan 17, 2025
28645a4
fix: fixed qa bug (#5554)
skdud4659 Jan 17, 2025
5ab319c
feat: apply sort (#5555)
skdud4659 Jan 17, 2025
6e9f04e
Merge remote-tracking branch 'cloudforet-io/develop' into feature-pro…
skdud4659 Jan 20, 2025
c2c7618
feat: apply qa issue (#5569)
seungyeoneeee Jan 20, 2025
cc1607d
feat: apply minor qa issue (#5580)
skdud4659 Jan 21, 2025
e08da5f
Merge remote-tracking branch 'cloudforet-io/develop' into feature-pro…
skdud4659 Jan 21, 2025
487aa43
feat: update Alert Public Page with V2 & apply qa issue (#5572)
seungyeoneeee Jan 21, 2025
7a01ba4
Merge remote-tracking branch 'cloudforet-io/develop' into feature-pro…
skdud4659 Jan 21, 2025
48430ca
feat: apply message overlay (#5583)
skdud4659 Jan 21, 2025
f36f8ab
feat: apply qa issue (#5584)
seungyeoneeee Jan 22, 2025
34a7d50
feat: apply minor qa (#5589)
skdud4659 Jan 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ const stopPairInit = watch(() => props.pairs, (pairs) => {
width: 15rem;
}
.value {
@apply inline-block font-bold;
@apply inline-block font-bold pl-2;
width: 20rem;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ const handleSelectDropdown = (type: 'start' | 'end', value: number) => {
}
};

const areDayArraysEqual = (selectedDayButton: DayType[], compareDays: DayType[]) => {
if (selectedDayButton.length !== compareDays.length) return false;
const selectedDaySet = new Set(selectedDayButton);
return compareDays.every((day) => selectedDaySet.has(day));
};


watch([() => state.selectedRadioIdx, () => state.selectedDayButton, () => state.start, () => state.end], ([selectedRadioIdx]) => {
emit('update-form', {
Expand All @@ -130,6 +136,16 @@ watch([() => state.selectedRadioIdx, () => state.selectedDayButton, () => state.
});
}, { immediate: true });

watch(() => state.selectedDayButton, (selectedDayButton) => {
const weekDays = ['MON', 'TUE', 'WED', 'THU', 'FRI'] as DayType[];
const everyDay = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'] as DayType[];
if (areDayArraysEqual(selectedDayButton, weekDays)) {
state.selectedRadioIdx = 0;
} else if (areDayArraysEqual(selectedDayButton, everyDay)) {
state.selectedRadioIdx = 1;
}
}, { immediate: true });

onMounted(() => {
if (props.scheduleForm) {
initScheduleForm();
Expand Down
114 changes: 87 additions & 27 deletions apps/web/src/common/pages/AlertPublicDetailPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import {
import type { TabItem } from '@cloudforet/mirinae/types/navigation/tabs/tab/type';
import { iso8601Formatter } from '@cloudforet/utils';

import type { AlertModel } from '@/schema/alert-manager/alert/model';
import { ALERT_STATE, ALERT_URGENCY } from '@/schema/monitoring/alert/constants';
import type { AlertModel } from '@/schema/monitoring/alert/model';
import type { AlertModelV1 } from '@/schema/monitoring/alert/model';
import { i18n, setI18nLocale } from '@/translations';

import { ERROR_ROUTE } from '@/router/constant';
Expand All @@ -31,45 +32,75 @@ import { AUTH_ROUTE } from '@/services/auth/routes/route-constant';
const router = useRouter();

interface Props {
alertUrl?: string;
language?: string;
alertUrl?: string;
language?: string;
}

const props = defineProps<Props>();

interface PublicAlertModelV1 extends AlertModelV1 {
project_name: string;
domain_settings: {
timezone: string;
language: string;
};
}

interface PublicAlertModel extends AlertModel {
project_name: string;
domain_settings: {
timezone: string;
language: string;
};
service_name: string;
domain_settings: {
timezone: string;
language: string;
}
}

const state = reactive({
loading: true,
alertData: {} as Partial<PublicAlertModel>,
alertVersion: '',
alertData: {} as Partial<PublicAlertModelV1> & Partial<PublicAlertModel>,
alertId: '',
duration: computed(() => calculateTime(state.alertData?.created_at)),
timezone: computed(() => state.alertData?.domain_settings?.timezone ?? 'UTC'),
language: computed(() => state.alertData?.domain_settings?.language ?? 'en'),
});

const tableState = reactive({
fields: computed(() => [
{ name: 'description', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.DESC'), disableCopy: true },
{ name: 'rule', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.RULE'), disableCopy: true },
{ name: 'severity', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.SEVERITY'), disableCopy: true },
{ name: 'escalation_policy_id', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.ESCALATION_POLICY'), disableCopy: true },
{ name: 'project_id', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.PROJECT'), disableCopy: true },
{ name: 'triggered_by', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.TRIGGERED_BY'), disableCopy: true },
{ name: 'account', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.ACCOUNT_ID'), disableCopy: true },
{ name: 'resources', label: i18n.t('MONITORING.ALERT.DETAIL.DETAILS.RESOURCE'), disableCopy: true },
{ name: 'responder', label: i18n.t('MONITORING.ALERT.DETAIL.DETAILS.RESPONDER'), disableCopy: true },
{ name: 'created_at', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.CREATED'), disableCopy: true },
{ name: 'acknowledged_at', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.ACKNOWLEDGED'), disableCopy: true },
{ name: 'resolved_at', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.RESOLVED'), disableCopy: true },
]),
escalationPolicyName: '',
fields: computed(() => {
let fieldPerVersion;
if (state.alertVersion === 'v1') {
fieldPerVersion = [
{ name: 'project_id', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.PROJECT'), disableCopy: true },
{ name: 'account', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.ACCOUNT_ID'), disableCopy: true },
{ name: 'responder', label: i18n.t('MONITORING.ALERT.DETAIL.DETAILS.RESPONDER'), disableCopy: true },
];
} else {
fieldPerVersion = [
{ name: 'service_id', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.SERVICE'), disableCopy: true },
{ name: 'triggered_type', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.TRIGGERED_TYPE'), disableCopy: true },
{ name: 'acknowledged_by', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.ACKNOWLEDGED_BY'), disableCopy: true },
{ name: 'resolved_by', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.RESOLVED_BY'), disableCopy: true },
{ name: 'webhook_id', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.WEBHOOK'), disableCopy: true },
];
}
return [
{ name: 'description', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.DESC'), disableCopy: true },
{ name: 'rule', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.RULE'), disableCopy: true },
{ name: 'severity', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.SEVERITY'), disableCopy: true },
{ name: 'escalation_policy_id', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.ESCALATION_POLICY'), disableCopy: true },
{ name: 'triggered_by', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.TRIGGERED_BY'), disableCopy: true },
{ name: 'resources', label: i18n.t('MONITORING.ALERT.DETAIL.DETAILS.RESOURCE'), disableCopy: true },
{ name: 'created_at', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.CREATED'), disableCopy: true },
{ name: 'acknowledged_at', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.ACKNOWLEDGED'), disableCopy: true },
{ name: 'resolved_at', label: i18n.t('MONITORING.ALERT.DETAIL.INFO.RESOLVED'), disableCopy: true },
...fieldPerVersion,
];
}),
escalationPolicyName: computed(() => {
if (state.alertVersion === 'v2') {
return state.alertData.escalation_policy_name;
}
return '';
}),
webhooks: {},
alertStateList: computed(() => ([
{ name: ALERT_STATE.TRIGGERED, label: i18n.t('MONITORING.ALERT.DETAIL.HEADER.TRIGGERED') },
Expand Down Expand Up @@ -106,6 +137,12 @@ const fetchData = async () => {
try {
const response = await axios.get(alertFetchUrl as string);
state.alertData = response?.data;
if (Object.keys(state.alertData).includes('version')
&& state.alertData.version === 'v2') {
state.alertVersion = 'v2';
} else if (!Object.keys(state.alertData).includes('version')) {
state.alertVersion = 'v1';
}
} catch (e) {
console.error(e);
await router.push({ name: ERROR_ROUTE.EXPIRED_LINK._NAME });
Expand Down Expand Up @@ -159,7 +196,9 @@ const handleRouteToSignInWithRedirectPath = () => {
@click-back-button="router.go(-1)"
>
<template #title-right-extra>
<span class="alert-number">#{{ state.alertData?.alert_number }}</span>
<span v-if="state.alertVersion === 'v1'"
class="alert-number"
>#{{ state.alertData?.alert_number }}</span>
</template>
</p-heading>
<section class="detail-contents-wrapper">
Expand All @@ -168,11 +207,16 @@ const handleRouteToSignInWithRedirectPath = () => {
<p-pane-layout class="alert-detail-summary">
<p class="content-wrapper">
<span class="title">{{ $t('MONITORING.ALERT.DETAIL.HEADER.STATE') }}</span>
<template v-if="state.alertData?.state !== ALERT_STATE.ERROR">
<template v-if="state.alertVersion === 'v1' && state.alertData?.state !== ALERT_STATE.ERROR">
<span :class="{'text-alert': state.alertData.state === ALERT_STATE.TRIGGERED}">
{{ tableState.alertStateList.find(d => d.name === state.alertData?.state)?.label }}
</span>
</template>
<template v-else-if="state.alertVersion === 'v2' && state.alertData?.status !== ALERT_STATE.ERROR">
<span :class="{'text-alert': state.alertData.status === ALERT_STATE.TRIGGERED}">
{{ tableState.alertStateList.find(d => d.name === state.alertData?.status)?.label }}
</span>
</template>
<template v-else>
<p-badge style-type="alert"
badge-type="solid"
Expand Down Expand Up @@ -202,7 +246,9 @@ const handleRouteToSignInWithRedirectPath = () => {
{{ tableState.alertUrgencyList.find(d => d.name === state.alertData?.urgency)?.label }}
</span>
</p>
<p class="content-wrapper">
<p v-if="state.alertVersion === 'v1'"
class="content-wrapper"
>
<span class="title">{{ $t('MONITORING.ALERT.DETAIL.HEADER.ASSIGNED_TO') }}</span>
<span v-if="state.alertData?.assignee"
class="email"
Expand Down Expand Up @@ -285,6 +331,20 @@ const handleRouteToSignInWithRedirectPath = () => {
<span v-if="state.alertData.resolved_at"> {{ iso8601Formatter(state.alertData.resolved_at, state.timezone) }}</span>
<span v-else>--</span>
</template>
<template #data-service_id>
<p class="content-wrapper">
<span class="service">
{{ state.alertData?.service_name ?? state.alertData?.service_id }}
</span>
</p>
</template>
<template #data-triggered_type>
<p-badge badge-type="solid-outline"
style-type="indigo500"
>
{{ state.alertData.triggered_type }}
</p-badge>
</template>
<template #data-additional_info="{value}">
<span v-if="Object.keys(value)?.length === 0">
--
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/schema/monitoring/alert/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {
AlertResource, AlertSeverity, AlertState, AlertUrgency,
} from '@/schema/monitoring/alert/type';

export interface AlertModel {
export interface AlertModelV1 {
alert_number: number;
alert_id: string;
title: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed, reactive } from 'vue';
import { useRouter } from 'vue-router/composables';
import { useRoute, useRouter } from 'vue-router/composables';

import { SpaceConnector } from '@cloudforet/core-lib/space-connector';
import { PButtonModal } from '@cloudforet/mirinae';
Expand Down Expand Up @@ -33,6 +33,7 @@ const storeState = reactive({
alertInfo: computed<AlertModel>(() => alertDetailPageState.alertInfo),
});
const router = useRouter();
const route = useRoute();

const { getProperRouteLocation } = useProperRouteLocation();

Expand All @@ -53,7 +54,12 @@ const handleConfirm = async () => {
await SpaceConnector.clientV2.alertManager.alert.delete<AlertDeleteParameters>({
alert_id: storeState.alertInfo.alert_id,
});
await router.push(getProperRouteLocation({ name: ALERT_MANAGER_ROUTE.ALERTS._NAME }));
const serviceId = route.params?.serviceId;
if (serviceId) {
await router.go(-1);
} else {
await router.push(getProperRouteLocation({ name: ALERT_MANAGER_ROUTE.ALERTS._NAME }));
}
showSuccessMessage(i18n.t('ALERT_MANAGER.ALERTS.ALT_S_DELETE'), '');
} catch (e) {
ErrorHandler.handleError(e, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ const state = reactive({
alertUrgency: 'HIGH',
duration: computed<string>(() => (
storeState.alertInfo.status === ALERT_STATUS.RESOLVED
? calculateTime(storeState.alertInfo?.resolved_at, storeState.timezone)
: calculateTime(storeState.alertInfo?.created_at, storeState.timezone)
? calculateTime(storeState.alertInfo?.resolved_at, storeState.timezone) || '0m'
: calculateTime(storeState.alertInfo?.created_at, storeState.timezone) || '0m'
)),
alertStateList: computed<SelectDropdownMenuItem[]>(() => ([
{ name: ALERT_STATUS.TRIGGERED, label: i18n.t('ALERT_MANAGER.ALERTS.TRIGGERED') },
Expand All @@ -57,6 +57,8 @@ const state = reactive({
])),
});

const getEscalationInfo = (id: string) => storeState.escalationPolicy[id]?.label || '';

const handleChangeAlertState = async (alertState: AlertStatusType) => {
await alertDetailPageStore.updateAlertDetail({
alert_id: storeState.alertInfo.alert_id,
Expand Down Expand Up @@ -132,7 +134,7 @@ watch(() => alertDetailPageState.alertInfo, (alertInfo) => {
</div>
<div class="content-wrapper">
<span class="title">{{ $t('ALERT_MANAGER.ESCALATION_POLICY.TITLE') }}</span>
<p-link :text="storeState.escalationPolicy[storeState.alertInfo.escalation_policy_id].label"
<p-link :text="getEscalationInfo(storeState.alertInfo.escalation_policy_id)"
action-icon="internal-link"
new-tab
:to="getProperRouteLocation({
Expand All @@ -146,6 +148,7 @@ watch(() => alertDetailPageState.alertInfo, (alertInfo) => {
},
})"
highlight
size="md"
class="leading-8"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const storeState = reactive({
selectedServiceId: computed<string>(() => alertPageState.selectedServiceId),
selectedStatus: computed<string>(() => alertPageState.selectedStatus),
selectedUrgency: computed<string>(() => alertPageState.selectedUrgency),
selectedSearchFilter: computed<string|undefined>(() => alertPageState.selectedSearchFilter),
selectedSearchFilter: computed<string[]|undefined>(() => alertPageState.selectedSearchFilter),
});
const state = reactive({
menuItems: computed<MenuItem[]>(() => [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,8 @@ watch(() => storeState.serviceId, async (serviceId) => {
</template>
<template #col-duration-format="{ item }">
<span>{{ item.status === ALERT_STATUS.RESOLVED
? calculateTime(item?.resolved_at, storeState.timezone)
: calculateTime(item?.created_at, storeState.timezone) }}</span>
? calculateTime(item?.resolved_at, storeState.timezone) || '0m'
: calculateTime(item?.created_at, storeState.timezone) || '0m' }}</span>
</template>
</p-toolbox-table>
<custom-field-modal :visible="state.visibleCustomFieldModal"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const state = reactive({
alerts: storeState.service.alerts.TOTAL.HIGH + storeState.service.alerts.TOTAL.LOW,
webhook: storeState.service.webhooks?.length || 0,
})),
noData: computed<boolean>(() => state.data.alerts === 0 && state.data.webhook === 0),
});
const handleConfirm = async () => {
state.loading = true;
Expand All @@ -66,7 +67,7 @@ const handleClose = () => {

<template>
<p-button-modal class="service-detail-delete-modal"
:header-title="$t('ALERT_MANAGER.SERVICE.MODAL_DELETE_TITLE')"
:header-title="!state.noData ? $t('ALERT_MANAGER.SERVICE.MODAL_DELETE_TITLE') : $t('ALERT_MANAGER.SERVICE.MODAL_DELETE_NO_DATA')"
size="sm"
theme-color="alert"
:fade="true"
Expand All @@ -77,10 +78,13 @@ const handleClose = () => {
@cancel="handleClose"
@close="handleClose"
>
<template #body>
<template v-if="!state.noData"
#body
>
<div class="flex flex-col gap-2 pt-4 pb-2">
<span>{{ $t('ALERT_MANAGER.SERVICE.MODAL_DELETE_DESC') }}</span>
<p-definition-table :fields="state.fields"
<p-definition-table v-if="!state.noData"
:fields="state.fields"
:data="state.data"
:skeleton-rows="2"
class="definition-table"
Expand All @@ -89,6 +93,11 @@ const handleClose = () => {
/>
</div>
</template>
<template v-if="state.noData"
#confirm-button
>
{{ $t('COMMON.BUTTONS.DELETE') }}
</template>
</p-button-modal>
</template>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ watch(() => tabState.activeTab, (activeTab) => {
mode: activeTab !== SERVICE_DETAIL_TABS.SETTINGS ? undefined : route.query?.mode,
webhookId: activeTab !== SERVICE_DETAIL_TABS.SETTINGS ? undefined : route.query?.webhookId,
eventRuleId: activeTab !== SERVICE_DETAIL_TABS.SETTINGS ? undefined : route.query?.eventRuleId,
escalationPolicyId: activeTab !== SERVICE_DETAIL_TABS.SETTINGS ? undefined : route.query?.escalationPolicyId,
});
});
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,10 @@ watch(() => storeState.serviceInfo.service_id, (service_id) => {
>
<p-text-button style-type="highlight"
class="ml-auto mr-auto"
size="sm"
@click="handleRouteAlertsTab"
>
{{ $t('ALERT_MANAGER.SERVICE.VIEW_ALL_OPEN_ALERTS') }}
{{ $t('ALERT_MANAGER.SERVICE.VIEW_ALL') }}
</p-text-button>
</td>
</template>
Expand Down
Loading