Skip to content

feat(desktop): "Also send to #channel" broadcast opt-in for thread replies#1890

Open
yti93 wants to merge 1 commit into
block:mainfrom
yti93:youssef/thread-reply-broadcast
Open

feat(desktop): "Also send to #channel" broadcast opt-in for thread replies#1890
yti93 wants to merge 1 commit into
block:mainfrom
yti93:youssef/thread-reply-broadcast

Conversation

@yti93

@yti93 yti93 commented Jul 15, 2026

Copy link
Copy Markdown

Adds Slack's "Also send to #channel" to the desktop thread composer, using the NIP-CW broadcast reply semantics the protocol already defines (["broadcast", "1"]). The relay ingest, SDK, CLI, and both clients' rendering already support broadcast replies — this PR adds the missing authoring surface on desktop.

What

A checkbox under the thread composer lets the author surface their next reply on the channel timeline as well as in its thread:

  • Offered only where the spec allows it: NIP-CW defines broadcast for depth-1 replies, so the toggle appears only when replying directly to a root thread head (canBroadcastThreadReply). It hides when targeting a nested reply, when the thread head is itself a reply, or while editing.
  • One-shot, like Slack: a successful send consumes the opt-in; the next reply starts unchecked. A failed send keeps it checked so a retry still broadcasts. Switching threads clears it (state keyed to the thread-head id, same pattern as collapsedThreadHeadId).
  • Belt and braces at submit time: the captured send context re-checks eligibility, so a checkbox checked before switching to a nested reply target can never emit a depth ≥ 2 broadcast.
  • DM channels label the toggle "Also send as direct message".

How

  • events.rs: build_message(..., broadcast) appends ["broadcast", "1"] to replies only — the flag is inert without a thread_ref, so non-reply sends can never carry the tag. The managed-agent and huddle-transcription paths pass false.
  • send_channel_message accepts broadcast: Option<bool> over IPC; the TS bridge (sendChannelMessage) threads it through for replies only.
  • Optimistic message and server-echo tag reconstruction include the tag, so the reply appears on the timeline immediately (buildMainTimelineEntries already surfaces broadcast replies).
  • The submit-time capture path (ThreadSendContext, now a shared type replacing four inline copies) carries broadcast through the mention-flow confirmation dialog, so a deferred send after a non-member mention prompt still broadcasts.
  • E2E mock bridge mirrors the relay's stored-event shape for broadcast replies.

Testing

  • Rust: build_message emits the tag on replies when requested, never on top-level messages (message_reply_broadcast_tag, message_top_level_ignores_broadcast).
  • Unit: buildReplyTags tag shape/ordering with broadcast; canBroadcastThreadReply eligibility matrix (threading.test.mjs, threadPanel.test.mjs).
  • Playwright (thread-broadcast.spec.ts): broadcast reply lands on the channel timeline while a plain reply doesn't; opt-in resets after send; toggle hides when targeting a nested reply.
  • pnpm check, tsc --noEmit, biome, clippy, cargo test (Tauri, 1400 pass), desktop unit suite (2893 pass) all green. File-size guard overrides bumped per the documented convention (three files already on the queued-to-split list).

Slack-style NIP-CW broadcast: a checkbox under the thread composer lets
the author surface a direct reply to the thread head on the channel
timeline as well as in its thread.

- events.rs build_message takes broadcast and appends ["broadcast","1"]
  to replies only; send_channel_message threads it through the IPC
  boundary (inert for non-replies and the managed-agent path)
- thread panel offers the toggle only for depth-1 replies to a root
  thread head (canBroadcastThreadReply); the opt-in is one-shot and
  clears on thread switch, consumed by a successful send
- optimistic message + server-echo tag reconstruction carry the tag so
  the reply appears on the timeline immediately
- e2e mock bridge mirrors the relay's stored-event shape
@yti93 yti93 requested a review from a team as a code owner July 15, 2026 02:00
@yti93

yti93 commented Jul 15, 2026

Copy link
Copy Markdown
Author

Desktop screenshots (mock bridge)

The toggle — replying directly to a root thread head offers the one-shot opt-in under the composer:

01-broadcast-toggle

Checked before send:

02-broadcast-checked

After send — the reply lands in the thread and on the #general timeline (bottom), the thread summary shows "1 reply", and the checkbox has reset for the next reply:

03-broadcast-on-timeline

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant