Skip to content

fix(desktop): defer channel visibility change to Save - #5203

Merged
wesbillman merged 1 commit into
block:mainfrom
kchung:fix/channel-visibility-defer-save
Aug 7, 2026
Merged

fix(desktop): defer channel visibility change to Save#5203
wesbillman merged 1 commit into
block:mainfrom
kchung:fix/channel-visibility-defer-save

Conversation

@kchung

@kchung kchung commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Problem

In the Edit channel dialog, flipping visibility (Public <> Private) persisted immediately on selection, bypassing the Save changes button — while every other field (name, description, temporary, TTL) waited for an explicit save. This surprised users and gave no chance to cancel a flip, e.g. a private->public change that instantly exposes channel history.

Reported in the Buzz "Welcome" channel by Kevin Chung.

Root cause

The visibility dropdown was wired to handleConvertVisibility(), which called the update mutation on selection. This was intentional at the time (there was even an e2e test named 02 — visibility updates immediately and an "Updating…" spinner), but it is inconsistent with the rest of the dialog and is the surprising behavior reported.

Change (defer to Save)

  • Visibility becomes a deferred draft like the other fields: selecting a value updates local isPrivateDraft and marks the draft dirty. The change commits via handleSaveChannelEdits (which already handled visibility) on Save, and is discarded on Cancel.
  • The dialog title now reflects the pending draft (nextVisibility), so the pending choice is visible before saving.
  • The edit-dialog reset restores isPrivateDraft from server state.
  • Removed the now-dead handleConvertVisibility handler, isConvertingVisibility state, the channelIdRef race guard it needed, and the unused isPending/"Updating…" spinner path in ChannelPermissionsSettings (no caller passes isPending anymore).

Tests

  • Rewrote e2e 02 -> visibility defers to Save: select -> Save enabled -> title reflects draft -> Save -> persists; toggling back to the original value clears the draft and disables Save.
  • Extended 09 (cancel discards drafts) to also cover a visibility change.
  • Repurposed 10: the stale-update race it guarded is architecturally gone, so it now asserts an unsaved visibility draft does not leak across a channel switch.

Validation

  • pnpm typecheck — clean
  • biome check (changed files) — clean
  • pnpm test4497 passed / 0 failed
  • playwright test --project=smoke channel-controls10 passed

The Edit channel dialog persisted Public<>Private the instant a value was
selected, bypassing the Save changes button while every other field (name,
description, temporary, TTL) waited for an explicit save. This surprised
users and gave no chance to cancel a flip (e.g. a private->public change
that instantly exposes history).

Make visibility a deferred draft like the other fields: selecting a value
only updates local `isPrivateDraft` state and marks the draft dirty; the
change is committed by `handleSaveChannelEdits` (which already supports
visibility) when Save is clicked, and discarded on Cancel. The dialog
title now reflects the pending draft, and the edit-dialog reset restores
`isPrivateDraft` from server state.

Removes the now-unused `handleConvertVisibility` handler, the
`isConvertingVisibility` state, the `channelIdRef` race guard it needed,
and the dead `isPending`/"Updating…" spinner path in
`ChannelPermissionsSettings` (no caller passes `isPending` anymore).

Tests: rewrite channel-controls e2e `02` to assert deferred-save behavior
(select -> Save enabled -> Save -> persisted), extend `09` to cover
visibility discard-on-cancel, and repurpose `10` (the stale-update race is
architecturally gone) to assert an unsaved draft does not leak across a
channel switch.

Co-authored-by: Kevin Chung <chung@squareup.com>
Signed-off-by: Kevin Chung <chung@squareup.com>
@kchung
kchung requested a review from a team as a code owner August 7, 2026 16:55
@wesbillman

Copy link
Copy Markdown
Collaborator

Release review by Carl on Wes’s behalf at exact head 55e2c3c911ddc52d29e56ee4bca2eb77b289b5af: include this in the release once exact-head CI is green. The change is necessary, correct, and low risk. No blocker found.

Necessity: this is not merely cosmetic consistency. Today selecting Private → Public immediately persists and can expose channel history even if the user cancels the dialog. The same dialog visibly presents one Save changes boundary for name, description, TTL, and channel type, so visibility bypassing it is a destructive surprise. Fixing it before release is worthwhile.

Correctness/safety: visibility was already part of handleSaveChannelEdits; this patch removes the parallel immediate-write path and feeds the existing draft/save transaction instead. Dirty detection, reverting to the original value, cancel reset, failed-save behavior, channel-switch resync, mutation cache updates, and create-channel behavior all remain coherent. The shared permissions component loses only a spinner prop used solely by the deleted immediate mutation; its create-channel caller was already draft-based and is unaffected. No backend/API/persistence format or authorization behavior changes. The patch also removes the stale async channel-id race entirely rather than weakening its guard.

Independent exact-head validation: pnpm typecheck passed; Biome passed on all three changed files; E2E build passed; focused channel-controls smoke suite 10/10 passed; git diff --check passed; worktree clean; remote head unchanged. The test behavior changed intentionally: visibility now requires Save, Cancel discards it, and an unsaved draft cannot leak across a channel switch.

