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 <supakaity@blahaj.zone>
Reviewed-on: https://codeberg.org/calckey/calckey/pulls/9606
Co-authored-by: Kaity A <supakaity@noreply.codeberg.org>
Co-committed-by: Kaity A <supakaity@noreply.codeberg.org>
This commit is contained in:
Kaity A 2023-02-12 01:19:43 +00:00 committed by Kainoa Kanter
parent ace8350043
commit 653c71dad5
3 changed files with 37 additions and 1 deletions

View File

@ -135,6 +135,9 @@ export interface NoteStreamTypes {
reaction: string; reaction: string;
userId: User["id"]; userId: User["id"];
}; };
replied: {
id: Note["id"];
};
} }
type NoteStreamEventTypes = { type NoteStreamEventTypes = {
[key in keyof NoteStreamTypes]: { [key in keyof NoteStreamTypes]: {

View File

@ -1,6 +1,6 @@
import * as mfm from "mfm-js"; import * as mfm from "mfm-js";
import es from "../../db/elasticsearch.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 DeliverManager from "@/remote/activitypub/deliver-manager.js";
import renderNote from "@/remote/activitypub/renderer/note.js"; import renderNote from "@/remote/activitypub/renderer/note.js";
import renderCreate from "@/remote/activitypub/renderer/create.js"; import renderCreate from "@/remote/activitypub/renderer/create.js";
@ -430,6 +430,12 @@ export default async (
} }
publishNotesStream(note); 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) => const webhooks = await getActiveWebhooks().then((webhooks) =>
webhooks.filter((x) => x.userId === user.id && x.on.includes("note")), webhooks.filter((x) => x.userId === user.id && x.on.includes("note")),

View File

@ -142,6 +142,8 @@ import { i18n } from '@/i18n';
import { getNoteMenu } from '@/scripts/get-note-menu'; import { getNoteMenu } from '@/scripts/get-note-menu';
import { useNoteCapture } from '@/scripts/use-note-capture'; import { useNoteCapture } from '@/scripts/use-note-capture';
import { deepClone } from '@/scripts/clone'; import { deepClone } from '@/scripts/clone';
import { stream } from '@/stream';
import { NoteUpdatedEvent } from 'calckey-js/built/streaming.types';
const router = useRouter(); const router = useRouter();
@ -302,6 +304,31 @@ if (appearNote.replyId) {
conversation.value = res.reverse(); 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);
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>