Skip to content

fix(desktop): keep thread-open affordance in archived channels - #4012

Merged
tlongwell-block merged 1 commit into
block:mainfrom
treywood:fix/archived-channel-thread-affordance
Aug 1, 2026
Merged

fix(desktop): keep thread-open affordance in archived channels#4012
tlongwell-block merged 1 commit into
block:mainfrom
treywood:fix/archived-channel-thread-affordance

Conversation

@treywood

@treywood treywood commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Problem

Threaded replies "disappeared" from archived Buzz channels: the "N replies →" summary row and the huddle-started "View thread" button vanished, so existing threads were unreachable from the channel timeline. The thread data was intact — this was a UI gate, not data loss.

Root cause

A single onReply prop drove two distinct affordances:

  • the compose affordances (hover "Reply" button, inline reply target), and
  • the view affordances ("N replies →" summary row, huddle "View thread").

ChannelPane nulls onReply on archived channels to keep them read-only. That correctly hid composing — but also hid the view affordances, since they keyed off the same prop.

Fix

Two independent props, one per concern:

  • onReply drives the compose affordances and is gated on archivedAt — nulled on archived channels, so no new replies can be started.
  • onOpenThread drives the view affordances and is passed regardless of archived state, threaded ChannelPane → MessageTimeline → TimelineMessageList → MessageRow.

Opening a thread on an archived channel is read-only: the thread panel's composer is independently gated via isComposerDisabled (includes archivedAt !== null, ChannelPane.tsx:318).

Before

Screenshot 2026-07-31 at 20 26 00

After

Screenshot 2026-07-31 at 20 28 04

Validation

  • pnpm typecheck clean
  • biome lint clean on touched files
  • full pnpm test suite green (3885 tests)
  • pre-push branch-skew / desktop-check / desktop-test hooks passed

treywood added a commit to treywood/buzz that referenced this pull request Jul 31, 2026
Follow-on to the archived-channel thread-open fix (Gordon's review of
block#4012). The huddle-started attachment's "View thread" button had the same
conflated-prop bug: MessageRow passed `onReply` straight through as
HuddleAttachment's `onOpenThread`, so on an archived channel (`onReply`
undefined) the button disappeared — the same class of bug as the timeline
summary row, just a different entry point.

Give MessageRow its own `onOpenThread` prop and feed HuddleAttachment via
the shared resolver so the "View thread" navigation survives archived
state while composing stays gated. Opening the thread is safe: the thread
panel's composer is independently gated via `isComposerDisabled`.

Also lift the resolver into `lib/threadOpenHandler.ts` as
`resolveThreadOpenHandler` so MessageRow and TimelineMessageList share one
source of truth without an import cycle (TimelineMessageList imports
MessageRow). Renamed from the ui-local `resolveThreadSummaryOpenHandler`;
test moved to `lib/threadOpenHandler.test.mjs` and extended to document
both affordances.

Co-authored-by: Trey Wood <treyw@squareup.com>
Signed-off-by: Trey Wood <treyw@squareup.com>
@treywood
treywood force-pushed the fix/archived-channel-thread-affordance branch 2 times, most recently from a667ca9 to 108f38d Compare July 31, 2026 21:27
Archived channels hid every thread-open affordance in the channel
timeline — the "N replies →" summary row and the huddle-started "View
thread" button — so existing threads were unreachable from the channel
(though still reachable via the inbox "view in thread" entry point). The
thread data was intact; this was a UI gate, not data loss.

Root cause: one prop did double duty. `onReply` drove both the compose
affordances (the hover "Reply" button, inline reply target) and the
view affordances (summary row, huddle "View thread"). ChannelPane nulls
`onReply` on archived channels to enforce read-only — which correctly
hid composing, but inadvertently hid the view affordances too since they
keyed off the same prop.

Fully separate the two concerns into distinct props:
- `onReply` drives only the compose affordances, and stays gated on
  archived (nulled) so no new replies can be started.
- `onOpenThread` drives only the view affordances (summary row, huddle
  "View thread"), and is passed regardless of archived state, threaded
  `ChannelPane → MessageTimeline → TimelineMessageList → MessageRow`.

