diff --git a/packages/backend/src/models/repositories/channel.ts b/packages/backend/src/models/repositories/channel.ts index 857470f4ec..809129db6c 100644 --- a/packages/backend/src/models/repositories/channel.ts +++ b/packages/backend/src/models/repositories/channel.ts @@ -40,6 +40,7 @@ export const ChannelRepository = db.getRepository(Channel).extend({ name: channel.name, description: channel.description, userId: channel.userId, + bannerId: channel.bannerId, bannerUrl: banner ? DriveFiles.getPublicUrl(banner, false) : null, usersCount: channel.usersCount, notesCount: channel.notesCount, diff --git a/packages/backend/src/models/schema/channel.ts b/packages/backend/src/models/schema/channel.ts index 67833cb0dd..d3ec222c8d 100644 --- a/packages/backend/src/models/schema/channel.ts +++ b/packages/backend/src/models/schema/channel.ts @@ -36,6 +36,13 @@ export const packedChannelSchema = { nullable: true, optional: false, }, + bannerId: { + type: "string", + optional: false, + nullable: true, + format: "id", + example: "xxxxxxxxxx", + }, notesCount: { type: "number", nullable: false, @@ -57,5 +64,10 @@ export const packedChannelSchema = { optional: false, format: "id", }, + hasUnreadNote: { + type: "boolean", + optional: true, + nullable: false, + }, }, } as const; diff --git a/packages/backend/src/server/api/endpoints/channels/update.ts b/packages/backend/src/server/api/endpoints/channels/update.ts index 0de7a837a1..fdd21da65f 100644 --- a/packages/backend/src/server/api/endpoints/channels/update.ts +++ b/packages/backend/src/server/api/endpoints/channels/update.ts @@ -83,7 +83,7 @@ export default define(meta, paramDef, async (ps, me) => { await Channels.update(channel.id, { ...(ps.name !== undefined ? { name: ps.name } : {}), ...(ps.description !== undefined ? { description: ps.description } : {}), - ...(banner ? { bannerId: banner.id } : {}), + ...(banner ? { bannerId: banner.id } : { bannerId: null }), }); return await Channels.pack(channel.id, me); diff --git a/packages/client/src/pages/channel-editor.vue b/packages/client/src/pages/channel-editor.vue index 60bcfe990e..3791a98d05 100644 --- a/packages/client/src/pages/channel-editor.vue +++ b/packages/client/src/pages/channel-editor.vue @@ -50,6 +50,7 @@ import { useRouter } from "@/router"; import { definePageMetadata } from "@/scripts/page-metadata"; import { i18n } from "@/i18n"; import icon from "@/scripts/icon"; +import type { entities } from "firefish-js"; const router = useRouter(); @@ -57,26 +58,24 @@ const props = defineProps<{ channelId?: string; }>(); -const channel = ref(null); -const name = ref(null); -const description = ref(null); +const channel = ref(null); +const name = ref(""); +const description = ref(""); const bannerUrl = ref(null); const bannerId = ref(null); -watch( - () => bannerId.value, - async () => { - if (bannerId.value == null) { - bannerUrl.value = null; - } else { - bannerUrl.value = ( - await os.api("drive/files/show", { - fileId: bannerId.value, - }) - ).url; - } - }, -); +let bannerUrlUpdated = false; + +/** + * Set banner url and id when we already know the url + * Prevent redundant network requests from being sent + */ +function setBanner(opt: { bannerId: string | null; bannerUrl: string | null }) { + bannerUrlUpdated = true; + bannerUrl.value = opt.bannerUrl; + bannerId.value = opt.bannerId; + bannerUrlUpdated = false; +} async function fetchChannel() { if (props.channelId == null) return; @@ -86,23 +85,44 @@ async function fetchChannel() { }); name.value = channel.value.name; - description.value = channel.value.description; - bannerId.value = channel.value.bannerId; - bannerUrl.value = channel.value.bannerUrl; + description.value = channel.value.description ?? ""; + setBanner(channel.value); } -fetchChannel(); +await fetchChannel(); + +watch(bannerId, async () => { + if (bannerUrlUpdated) { + bannerUrlUpdated = false; + return; + } + if (bannerId.value == null) { + bannerUrl.value = null; + } else { + bannerUrl.value = ( + await os.api("drive/files/show", { + fileId: bannerId.value, + }) + ).url; + } +}); function save() { - const params = { + const params: { + name: string; + description: string; + bannerId: string | null; + } = { name: name.value, description: description.value, bannerId: bannerId.value, }; if (props.channelId) { - params.channelId = props.channelId; - os.api("channels/update", params).then(() => { + os.api("channels/update", { + ...params, + channelId: props.channelId, + }).then(() => { os.success(); }); } else { @@ -113,14 +133,20 @@ function save() { } } -function setBannerImage(evt) { +function setBannerImage(evt: MouseEvent) { selectFile(evt.currentTarget ?? evt.target, null).then((file) => { - bannerId.value = file.id; + setBanner({ + bannerId: file.id, + bannerUrl: file.url, + }); }); } function removeBannerImage() { - bannerId.value = null; + setBanner({ + bannerId: null, + bannerUrl: null, + }); } const headerActions = computed(() => []);