Release risk is low and bounded to Desktop’s Edit channel dialog. The security/product risk of not taking it is higher: an accidental private-to-public selection currently commits before confirmation. Merge only after repository CI is green on this exact head.

@wesbillman
wesbillman enabled auto-merge (squash) August 7, 2026 17:06
@wesbillman
wesbillman merged commit ef2ecaf into block:main Aug 7, 2026
26 checks passed
@kchung
kchung deleted the fix/channel-visibility-defer-save branch August 7, 2026 17:27
atishpatel added a commit that referenced this pull request Aug 7, 2026
…-log-harness

* origin/main:
  feat(desktop): adding rich link previews to messages (#3818)
  fix(buzz-agent): Responses reasoning summary, Anthropic display:summarized, ACP v2 messageId (#5195)
  fix(desktop): retain distinct agent instances in autocomplete (#5202)
  fix(desktop): defer channel visibility change to Save (#5203)
  feat(desktop): Projects follow-ups — access restrictions, fast loading, activity feed polish (#5073)
  refactor(cli): replace probe/decider/detail split with single typed extractor (#5191)
  fix(desktop): drop unhandled rejection from throwing window.Notification (#5143)
  fix(desktop): fence localStorage SecurityError from killing the React tree (#5142)
  fix(desktop): make terminal output selectable (#4980)
  fix(desktop): use WEBKIT_DMABUF_RENDERER_FORCE_SHM for NVIDIA/AppImage (#3654) (#4505)
  Make public starter channels best effort (#5192)
  Mobile: add anchored reaction popover (#5025)
  feat(mobile): add bee pull-to-refresh (#5059)

Signed-off-by: Atish Patel <atish@squareup.com>
wpfleger96 pushed a commit that referenced this pull request Aug 7, 2026
* origin/main: (32 commits)
  Recover from max-token response truncation (#5223)
  chore(release): release Buzz Desktop version 0.5.6 (#5214)
  fix(mobile): keep latest messages above composer (#4981)
  fix(sdk): preserve self-mention p tags in message and forum event builders (#4975)
  bump @tauri-apps/cli to ~2.11.4 to fix linux app icon issue (#4858)
  feat(desktop): adding rich link previews to messages (#3818)
  fix(buzz-agent): Responses reasoning summary, Anthropic display:summarized, ACP v2 messageId (#5195)
  fix(desktop): retain distinct agent instances in autocomplete (#5202)
  fix(desktop): defer channel visibility change to Save (#5203)
  feat(desktop): Projects follow-ups — access restrictions, fast loading, activity feed polish (#5073)
  refactor(cli): replace probe/decider/detail split with single typed extractor (#5191)
  fix(desktop): drop unhandled rejection from throwing window.Notification (#5143)
  fix(desktop): fence localStorage SecurityError from killing the React tree (#5142)
  fix(desktop): make terminal output selectable (#4980)
  fix(desktop): use WEBKIT_DMABUF_RENDERER_FORCE_SHM for NVIDIA/AppImage (#3654) (#4505)
  Make public starter channels best effort (#5192)
  Mobile: add anchored reaction popover (#5025)
  feat(mobile): add bee pull-to-refresh (#5059)
  Remove agent creation success modal (#5063)
  fix(buzz-agent): escalate LLM timeouts per retry and log per-call latency (#5130)
  ...

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

# Conflicts:
#	desktop/src/shared/api/tauri.ts
wpfleger96 pushed a commit that referenced this pull request Aug 7, 2026
…format

* origin/main: (60 commits)
  feat(desktop): unify add agent flows (#5015)
  fix(buzz-agent): budget summarizer reasoning separately so it cannot starve the handoff summary (#5248)
  infra: bind development services to loopback (#4871)
  chore(release): release Buzz Desktop version 0.5.7 (#5252)
  fix(desktop): isolate relay admission tests (#5221)
  fix(desktop): externalize boot <style> to prevent Tauri CSP nonce override (#5242)
  fix(desktop): let imported and recovered identities finish onboarding (#5228)
  Recover from max-token response truncation (#5223)
  chore(release): release Buzz Desktop version 0.5.6 (#5214)
  fix(mobile): keep latest messages above composer (#4981)
  fix(sdk): preserve self-mention p tags in message and forum event builders (#4975)
  bump @tauri-apps/cli to ~2.11.4 to fix linux app icon issue (#4858)
  feat(desktop): adding rich link previews to messages (#3818)
  fix(buzz-agent): Responses reasoning summary, Anthropic display:summarized, ACP v2 messageId (#5195)
  fix(desktop): retain distinct agent instances in autocomplete (#5202)
  fix(desktop): defer channel visibility change to Save (#5203)
  feat(desktop): Projects follow-ups — access restrictions, fast loading, activity feed polish (#5073)
  refactor(cli): replace probe/decider/detail split with single typed extractor (#5191)
  fix(desktop): drop unhandled rejection from throwing window.Notification (#5143)
  fix(desktop): fence localStorage SecurityError from killing the React tree (#5142)
  ...

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@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