-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(timed-events): add administration interface for new timed events (…
…#19) * feat: add view for managing all timed events in Aurora * feat: improve event labels
- Loading branch information
Showing
18 changed files
with
739 additions
and
12 deletions.
There are no files selected for viewing
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
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,34 @@ | ||
<template> | ||
<Button icon="pi pi-times" severity="danger" @click="confirmRef?.confirmDialog" /> | ||
<ConfirmWrapper | ||
ref="confirmRef" | ||
:loading="loading" | ||
message="Are you sure you want to delete this timed event?" | ||
:on-accept=" | ||
() => { | ||
loading = true; | ||
store.deleteTimedEvent(props.timedEvent.id).finally(() => { | ||
loading = false; | ||
}); | ||
} | ||
" | ||
/> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { ref } from 'vue'; | ||
import type { TimedEventResponse } from '@/api'; | ||
import { useTimedEventsStore } from '@/stores/timed-events.store'; | ||
import ConfirmWrapper from '@/components/prime/ConfirmWrapper.vue'; | ||
const store = useTimedEventsStore(); | ||
const props = defineProps<{ | ||
timedEvent: TimedEventResponse; | ||
}>(); | ||
const confirmRef = ref(); | ||
const loading = ref<boolean>(false); | ||
</script> | ||
|
||
<style scoped></style> |
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,165 @@ | ||
<template> | ||
<Dialog | ||
closable | ||
close-on-escape | ||
dismissable-mask | ||
header="Create new timed event" | ||
:keep-in-view-port="false" | ||
modal | ||
:visible="visible" | ||
@update:visible="(v) => $emit('update:visible', v)" | ||
> | ||
<div class="flex flex-col gap-4"> | ||
<div class="flex flex-col gap-2"> | ||
<label for="cronExpression">Cron expression</label> | ||
<InputText | ||
id="cronExpression" | ||
v-model="cronExpression" | ||
:invalid="cronInvalid" | ||
placeholder="39 5 * * *" | ||
type="text" | ||
/> | ||
<Message v-if="cronInvalid" severity="error" size="small" variant="simple" | ||
>Please type a valid cron expression</Message | ||
> | ||
<Message v-else severity="secondary" size="small" variant="simple">{{ | ||
cronstrue.toString(cronExpression) | ||
}}</Message> | ||
</div> | ||
<div class="flex flex-col gap-2"> | ||
<label for="event-type">Event type</label> | ||
<Select | ||
id="event-type" | ||
v-model="selectedType" | ||
option-label="label" | ||
option-value="name" | ||
:options="possibleTypes" | ||
placeholder="Choose a type" | ||
/> | ||
</div> | ||
<div v-if="originalTimedEvent" class="flex flex-col gap-2"> | ||
<label for="skip-next">Skip next?</label> | ||
<ToggleSwitch v-model="skipNext" /> | ||
</div> | ||
<TimedEventParamsHandlerAudio | ||
v-if="selectedType === 'switch-handler-audio'" | ||
:cron-expression="cronExpression" | ||
:cron-valid="!cronInvalid" | ||
:on-save="onSaveWrapper" | ||
:original-event-spec-params=" | ||
originalTimedEvent?.eventSpec.type === 'switch-handler-audio' | ||
? originalTimedEvent?.eventSpec.params | ||
: undefined | ||
" | ||
:skip-next="skipNext" | ||
/> | ||
<TimedEventParamsHandlerLights | ||
v-else-if="selectedType === 'switch-handler-lights'" | ||
:cron-expression="cronExpression" | ||
:cron-valid="!cronInvalid" | ||
:on-save="onSaveWrapper" | ||
:original-event-spec-params=" | ||
originalTimedEvent?.eventSpec.type === 'switch-handler-lights' | ||
? originalTimedEvent?.eventSpec.params | ||
: undefined | ||
" | ||
:skip-next="skipNext" | ||
/> | ||
<TimedEventParamsHandlerScreen | ||
v-else-if="selectedType === 'switch-handler-screen'" | ||
:cron-expression="cronExpression" | ||
:cron-valid="!cronInvalid" | ||
:on-save="onSaveWrapper" | ||
:original-event-spec-params=" | ||
originalTimedEvent?.eventSpec.type === 'switch-handler-screen' | ||
? originalTimedEvent?.eventSpec.params | ||
: undefined | ||
" | ||
:skip-next="skipNext" | ||
/> | ||
<TimedEventDialogSaveButton | ||
v-else | ||
:disabled="loading || cronInvalid || selectedType === ''" | ||
:loading="loading" | ||
@click="saveEvent" | ||
> | ||
Save changes | ||
</TimedEventDialogSaveButton> | ||
</div> | ||
</Dialog> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { computed, type ComputedRef, type Ref, ref } from 'vue'; | ||
import cronstrue from 'cronstrue'; | ||
import type { CreateTimedEventRequest, EventSpec, TimedEventResponse } from '@/api'; | ||
import TimedEventParamsHandlerScreen from '@/components/timed-events/types/TimedEventParamsHandlerScreen.vue'; | ||
import TimedEventParamsHandlerAudio from '@/components/timed-events/types/TimedEventParamsHandlerAudio.vue'; | ||
import TimedEventParamsHandlerLights from '@/components/timed-events/types/TimedEventParamsHandlerLights.vue'; | ||
import TimedEventDialogSaveButton from '@/components/timed-events/types/TimedEventDialogSaveButton.vue'; | ||
const props = defineProps<{ | ||
originalTimedEvent?: TimedEventResponse; | ||
visible: boolean; | ||
onSave: (params: CreateTimedEventRequest, skipNext?: boolean) => Promise<void>; | ||
}>(); | ||
const emit = defineEmits<{ | ||
'update:visible': [visible: boolean]; | ||
}>(); | ||
const loading = ref<boolean>(false); | ||
const cronExpression = ref<string>(props.originalTimedEvent?.cronExpression ?? ''); | ||
const cronInvalid: ComputedRef<boolean> = computed(() => { | ||
try { | ||
cronstrue.toString(cronExpression.value); | ||
return false; | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
} catch (error: unknown) { | ||
return true; | ||
} | ||
}); | ||
const selectedType = ref<EventSpec['type'] | ''>(props.originalTimedEvent?.eventSpec.type ?? ''); | ||
const possibleTypes: Ref<{ name: EventSpec['type']; label: string }[]> = ref([ | ||
{ name: 'system-reset', label: 'System reset' }, | ||
{ name: 'clean-audit-logs', label: 'Clean audit logs' }, | ||
{ name: 'switch-handler-audio', label: 'Switch handler audio' }, | ||
{ name: 'switch-handler-lights', label: 'Switch handler lights group' }, | ||
{ name: 'switch-handler-screen', label: 'Switch handler screen' }, | ||
] as { name: EventSpec['type']; label: string }[]); | ||
const skipNext = ref<boolean>(false); | ||
const onSaveWrapper = async (params: CreateTimedEventRequest, skipNext?: boolean) => { | ||
await props.onSave(params, skipNext); | ||
emit('update:visible', false as never); | ||
}; | ||
const saveEvent = () => { | ||
if (selectedType.value === '') return; | ||
loading.value = true; | ||
switch (selectedType.value) { | ||
case 'system-reset': | ||
onSaveWrapper({ cronExpression: cronExpression.value, eventSpec: { type: 'system-reset' } }, skipNext.value).then( | ||
() => { | ||
loading.value = false; | ||
}, | ||
); | ||
return; | ||
case 'clean-audit-logs': | ||
onSaveWrapper( | ||
{ cronExpression: cronExpression.value, eventSpec: { type: 'clean-audit-logs' } }, | ||
skipNext.value, | ||
).then(() => { | ||
loading.value = false; | ||
}); | ||
return; | ||
} | ||
}; | ||
</script> | ||
|
||
<style scoped></style> |
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,21 @@ | ||
<template> | ||
<Button icon="pi pi-plus" label="Create new event" severity="success" @click="open = true" /> | ||
<TimedEventDialog v-model:visible="open" :on-save="onSave" /> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { ref } from 'vue'; | ||
import TimedEventDialog from '@/components/timed-events/TimedEventDialog.vue'; | ||
import type { CreateTimedEventRequest } from '@/api'; | ||
import { useTimedEventsStore } from '@/stores/timed-events.store'; | ||
const open = ref<boolean>(false); | ||
const store = useTimedEventsStore(); | ||
const onSave = async (params: CreateTimedEventRequest) => { | ||
return store.createTimedEvent(params); | ||
}; | ||
</script> | ||
|
||
<style scoped></style> |
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,25 @@ | ||
<template> | ||
<Button icon="pi pi-pen-to-square" severity="secondary" @click="open = true" /> | ||
<TimedEventDialog v-model:visible="open" :on-save="onSave" :original-timed-event="timedEvent" /> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { ref } from 'vue'; | ||
import TimedEventDialog from '@/components/timed-events/TimedEventDialog.vue'; | ||
import type { CreateTimedEventRequest, TimedEventResponse } from '@/api'; | ||
import { useTimedEventsStore } from '@/stores/timed-events.store'; | ||
const props = defineProps<{ | ||
timedEvent: TimedEventResponse; | ||
}>(); | ||
const open = ref<boolean>(false); | ||
const store = useTimedEventsStore(); | ||
const onSave = async (params: CreateTimedEventRequest, skipNext?: boolean) => { | ||
if (!skipNext) throw new Error('"skipNext" is required.'); | ||
return store.updateTimedEvent(props.timedEvent.id, { ...params, skipNext }); | ||
}; | ||
</script> | ||
<style scoped></style> |
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,72 @@ | ||
<template> | ||
<TimedEventTag | ||
v-if="props.eventSpec.type === 'system-reset'" | ||
description="Reset system to initial state." | ||
label="System reset" | ||
/> | ||
<TimedEventTag | ||
v-else-if="props.eventSpec.type === 'clean-audit-logs'" | ||
description="Remove all expired audit logs from the database." | ||
label="Clean audit logs" | ||
/> | ||
<TimedEventTag | ||
v-else-if="props.eventSpec.type === 'switch-handler-audio' && props.eventSpec.params.handler !== ''" | ||
description="" | ||
:label="`Switch handler for audio '${getAudioName(props.eventSpec.params.id)}' to ${props.eventSpec.params.handler}`" | ||
/> | ||
<TimedEventTag | ||
v-else-if="props.eventSpec.type === 'switch-handler-audio'" | ||
description="" | ||
:label="`Remove handler for audio '${getAudioName(props.eventSpec.params.id)}'`" | ||
/> | ||
<TimedEventTag | ||
v-else-if="props.eventSpec.type === 'switch-handler-lights' && props.eventSpec.params.handler !== ''" | ||
description="" | ||
:label="`Switch handler for lights group '${getLightsGroupName(props.eventSpec.params.id)}' to ${props.eventSpec.params.handler}`" | ||
/> | ||
<TimedEventTag | ||
v-else-if="props.eventSpec.type === 'switch-handler-lights'" | ||
description="" | ||
:label="`Remove handler for lights group '${getLightsGroupName(props.eventSpec.params.id)}'`" | ||
/> | ||
<TimedEventTag | ||
v-else-if="props.eventSpec.type === 'switch-handler-screen' && props.eventSpec.params.handler !== ''" | ||
description="" | ||
:label="`Switch handler for screen '${getScreenName(props.eventSpec.params.id)}' to ${props.eventSpec.params.handler}`" | ||
/> | ||
<TimedEventTag | ||
v-else-if="props.eventSpec.type === 'switch-handler-screen'" | ||
description="" | ||
:label="`Remove handler for screen '${getScreenName(props.eventSpec.params.id)}'`" | ||
/> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import type { EventSpec } from '@/api'; | ||
import TimedEventTag from '@/components/timed-events/TimedEventTag.vue'; | ||
import { useSubscriberStore } from '@/stores/subscriber.store'; | ||
const subscriberStore = useSubscriberStore(); | ||
const getAudioName = (id: number) => { | ||
const match = subscriberStore.audios.find((audio) => audio.id === id); | ||
if (match) return match.name; | ||
return id.toString(); | ||
}; | ||
const getLightsGroupName = (id: number) => { | ||
const match = subscriberStore.lightsGroups.find((lightsGroup) => lightsGroup.id === id); | ||
if (match) return match.name; | ||
return id.toString(); | ||
}; | ||
const getScreenName = (id: number) => { | ||
const match = subscriberStore.screens.find((screen) => screen.id === id); | ||
if (match) return match.name; | ||
return id.toString(); | ||
}; | ||
const props = defineProps<{ | ||
eventSpec: EventSpec; | ||
}>(); | ||
</script> | ||
|
||
<style scoped></style> |
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,12 @@ | ||
<template> | ||
<Tag v-tooltip.bottom="{ value: description }" severity="secondary">{{ props.label }}</Tag> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
const props = defineProps<{ | ||
label: string; | ||
description: string; | ||
}>(); | ||
</script> | ||
|
||
<style scoped></style> |
18 changes: 18 additions & 0 deletions
18
src/components/timed-events/types/TimedEventDialogSaveButton.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,18 @@ | ||
<template> | ||
<div> | ||
<Button :disabled="disabled" :loading="loading" severity="success" @click="$emit('click')"> Save changes </Button> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
defineProps<{ | ||
disabled: boolean; | ||
loading: boolean; | ||
}>(); | ||
defineEmits<{ | ||
click: []; | ||
}>(); | ||
</script> | ||
|
||
<style scoped></style> |
Oops, something went wrong.