Notices fixes and support for titles (#3508)

* Notices fixes and support for titles

* Lint
This commit is contained in:
Prospector 2025-04-14 16:58:31 -07:00 committed by GitHub
parent 6c16688ca9
commit 04659a8198
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 52 additions and 6 deletions

View File

@ -114,6 +114,7 @@ defineExpose({ show, hide });
:level="notice.level" :level="notice.level"
:message="notice.message" :message="notice.message"
:dismissable="notice.dismissable" :dismissable="notice.dismissable"
:title="notice.title"
preview preview
/> />
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">

View File

@ -85,6 +85,7 @@ const props = defineProps<{
:level="notice.level" :level="notice.level"
:message="notice.message" :message="notice.message"
:dismissable="notice.dismissable" :dismissable="notice.dismissable"
:title="notice.title"
preview preview
/> />
<div class="mt-4 flex items-center gap-2"> <div class="mt-4 flex items-center gap-2">

View File

@ -6,6 +6,18 @@
}}</span> }}</span>
</template> </template>
<div class="flex w-[700px] flex-col gap-3"> <div class="flex w-[700px] flex-col gap-3">
<div class="flex flex-col gap-2">
<label for="notice-title" class="flex flex-col gap-1">
<span class="text-lg font-semibold text-contrast"> Title </span>
</label>
<input
id="notice-title"
v-model="newNoticeTitle"
placeholder="E.g. Maintenance"
type="text"
autocomplete="off"
/>
</div>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<label for="notice-message" class="flex flex-col gap-1"> <label for="notice-message" class="flex flex-col gap-1">
<span class="text-lg font-semibold text-contrast"> <span class="text-lg font-semibold text-contrast">
@ -13,8 +25,8 @@
<span class="text-brand-red">*</span> <span class="text-brand-red">*</span>
</span> </span>
</label> </label>
<div class="textarea-wrapper"> <div class="textarea-wrapper h-32">
<textarea id="notice-message" v-model="newNoticeMessage" maxlength="256" /> <textarea id="notice-message" v-model="newNoticeMessage" />
</div> </div>
</div> </div>
<div class="flex items-center justify-between gap-2"> <div class="flex items-center justify-between gap-2">
@ -73,6 +85,7 @@
: trimmedMessage : trimmedMessage
" "
:dismissable="newNoticeDismissable" :dismissable="newNoticeDismissable"
:title="trimmedTitle"
preview preview
/> />
</div> </div>
@ -197,6 +210,7 @@
:level="notice.level" :level="notice.level"
:message="notice.message" :message="notice.message"
:dismissable="notice.dismissable" :dismissable="notice.dismissable"
:title="notice.title"
preview preview
/> />
<div class="mt-4 flex items-center gap-2"> <div class="mt-4 flex items-center gap-2">
@ -285,6 +299,7 @@ const newNoticeLevel = ref(levelOptions[0]);
const newNoticeDismissable = ref(false); const newNoticeDismissable = ref(false);
const newNoticeMessage = ref(""); const newNoticeMessage = ref("");
const newNoticeScheduledDate = ref<string>(); const newNoticeScheduledDate = ref<string>();
const newNoticeTitle = ref<string>();
const newNoticeExpiresDate = ref<string>(); const newNoticeExpiresDate = ref<string>();
function openNewNoticeModal() { function openNewNoticeModal() {
@ -303,6 +318,7 @@ function startEditing(notice: ServerNoticeType, assignments: boolean = false) {
newNoticeLevel.value = levelOptions.find((x) => x.id === notice.level) ?? levelOptions[0]; newNoticeLevel.value = levelOptions.find((x) => x.id === notice.level) ?? levelOptions[0];
newNoticeDismissable.value = notice.dismissable; newNoticeDismissable.value = notice.dismissable;
newNoticeMessage.value = notice.message; newNoticeMessage.value = notice.message;
newNoticeTitle.value = notice.title;
newNoticeScheduledDate.value = dayjs(notice.announce_at).format(DATE_TIME_FORMAT); newNoticeScheduledDate.value = dayjs(notice.announce_at).format(DATE_TIME_FORMAT);
newNoticeExpiresDate.value = notice.expires newNoticeExpiresDate.value = notice.expires
? dayjs(notice.expires).format(DATE_TIME_FORMAT) ? dayjs(notice.expires).format(DATE_TIME_FORMAT)
@ -338,6 +354,7 @@ async function deleteNotice(notice: ServerNoticeType) {
} }
const trimmedMessage = computed(() => newNoticeMessage.value?.trim()); const trimmedMessage = computed(() => newNoticeMessage.value?.trim());
const trimmedTitle = computed(() => newNoticeTitle.value?.trim());
const noticeSubmitError = computed(() => { const noticeSubmitError = computed(() => {
let error: undefined | string; let error: undefined | string;
@ -372,13 +389,14 @@ async function saveChanges() {
method: "PATCH", method: "PATCH",
body: { body: {
message: newNoticeMessage.value, message: newNoticeMessage.value,
title: trimmedTitle.value,
level: newNoticeLevel.value.id, level: newNoticeLevel.value.id,
dismissable: newNoticeDismissable.value, dismissable: newNoticeDismissable.value,
announce_at: newNoticeScheduledDate.value announce_at: newNoticeScheduledDate.value
? dayjs(newNoticeScheduledDate.value).toISOString() ? dayjs(newNoticeScheduledDate.value).toISOString()
: dayjs().toISOString(), : dayjs().toISOString(),
expires: newNoticeExpiresDate.value expires: newNoticeExpiresDate.value
? dayjs(newNoticeScheduledDate.value).toISOString() ? dayjs(newNoticeExpiresDate.value).toISOString()
: undefined, : undefined,
}, },
}).catch((err) => { }).catch((err) => {
@ -402,10 +420,15 @@ async function createNotice() {
method: "POST", method: "POST",
body: { body: {
message: newNoticeMessage.value, message: newNoticeMessage.value,
title: trimmedTitle.value,
level: newNoticeLevel.value.id, level: newNoticeLevel.value.id,
dismissable: newNoticeDismissable.value, dismissable: newNoticeDismissable.value,
announce_at: newNoticeScheduledDate.value ?? dayjs().toISOString(), announce_at: newNoticeScheduledDate.value
expires: newNoticeExpiresDate.value, ? dayjs(newNoticeScheduledDate.value).toISOString()
: dayjs().toISOString(),
expires: newNoticeExpiresDate.value
? dayjs(newNoticeExpiresDate.value).toISOString()
: undefined,
}, },
}).catch((err) => { }).catch((err) => {
app.$notify({ app.$notify({

View File

@ -10,6 +10,7 @@
:level="notice.level" :level="notice.level"
:message="notice.message" :message="notice.message"
:dismissable="notice.dismissable" :dismissable="notice.dismissable"
:title="notice.title"
class="w-full" class="w-full"
@dismiss="() => dismissNotice(notice.id)" @dismiss="() => dismissNotice(notice.id)"
/> />

View File

@ -1,7 +1,15 @@
<template> <template>
<Admonition :type="NOTICE_TYPE[props.level]"> <Admonition :type="NOTICE_TYPE[props.level]">
<template #header> <template #header>
{{ formatMessage(heading) }} <template v-if="!hideDefaultTitle">
{{ formatMessage(heading) }}
</template>
<template v-if="title">
<template v-if="hideDefaultTitle">
{{ title.substring(1) }}
</template>
<template v-else> - {{ title }}</template>
</template>
</template> </template>
<template #actions> <template #actions>
<ButtonStyled v-if="dismissable" circular> <ButtonStyled v-if="dismissable" circular>
@ -36,12 +44,18 @@ const props = withDefaults(
message: string message: string
dismissable: boolean dismissable: boolean
preview?: boolean preview?: boolean
title?: string
}>(), }>(),
{ {
preview: false, preview: false,
title: undefined,
}, },
) )
const hideDefaultTitle = computed(
() => props.title && props.title.length > 1 && props.title.startsWith('\\'),
)
const messages = defineMessages({ const messages = defineMessages({
info: { info: {
id: 'servers.notice.heading.info', id: 'servers.notice.heading.info',
@ -71,3 +85,8 @@ const NOTICE_TYPE: Record<string, 'info' | 'warning' | 'critical'> = {
const heading = computed(() => NOTICE_HEADINGS[props.level] ?? messages.info) const heading = computed(() => NOTICE_HEADINGS[props.level] ?? messages.info)
</script> </script>
<style scoped lang="scss">
.markdown-body > *:first-child {
margin-top: 0;
}
</style>

View File

@ -256,6 +256,7 @@ export type Report = {
export type ServerNotice = { export type ServerNotice = {
id: number id: number
message: string message: string
title?: string
level: string level: string
dismissable: boolean dismissable: boolean
announce_at: string announce_at: string