Tag a comment into the room the event it answers lives in (#497)
This commit is contained in:
parent
e052191bb2
commit
ad480ad4a0
4 changed files with 39 additions and 1 deletions
|
|
@ -654,6 +654,8 @@ Acceptance:
|
|||
top-level comment.
|
||||
- Alice sees both and can add her own comment at the root, optionally attaching
|
||||
an image to it.
|
||||
- Every comment on an article posted in a room is tagged into that room, so the
|
||||
relay handles it as part of the group.
|
||||
|
||||
### US-040 — React to a post with an emoji
|
||||
|
||||
|
|
@ -706,6 +708,8 @@ Acceptance:
|
|||
appends a post and increments the reply count in the header.
|
||||
- "Reply" on a single post shows "Replying to" that post, which can be cleared
|
||||
before submitting.
|
||||
- A reply to a thread in a room is tagged into that room, so the relay handles
|
||||
it as part of the group.
|
||||
- The thread's opening post carries an "OP" badge on every page.
|
||||
|
||||
### US-044 — Navigate a long thread
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {HOUR, MINUTE} from "@welshman/lib"
|
||||
import {LONG_FORM, MESSAGE, NOTE, makeEvent} from "@welshman/util"
|
||||
import {COMMENT, LONG_FORM, MESSAGE, NOTE, makeEvent, tagSpec, tagValue} from "@welshman/util"
|
||||
import type {SignedEvent} from "@welshman/util"
|
||||
import {Article, Comment, Thread} from "@welshman/domain"
|
||||
import type {Locator, Page} from "@playwright/test"
|
||||
|
|
@ -325,6 +325,7 @@ test("US-039 comment on an article", async ({seed, as}) => {
|
|||
space
|
||||
.kind(Article)
|
||||
.writer()
|
||||
.setRoom(space.url, "general")
|
||||
.setIdentifier("tending-the-garden")
|
||||
.setTitle("Tending the Garden")
|
||||
.setSummary("A short teaser about gardens.")
|
||||
|
|
@ -349,6 +350,15 @@ test("US-039 comment on an article", async ({seed, as}) => {
|
|||
// relay confirms it, so for a moment the page carries this text twice. Match the rendered comment.
|
||||
await expect(comment(bob, "The soil chapter is the good one.")).toBeVisible()
|
||||
|
||||
// A comment on a room event is a room event, so it carries the room the root lives in. Without
|
||||
// that tag the relay doesn't see it as part of the group, and neither its access rules nor a
|
||||
// room deletion ever reach it.
|
||||
await expect
|
||||
.poll(() =>
|
||||
getPublishedEvents(bob.context(), COMMENT).map(event => tagValue(tagSpec("h"), event.tags)),
|
||||
)
|
||||
.toEqual(["general"])
|
||||
|
||||
const carol = await as(users.carol, articlesPath)
|
||||
|
||||
await openArticle(carol, "Tending the Garden")
|
||||
|
|
@ -747,6 +757,13 @@ test("US-043 reply to a thread and to a specific post", async ({seed, as}) => {
|
|||
|
||||
await expect(bob.getByText("21 replies")).toBeVisible()
|
||||
|
||||
// The same for a thread reply, which goes out through a different composer.
|
||||
await expect
|
||||
.poll(() =>
|
||||
getPublishedEvents(bob.context(), COMMENT).map(event => tagValue(tagSpec("h"), event.tags)),
|
||||
)
|
||||
.toEqual(["lounge"])
|
||||
|
||||
// The thread's author is marked OP wherever their posts turn up, second page included.
|
||||
await bob.getByRole("button", {name: "2", exact: true}).click()
|
||||
await expect(bob.getByText("Page 2 of 2")).toBeVisible()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import {writable} from "svelte/store"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {tagSpec, tagValue} from "@welshman/util"
|
||||
import {publishToRelays} from "@welshman/app"
|
||||
import {Comment} from "@welshman/domain"
|
||||
import {isMobile, preventDefault} from "@lib/html"
|
||||
|
|
@ -28,6 +29,8 @@
|
|||
|
||||
const {url, event, parent, onCancel, onSubmit}: Props = $props()
|
||||
|
||||
const h = $derived(tagValue(tagSpec("h"), event.tags))
|
||||
|
||||
const draftKey = new DraftKey<Values>(`comment:${event.id}:${parent?.id ?? ""}`)
|
||||
const initialValues = draftKey.get()
|
||||
const uploading = writable(false)
|
||||
|
|
@ -54,6 +57,12 @@
|
|||
.setParentFromEvent(parent ?? event)
|
||||
.setProtected(await $relays.hasNip(url, 70))
|
||||
|
||||
// A comment on a room event is a room event too: an untagged one isn't visible to the
|
||||
// group at all, so the relay neither gates it with the room nor deletes it with it.
|
||||
if (h) {
|
||||
eventWriter.setRoom(url, h)
|
||||
}
|
||||
|
||||
const thunk = await command(eventWriter).then(publishToRelays([url]))
|
||||
const error = await thunk.waitForError()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import {onMount} from "svelte"
|
||||
import {writable} from "svelte/store"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {tagSpec, tagValue} from "@welshman/util"
|
||||
import {publishToRelays} from "@welshman/app"
|
||||
import {Comment} from "@welshman/domain"
|
||||
import {isMobile, preventDefault} from "@lib/html"
|
||||
|
|
@ -32,6 +33,7 @@
|
|||
}
|
||||
|
||||
const {url, event, parent, onClose, onClearParent, onSubmit}: Props = $props()
|
||||
const h = $derived(tagValue(tagSpec("h"), event.tags))
|
||||
const draftKey = new DraftKey<Values>(`reply:${event.id}:${parent?.id || ""}`)
|
||||
const initialValues = draftKey.get()
|
||||
const uploading = writable(false)
|
||||
|
|
@ -64,6 +66,12 @@
|
|||
.setParentFromEvent(event)
|
||||
.setProtected(await $relays.hasNip(url, 70))
|
||||
|
||||
// A comment on a room event is a room event too: an untagged one isn't visible to the
|
||||
// group at all, so the relay neither gates it with the room nor deletes it with it.
|
||||
if (h) {
|
||||
eventWriter.setRoom(url, h)
|
||||
}
|
||||
|
||||
const thunk = await command(eventWriter).then(publishToRelays([url]))
|
||||
|
||||
draftKey.clear()
|
||||
|
|
|
|||
Loading…
Reference in a new issue