From 653c71dad51cdf858997159973755ea2d66875e4 Mon Sep 17 00:00:00 2001 From: Kaity A Date: Sun, 12 Feb 2023 01:19:43 +0000 Subject: [PATCH] Enable reply update/display in detailed view. (#9606) This PR establishes a new replied note stream update for subscribed notes, which gets fired off whenever a note receives a reply and the user is subscribed to the note for updates. It specifically does not provide note details as part of the update, just the note id of the reply, so that they must go and retrieve the note and be subject to the proper permission and visibility checks. The detailed note component has then been updated to watch for the replied notification so it can add new replies to the thread as they are created. This allows both seeing new replies while on the page, and also to see your own replies appear after you post them without having to reload the page. This PR relies on https://codeberg.org/calckey/calckey.js/pulls/2 to add the replied type to the calkey.js module. Co-authored-by: Kaity A Reviewed-on: https://codeberg.org/calckey/calckey/pulls/9606 Co-authored-by: Kaity A Co-committed-by: Kaity A --- .../backend/src/server/api/stream/types.ts | 3 +++ packages/backend/src/services/note/create.ts | 8 +++++- .../client/src/components/MkNoteDetailed.vue | 27 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts index 837f42c871..b35c599bde 100644 --- a/packages/backend/src/server/api/stream/types.ts +++ b/packages/backend/src/server/api/stream/types.ts @@ -135,6 +135,9 @@ export interface NoteStreamTypes { reaction: string; userId: User["id"]; }; + replied: { + id: Note["id"]; + }; } type NoteStreamEventTypes = { [key in keyof NoteStreamTypes]: { diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index 210ea77710..b37b160fbe 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -1,6 +1,6 @@ import * as mfm from "mfm-js"; import es from "../../db/elasticsearch.js"; -import { publishMainStream, publishNotesStream } from "@/services/stream.js"; +import { publishMainStream, publishNotesStream, publishNoteStream } from "@/services/stream.js"; import DeliverManager from "@/remote/activitypub/deliver-manager.js"; import renderNote from "@/remote/activitypub/renderer/note.js"; import renderCreate from "@/remote/activitypub/renderer/create.js"; @@ -430,6 +430,12 @@ export default async ( } publishNotesStream(note); + if (note.replyId != null) { + // Only provide the reply note id here as the recipient may not be authorized to see the note. + publishNoteStream(note.replyId, "replied", { + id: note.id, + }); + } const webhooks = await getActiveWebhooks().then((webhooks) => webhooks.filter((x) => x.userId === user.id && x.on.includes("note")), diff --git a/packages/client/src/components/MkNoteDetailed.vue b/packages/client/src/components/MkNoteDetailed.vue index dd6187d7e4..fab06f1ab6 100644 --- a/packages/client/src/components/MkNoteDetailed.vue +++ b/packages/client/src/components/MkNoteDetailed.vue @@ -142,6 +142,8 @@ import { i18n } from '@/i18n'; import { getNoteMenu } from '@/scripts/get-note-menu'; import { useNoteCapture } from '@/scripts/use-note-capture'; import { deepClone } from '@/scripts/clone'; +import { stream } from '@/stream'; +import { NoteUpdatedEvent } from 'calckey-js/built/streaming.types'; const router = useRouter(); @@ -302,6 +304,31 @@ if (appearNote.replyId) { conversation.value = res.reverse(); }); } + +function onNoteReplied(noteData: NoteUpdatedEvent): void { + const { type, id, body } = noteData; + if (type === 'replied' && id === appearNote.id) { + const { id: createdId } = body; + + os.api('notes/show', { + noteId: createdId, + }).then(note => { + if (note.replyId === appearNote.id) { + replies.value.unshift(note); + directReplies.value.unshift(note); + } + }); + } + +} + +onMounted(() => { + stream.on("noteUpdated", onNoteReplied); +}); + +onUnmounted(() => { + stream.off("noteUpdated", onNoteReplied); +});