The two props are now independent — no fallback coupling. The one caller
that previously relied on the shared prop, MessageThreadPanel's reply
rows, now passes `onOpenThread={onExpandReplies}` explicitly.

Opening a thread on an archived channel is safe: the thread panel's
composer is independently gated via `isComposerDisabled`, which includes
`archivedAt !== null` (ChannelPane.tsx:318), so it opens read-only.

Co-authored-by: Trey Wood <treyw@squareup.com>
Signed-off-by: Trey Wood <treyw@squareup.com>
@treywood
treywood force-pushed the fix/archived-channel-thread-affordance branch from 108f38d to 40e29a9 Compare July 31, 2026 21:37
@treywood
treywood marked this pull request as ready for review July 31, 2026 21:43
@treywood
treywood requested a review from a team as a code owner July 31, 2026 21:43
@tlongwell-block
tlongwell-block merged commit 8e81afa into block:main Aug 1, 2026
26 checks passed
tlongwell-block pushed a commit to Kampe/buzz that referenced this pull request Aug 1, 2026
* origin/main: (98 commits)
  docs: note that addressable channel events scope by d, not h (block#4103)
  docs: fix stale kind count, quick-start numbering, and empty Further Reading (block#2613)
  fix(desktop): keep thread-open affordance in archived channels (block#4012)
  docs: add one-click Railway deploy for a hosted relay (block#2733)
  fix(desktop): point Oh My Pi preset at omp.sh (block#3516)
  fix(mesh): stop restarting a busy or loading shared-compute node (block#3909)
  fix(desktop): preserve first huddle speech (block#3962)
  feat(desktop): Agent Trading Cards — mintable agent-snapshot card PNGs with optional NIP-44 lock (block#3278)
  fix(buzz-acp): thread cache-read tokens into NIP-AM kind:44200 events (block#3999)
  feat(relay): accept kind:30621 multi-repo projects at ingest (block#3171)
  fix(release): preserve main in desktop PR body (block#3979)
  chore(release): release Buzz Desktop version 0.5.3 (block#3972)
  fix(release): require exact-head approval for desktop tags (block#3973)
  fix(release): make desktop tagging squash-safe (block#3965)
  Revert "chore(release): release Buzz Desktop version 0.5.3" (block#3960)
  docs(nips): add single-coordinate manual-unread override layer and verification model to NIP-RS (block#2864)
  chore(release): release Buzz Desktop version 0.5.3
  fix(release): make immutable desktop release operable (block#3943)
  feat(desktop): import local Pocket voices (block#3259)
  fix(desktop): open profiles from avatars (block#3751)
  ...

Signed-off-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz>
joahg added a commit to joahg/buzz-dev-mode that referenced this pull request Aug 1, 2026
…-style

* origin/main:
  fix(relay): allow open relays to set their NIP-11 workspace icon (kind:9033) (block#3998)
  docs: note that addressable channel events scope by d, not h (block#4103)
  docs: fix stale kind count, quick-start numbering, and empty Further Reading (block#2613)
  fix(desktop): keep thread-open affordance in archived channels (block#4012)

Signed-off-by: Joah Gerstenberg <joah@squareup.com>
tellaho added a commit that referenced this pull request Aug 1, 2026
* origin/main: (24 commits)
  perf(relay): serve relay-membership checks from the read replica (#4124)
  chore(deps): bump nostr-relay-pool for RUSTSEC-2026-0224 (#4139)
  docs(nostr): document #h requirement for live reaction subscriptions (#3487)
  docs(chart): fix ArgoCD example for native OCI sources (full artifact repoURL + path) (#3426)
  docs(readme): clarify which release asset to download per platform (#3481)
  fix(relay): allow open relays to set their NIP-11 workspace icon (kind:9033) (#3998)
  docs: note that addressable channel events scope by d, not h (#4103)
  docs: fix stale kind count, quick-start numbering, and empty Further Reading (#2613)
  fix(desktop): keep thread-open affordance in archived channels (#4012)
  docs: add one-click Railway deploy for a hosted relay (#2733)
  fix(desktop): point Oh My Pi preset at omp.sh (#3516)
  fix(mesh): stop restarting a busy or loading shared-compute node (#3909)
  fix(desktop): preserve first huddle speech (#3962)
  feat(desktop): Agent Trading Cards — mintable agent-snapshot card PNGs with optional NIP-44 lock (#3278)
  fix(buzz-acp): thread cache-read tokens into NIP-AM kind:44200 events (#3999)
  feat(relay): accept kind:30621 multi-repo projects at ingest (#3171)
  fix(release): preserve main in desktop PR body (#3979)
  chore(release): release Buzz Desktop version 0.5.3 (#3972)
  fix(release): require exact-head approval for desktop tags (#3973)
  fix(release): make desktop tagging squash-safe (#3965)
  ...

Signed-off-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
tellaho added a commit that referenced this pull request Aug 1, 2026
…onfig

* origin/main:
  perf(relay): serve relay-membership checks from the read replica (#4124)
  chore(deps): bump nostr-relay-pool for RUSTSEC-2026-0224 (#4139)
  docs(nostr): document #h requirement for live reaction subscriptions (#3487)
  docs(chart): fix ArgoCD example for native OCI sources (full artifact repoURL + path) (#3426)
  docs(readme): clarify which release asset to download per platform (#3481)
  fix(relay): allow open relays to set their NIP-11 workspace icon (kind:9033) (#3998)
  docs: note that addressable channel events scope by d, not h (#4103)
  docs: fix stale kind count, quick-start numbering, and empty Further Reading (#2613)
  fix(desktop): keep thread-open affordance in archived channels (#4012)
  docs: add one-click Railway deploy for a hosted relay (#2733)
  fix(desktop): point Oh My Pi preset at omp.sh (#3516)
  fix(mesh): stop restarting a busy or loading shared-compute node (#3909)
  fix(desktop): preserve first huddle speech (#3962)
  feat(desktop): Agent Trading Cards — mintable agent-snapshot card PNGs with optional NIP-44 lock (#3278)
  fix(buzz-acp): thread cache-read tokens into NIP-AM kind:44200 events (#3999)
  feat(relay): accept kind:30621 multi-repo projects at ingest (#3171)
  fix(release): preserve main in desktop PR body (#3979)
  chore(release): release Buzz Desktop version 0.5.3 (#3972)
  fix(release): require exact-head approval for desktop tags (#3973)
  fix(release): make desktop tagging squash-safe (#3965)

Signed-off-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
tellaho added a commit that referenced this pull request Aug 2, 2026
- Incorporate upstream desktop changes required by the pre-push overlap guard
- Preserve the link preview thumbnail stabilization work on the updated base

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>

* origin/main: (26 commits)
  docs: formal spec for remote agents and their management (#3748)
  fix(nip-oa): accept raw Nostr tag form in parse_json_array (#4203)
  perf(relay): serve relay-membership checks from the read replica (#4124)
  chore(deps): bump nostr-relay-pool for RUSTSEC-2026-0224 (#4139)
  docs(nostr): document #h requirement for live reaction subscriptions (#3487)
  docs(chart): fix ArgoCD example for native OCI sources (full artifact repoURL + path) (#3426)
  docs(readme): clarify which release asset to download per platform (#3481)
  fix(relay): allow open relays to set their NIP-11 workspace icon (kind:9033) (#3998)
  docs: note that addressable channel events scope by d, not h (#4103)
  docs: fix stale kind count, quick-start numbering, and empty Further Reading (#2613)
  fix(desktop): keep thread-open affordance in archived channels (#4012)
  docs: add one-click Railway deploy for a hosted relay (#2733)
  fix(desktop): point Oh My Pi preset at omp.sh (#3516)
  fix(mesh): stop restarting a busy or loading shared-compute node (#3909)
  fix(desktop): preserve first huddle speech (#3962)
  feat(desktop): Agent Trading Cards — mintable agent-snapshot card PNGs with optional NIP-44 lock (#3278)
  fix(buzz-acp): thread cache-read tokens into NIP-AM kind:44200 events (#3999)
  feat(relay): accept kind:30621 multi-repo projects at ingest (#3171)
  fix(release): preserve main in desktop PR body (#3979)
  chore(release): release Buzz Desktop version 0.5.3 (#3972)
  ...

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
kaalph pushed a commit to kaalph/buzz that referenced this pull request Aug 21, 2026
- Incorporate upstream desktop changes required by the pre-push overlap guard
- Preserve the link preview thumbnail stabilization work on the updated base

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>

* origin/main: (26 commits)
  docs: formal spec for remote agents and their management (block#3748)
  fix(nip-oa): accept raw Nostr tag form in parse_json_array (block#4203)
  perf(relay): serve relay-membership checks from the read replica (block#4124)
  chore(deps): bump nostr-relay-pool for RUSTSEC-2026-0224 (block#4139)
  docs(nostr): document #h requirement for live reaction subscriptions (block#3487)
  docs(chart): fix ArgoCD example for native OCI sources (full artifact repoURL + path) (block#3426)
  docs(readme): clarify which release asset to download per platform (block#3481)
  fix(relay): allow open relays to set their NIP-11 workspace icon (kind:9033) (block#3998)
  docs: note that addressable channel events scope by d, not h (block#4103)
  docs: fix stale kind count, quick-start numbering, and empty Further Reading (block#2613)
  fix(desktop): keep thread-open affordance in archived channels (block#4012)
  docs: add one-click Railway deploy for a hosted relay (block#2733)
  fix(desktop): point Oh My Pi preset at omp.sh (block#3516)
  fix(mesh): stop restarting a busy or loading shared-compute node (block#3909)
  fix(desktop): preserve first huddle speech (block#3962)
  feat(desktop): Agent Trading Cards — mintable agent-snapshot card PNGs with optional NIP-44 lock (block#3278)
  fix(buzz-acp): thread cache-read tokens into NIP-AM kind:44200 events (block#3999)
  feat(relay): accept kind:30621 multi-repo projects at ingest (block#3171)
  fix(release): preserve main in desktop PR body (block#3979)
  chore(release): release Buzz Desktop version 0.5.3 (block#3972)
  ...

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
BradGroux pushed a commit to BradGroux/buzz that referenced this pull request Aug 23, 2026
…#4012)

## Problem

Threaded replies "disappeared" from archived Buzz channels: the **"N
replies →"** summary row and the huddle-started **"View thread"** button
vanished, so existing threads were unreachable from the channel
timeline. The thread data was intact — this was a UI gate, not data
loss.

## Root cause

A single `onReply` prop drove two distinct affordances:
- the **compose** affordances (hover "Reply" button, inline reply
target), and
- the **view** affordances ("N replies →" summary row, huddle "View
thread").

`ChannelPane` nulls `onReply` on archived channels to keep them
read-only. That correctly hid composing — but also hid the view
affordances, since they keyed off the same prop.

## Fix

Two independent props, one per concern:

- **`onReply`** drives the compose affordances and is gated on
`archivedAt` — nulled on archived channels, so no new replies can be
started.
- **`onOpenThread`** drives the view affordances and is passed
regardless of archived state, threaded `ChannelPane → MessageTimeline →
TimelineMessageList → MessageRow`.

Opening a thread on an archived channel is read-only: the thread panel's
composer is independently gated via `isComposerDisabled` (includes
`archivedAt !== null`, `ChannelPane.tsx:318`).

### Before
<img width="811" height="794" alt="Screenshot 2026-07-31 at 20 26 00"
src="https://github.com/user-attachments/assets/670d9db4-30da-4c6d-97dc-275b5dbebca8"
/>

### After
<img width="873" height="791" alt="Screenshot 2026-07-31 at 20 28 04"
src="https://github.com/user-attachments/assets/88525231-2539-4eb3-8117-8e58a0cb3855"
/>

## Validation

- `pnpm typecheck` clean
- biome lint clean on touched files
- full `pnpm test` suite green (3885 tests)
- pre-push `branch-skew` / `desktop-check` / `desktop-test` hooks passed

Signed-off-by: Trey Wood <treyw@squareup.com>
Co-authored-by: npub14h0tw3uj7jm77qfxcwn6um2s5h55l0klrt2w9srzp3m3yvjc0mpsjsuk6e <addeb74792f4b7ef0126c3a7ae6d50a5e94fbedf1ad4e2c0620c771232587ec3@buzz.block.builderlab.xyz>
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.

2 participants