-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5466 from cloudforet-io/feature-project-alert-man…
…ager feat: apply alert manager v2
- Loading branch information
Showing
701 changed files
with
74,361 additions
and
4,464 deletions.
There are no files selected for viewing
127 changes: 127 additions & 0 deletions
127
apps/web/src/common/components/channel-user-select/ChannelUserSelect.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
<script lang="ts" setup> | ||
import { | ||
computed, reactive, ref, watch, | ||
} from 'vue'; | ||
import { | ||
PFieldGroup, PRadioGroup, PRadio, | ||
} from '@cloudforet/mirinae'; | ||
import type { MenuItem } from '@cloudforet/mirinae/types/inputs/context-menu/type'; | ||
import { i18n } from '@/translations'; | ||
import UserSelectDropdown from '@/common/modules/user/UserSelectDropdown.vue'; | ||
import { useNotificationChannelCreateFormStore } from '@/services/iam/store/notification-channel-create-form-store'; | ||
const notificationChannelCreateFormStore = useNotificationChannelCreateFormStore(); | ||
const notificationChannelCreateFormState = notificationChannelCreateFormStore.state; | ||
const USER_MODE = { | ||
ALL_MEMBER: 'ALL_MEMBER', | ||
USER_GROUP: 'USER_GROUP', | ||
USER: 'USER', | ||
}; | ||
const SHOW_TYPE = { | ||
USER_LIST: 'userList', | ||
USER_GROUP_LIST: 'userGroupList', | ||
}; | ||
const showType = ref<string>(); | ||
const selectedIds = ref<any>([]); | ||
const state = reactive({ | ||
userMode: computed<MenuItem[]>(() => [{ | ||
label: i18n.t('IAM.USER_GROUP.MODAL.CREATE_CHANNEL.DESC.USER_MODE.ALL_MEMBERS'), | ||
name: USER_MODE.ALL_MEMBER, | ||
}, { | ||
label: i18n.t('IAM.USER_GROUP.MODAL.CREATE_CHANNEL.DESC.USER_MODE.USER_GROUP'), | ||
name: USER_MODE.USER_GROUP, | ||
}, { | ||
label: i18n.t('IAM.USER_GROUP.MODAL.CREATE_CHANNEL.DESC.USER_MODE.SPECIFIC_USER'), | ||
name: USER_MODE.USER, | ||
}]), | ||
selectedUserModeIdx: 0, | ||
}); | ||
/* Component */ | ||
const handleChange = (idx: number) => { | ||
state.selectedUserModeIdx = idx; | ||
}; | ||
const handleSelectedIds = (value) => { | ||
selectedIds.value = value; | ||
}; | ||
/* Watcher */ | ||
watch(() => state.userMode[state.selectedUserModeIdx], (nv_userMode) => { | ||
showType.value = nv_userMode?.name === USER_MODE.USER_GROUP ? SHOW_TYPE.USER_GROUP_LIST : SHOW_TYPE.USER_LIST; | ||
}, { deep: true, immediate: true }); | ||
watch(() => state.selectedUserModeIdx, async (nv_selectedIdx, ov_selectedIdx) => { | ||
if (nv_selectedIdx !== ov_selectedIdx) { | ||
selectedIds.value = []; | ||
} | ||
}); | ||
watch(() => state.selectedUserModeIdx, (nv_selected_idx) => { | ||
if (nv_selected_idx === 0) { | ||
notificationChannelCreateFormState.userInfo.type = 'ALL_MEMBER'; | ||
} else if (nv_selected_idx === 1) { | ||
notificationChannelCreateFormState.userInfo.type = 'USER_GROUP'; | ||
} else { | ||
notificationChannelCreateFormState.userInfo.type = 'USER'; | ||
} | ||
}); | ||
watch([() => notificationChannelCreateFormState.userInfo.type, () => notificationChannelCreateFormState.userInfo.value], () => { | ||
// TODO: Retrieving a list of existing users | ||
// if (nv_user_info_type) { | ||
// if (nv_user_info_type !== 'ALL_MEMBER') { | ||
// state.selectedUserModeIdx = nv_user_info_type === 'USER_GROUP' ? 1 : 2; | ||
// | ||
// selectedIds.value = { | ||
// type: nv_user_info_type, | ||
// value: nv_user_info_value, | ||
// }; | ||
// } else { | ||
// state.selectedUserModeIdx = 0; | ||
// } | ||
// } | ||
}, { immediate: true, deep: true }); | ||
watch(selectedIds, (nv_selected_ids) => { | ||
const result: string[] = []; | ||
nv_selected_ids.forEach((id) => { | ||
result.push(id.value); | ||
}); | ||
notificationChannelCreateFormState.userInfo.value = result; | ||
}, { immediate: true }); | ||
</script> | ||
|
||
<template> | ||
<p-field-group :label="$t('IAM.USER_GROUP.MODAL.CREATE_CHANNEL.DESC.USER_MODE.TITLE')" | ||
required | ||
> | ||
<p-radio-group> | ||
<p-radio v-for="(mode, idx) in state.userMode" | ||
:key="`${mode.name}-${idx}`" | ||
v-model="state.selectedUserModeIdx" | ||
:value="idx" | ||
@handle="handleChange" | ||
> | ||
{{ mode.label }} | ||
</p-radio> | ||
</p-radio-group> | ||
<user-select-dropdown class="mt-2" | ||
:show-user-list="showType === SHOW_TYPE.USER_LIST" | ||
:show-user-group-list="showType === SHOW_TYPE.USER_GROUP_LIST" | ||
:disabled="state.userMode[state.selectedUserModeIdx].name === USER_MODE.ALL_MEMBER" | ||
appearance-type="stack" | ||
selection-type="multiple" | ||
:selected-ids="selectedIds" | ||
@update:selected-ids="handleSelectedIds" | ||
/> | ||
</p-field-group> | ||
</template> |
191 changes: 191 additions & 0 deletions
191
apps/web/src/common/components/schedule-setting-form/ScheduleSettingForm.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
<script lang="ts" setup> | ||
import { | ||
computed, onMounted, reactive, watch, | ||
} from 'vue'; | ||
import { range, zipObject } from 'lodash'; | ||
import { | ||
PFieldGroup, PRadioGroup, PRadio, PI, PSelectButton, PSelectDropdown, | ||
} from '@cloudforet/mirinae'; | ||
import type { SelectDropdownMenuItem } from '@cloudforet/mirinae/types/controls/dropdown/select-dropdown/type'; | ||
import type { ServiceChannelScheduleType } from '@/schema/alert-manager/service-channel/type'; | ||
import { i18n } from '@/translations'; | ||
import { useUserStore } from '@/store/user/user-store'; | ||
import type { | ||
ScheduleDayButtonType, | ||
ScheduleRadioType, | ||
DayType, | ||
ScheduleSettingFormType, | ||
ScheduleFormDayType, | ||
} from '@/common/components/schedule-setting-form/schedule-setting-form'; | ||
import { blue } from '@/styles/colors'; | ||
interface Props { | ||
scheduleForm?: ScheduleSettingFormType; | ||
} | ||
const props = withDefaults(defineProps<Props>(), { | ||
scheduleForm: undefined, | ||
}); | ||
const userStore = useUserStore(); | ||
const userState = userStore.state; | ||
const emit = defineEmits<{(e: 'update-form', form: ScheduleSettingFormType): void; }>(); | ||
const storeState = reactive({ | ||
timezone: computed(() => userState.timezone || 'UTC'), | ||
}); | ||
const state = reactive({ | ||
scheduleTypeList: computed<ScheduleRadioType[]>(() => [ | ||
{ name: 'WEEK_DAY', label: i18n.t('COMMON.SCHEDULE_SETTING.WEEKDAYS') }, | ||
{ name: 'ALL_DAY', label: i18n.t('COMMON.SCHEDULE_SETTING.EVERYDAY') }, | ||
{ name: 'CUSTOM', label: i18n.t('COMMON.SCHEDULE_SETTING.CUSTOM') }, | ||
]), | ||
selectedRadioIdx: 0, | ||
days: computed<ScheduleDayButtonType[]>(() => [ | ||
{ name: 'MON', label: i18n.t('COMMON.SCHEDULE_SETTING.MON') }, | ||
{ name: 'TUE', label: i18n.t('COMMON.SCHEDULE_SETTING.TUE') }, | ||
{ name: 'WED', label: i18n.t('COMMON.SCHEDULE_SETTING.WED') }, | ||
{ name: 'THU', label: i18n.t('COMMON.SCHEDULE_SETTING.THU') }, | ||
{ name: 'FRI', label: i18n.t('COMMON.SCHEDULE_SETTING.FRI') }, | ||
{ name: 'SAT', label: i18n.t('COMMON.SCHEDULE_SETTING.SAT') }, | ||
{ name: 'SUN', label: i18n.t('COMMON.SCHEDULE_SETTING.SUN') }, | ||
]), | ||
selectedDayButton: ['MON', 'TUE', 'WED', 'THU', 'FRI'] as DayType[], | ||
start: 0, | ||
end: 24, | ||
startHourTimeList: computed<SelectDropdownMenuItem[]>(() => range(0, state.end).map((h) => ({ | ||
label: `${h.toString().padStart(2, '0')}:00`, | ||
name: h.toString(), | ||
}))), | ||
endHourTimeList: computed<SelectDropdownMenuItem[]>(() => range(Number(state.start) + 1, 25).map((h) => ({ | ||
label: `${h.toString().padStart(2, '0')}:00`, | ||
name: h.toString(), | ||
}))), | ||
scheduleDayForm: computed<Record<DayType, ScheduleFormDayType>>(() => { | ||
const refinedDays = state.days.map((day) => ({ | ||
is_scheduled: state.selectedDayButton.includes(day.name), | ||
start: state.start, | ||
end: state.end, | ||
})); | ||
return zipObject(state.days.map((i) => i.name), refinedDays) as Record<DayType, ScheduleFormDayType>; | ||
}), | ||
}); | ||
const initScheduleForm = () => { | ||
if (!props.scheduleForm) return; | ||
state.selectedRadioIdx = state.scheduleTypeList.findIndex((item) => item.name === props.scheduleForm?.SCHEDULE_TYPE) || 0; | ||
let filteredSchedule: string[] = []; | ||
if (state.selectedRadioIdx === 0) { | ||
filteredSchedule = state.days.slice(0, 5).map((day) => day.name); | ||
} else if (state.selectedRadioIdx === 1) { | ||
filteredSchedule = state.days.map((day) => day.name); | ||
} else { | ||
filteredSchedule = state.days.filter((day) => { | ||
if (!props.scheduleForm) return []; | ||
const schedule = props.scheduleForm[day.name]; | ||
return schedule?.is_scheduled; | ||
}).map((i) => i.name); | ||
} | ||
state.selectedDayButton = filteredSchedule; | ||
state.start = props.scheduleForm[filteredSchedule[0]]?.start || 0; | ||
state.end = props.scheduleForm[filteredSchedule[0]]?.end || 24; | ||
}; | ||
const handleSelectScheduleType = (type: ServiceChannelScheduleType) => { | ||
if (type === 'WEEK_DAY') { | ||
state.selectedDayButton = state.days.slice(0, 5).map((day) => day.name); | ||
} else if (type === 'ALL_DAY') { | ||
state.selectedDayButton = state.days.map((day) => day.name); | ||
} else { | ||
state.selectedDayButton = []; | ||
} | ||
}; | ||
const handleSelectDayButton = (value: DayType[]) => { | ||
state.selectedRadioIdx = 2; | ||
state.selectedDayButton = value; | ||
}; | ||
const handleSelectDropdown = (type: 'start' | 'end', value: number) => { | ||
if (type === 'start') { | ||
state.start = value || 0; | ||
} else { | ||
state.end = value || 0; | ||
} | ||
}; | ||
watch([() => state.selectedRadioIdx, () => state.selectedDayButton, () => state.start, () => state.end], ([selectedRadioIdx]) => { | ||
emit('update-form', { | ||
SCHEDULE_TYPE: state.scheduleTypeList[selectedRadioIdx].name, | ||
TIMEZONE: storeState.timezone, | ||
...state.scheduleDayForm, | ||
}); | ||
}, { immediate: true }); | ||
onMounted(() => { | ||
if (props.scheduleForm) { | ||
initScheduleForm(); | ||
} | ||
}); | ||
</script> | ||
|
||
<template> | ||
<div class="schedule-setting-form flex flex-col"> | ||
<p-field-group :label="$t('COMMON.SCHEDULE_SETTING.SCHEDULE_SETTING')" | ||
required | ||
> | ||
<p-radio-group direction="horizontal"> | ||
<p-radio v-for="(item, index) in state.scheduleTypeList" | ||
:key="`schedule-setting-${index}`" | ||
v-model="state.selectedRadioIdx" | ||
:value="index" | ||
@change="handleSelectScheduleType(item.name)" | ||
> | ||
{{ item.label }} | ||
</p-radio> | ||
</p-radio-group> | ||
<div class="flex gap-1 py-2 px-0.5"> | ||
<p-i name="ic_info-circle" | ||
:color="blue[600]" | ||
width="0.875rem" | ||
height="0.875rem" | ||
/> | ||
<p class="text-xs text-blue-600"> | ||
{{ $t('COMMON.SCHEDULE_SETTING.INFO') }} | ||
</p> | ||
</div> | ||
<div class="w-full overflow py-4 flex flex-wrap gap-2"> | ||
<p-select-button v-for="(item, index) in state.days" | ||
:key="`schedule-days-${index}`" | ||
v-model="state.selectedDayButton" | ||
multi-selectable | ||
:value="item.name" | ||
@change="handleSelectDayButton" | ||
> | ||
{{ item.label }} | ||
</p-select-button> | ||
</div> | ||
<div class="flex items-center gap-2"> | ||
<p-select-dropdown :menu="state.startHourTimeList" | ||
:selected="state.start" | ||
:placeholder="state.startHourTimeList[state.start].label" | ||
@select="handleSelectDropdown('start', $event)" | ||
/> | ||
<span>{{ $t('COMMON.SCHEDULE_SETTING.TO') }}</span> | ||
<p-select-dropdown :menu="state.endHourTimeList" | ||
:selected="state.end" | ||
:placeholder="state.endHourTimeList[state.end - state.start - 1].label" | ||
@select="handleSelectDropdown('end', $event)" | ||
/> | ||
</div> | ||
</p-field-group> | ||
</div> | ||
</template> |
26 changes: 26 additions & 0 deletions
26
apps/web/src/common/components/schedule-setting-form/schedule-setting-form.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import type { TranslateResult } from 'vue-i18n'; | ||
|
||
export type ScheduleType = 'ALL_DAY' | 'WEEK_DAY' | 'WEEKEND' | 'CUSTOM'; | ||
export type DayType = 'MON' | 'TUE' | 'WED' | 'THU' | 'FRI' | 'SAT' | 'SUN'; | ||
|
||
export type ScheduleRadioType = { | ||
name: ScheduleType; | ||
label: TranslateResult; | ||
}; | ||
export type ScheduleDayButtonType = { | ||
name: DayType; | ||
label: TranslateResult; | ||
}; | ||
|
||
type ScheduleFormType = { | ||
SCHEDULE_TYPE: ScheduleType; | ||
}; | ||
export type ScheduleFormDayType = { | ||
is_scheduled: boolean; | ||
start: number; | ||
end: number; | ||
}; | ||
|
||
export type ScheduleSettingFormType = ScheduleFormType & Partial<Record<DayType, ScheduleFormDayType>> & { | ||
TIMEZONE: string; | ||
}; |
Oops, something went wrong.