镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

fix(attention): ask before deleting a watch - #3092

Merged
matt2e merged 2 commits into
mainfrom
warn-before-delete-1
Nov 9, 2026
Merged

matt2e merged 2 commits into
mainfrom
warn-before-delete-1

Conversation

@matt2e

@matt2e matt2e commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Delete on a watch's status menu in the Attention tab removed the watch on one click, with no confirmation and no Undo, while Delete on the Interest a few pixels away asks first. This reuses the Interest's AlertDialog for the watch so the two deletes behave the same. It is PR 1 of 3 from the P5-05 one-click-destructive sweep; paired CLI tool Revoke (Settings → Security) and external app Revoke access are separate follow-ups.

What changes

  • Delete on a watch's status menu closes the menu and opens an alert dialog titled "Delete {name}?". A nameless watch (every timer, and event or source watches without a name) is labelled by its Interest, so its dialog would read the same as the Interest's own delete next to it; those are titled "Delete this timer?" or "Delete this watch?" instead, and the description names the same kind.
  • Cancel takes initial focus. Escape or Cancel closes the dialog with no save and returns focus to the watch's status pill. Outside click does not dismiss.
  • Confirm runs the existing agents.save through useAction(): Delete shows loading and keeps focus, Cancel is disabled, and Escape cannot dismiss mid-save. After the row leaves, focus lands on the nearest remaining control (the Interest's pill), as the Interest delete already does.
  • A refused save keeps the dialog open with the error inside it and suppresses the row's inline copy, so there is exactly one alert.
  • useAction() gains reset(); opening the dialog clears a stale Pause/Resume error so it cannot appear inside the dialog as if Delete had failed.
  • Help guide: the watch pill sentence gains "(Delete asks first)".

Deliberately untouched: Tab.tsx. An Interest with no watches still deletes on one click, and the Interest-side reset() parity is a follow-up.

Before / after

Left is main at 58116b8 (one click, the row is gone, no dialog; the Interest beside it still asks "Delete PR reviews?"). Right is this branch (dialog with Cancel focused, Escape returns focus to the pill, confirm removes the row and focus lands on the Interest's pill). The pink outline is a focus ring injected for the recording; the app only draws focus rings under keyboard navigation.

staged-image-1366068f-63b0-46df-90e0-a1dd6f27a9ac.mp4

Contact sheet of the same recording. At 6.4 s the left row is already gone while the right shows the dialog. At 14.1 s the left is in the Interest's dialog for contrast. At 16.6 s the right row is gone with focus on the Release planning pill.

Testing

Check Result
bin/pnpm typecheck exit 0
biome clean
vitest run src/bundled/watching 27/27 passed
tests/browser/agent-attention.spec.mjs, Chromium 4/4 passed
tests/browser/agent-attention.spec.mjs, WebKit 4/4 passed
bin/pnpm design:check exit 0
git diff --check clean

🤖 Generated with Claude Code

Delete on a watch's status menu removed the watch on one click, while
Delete on its Interest a few pixels away asked first. The menu item now
closes the menu and opens the same AlertDialog with Cancel focused.
A watch with its own name is titled "Delete {name}?"; a nameless watch
(every timer, and event or source watches without a name) is labelled
by its Interest, so its dialog would read the same as the Interest's
own delete next to it. Those are titled "Delete this timer?" or
"Delete this watch?" instead, and the description names the same kind.

Confirm runs the existing save through useAction(), so Delete shows
loading and Cancel is disabled while pending; a refused save keeps the
dialog open with its error as the single alert. The action is shared
with Pause/Resume, so opening the dialog clears any earlier error
rather than showing a refused Pause as if Delete had failed. Cancel and
Escape return focus to the status pill; after a confirmed delete Base
UI lands focus on the nearest remaining control, as the Interest delete
does. The help guide notes that Delete asks first.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: mtoohey <mtoohey@squareup.com>
@matt2e
matt2e requested a review from a team as a code owner November 9, 2026 14:52

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 One deletion confirmation correctness issue.

Comment thread src/bundled/watching/WatchRow.tsx Resolved
The watch Delete dialog saved only the slug, so a watch the agent
revised while the dialog stayed open (after a refused save, say) was
deleted on Confirm without a conflict, although the person had only
reviewed the earlier version. The Interest delete beside it already
supplies attentionExpected and is refused when the object changed.

The dialog now holds the watch's attention object from the moment the
Delete menu item opens it, and Confirm passes that object as
attentionExpected with the slug. Capturing at Confirm would not cover
changes during the dialog's lifetime, so the snapshot is taken when it
opens; closing the dialog clears it. A watch changed meanwhile is
refused with the service's existing "Attention changed" error, shown in
the dialog, and reopening it reviews and deletes the current version.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@kazemek21 kazemek21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Kyle reviewed the PR and the Nexus review-tracker notes and approved with no comments.

Posted by Codex (gpt-6.1-sol) on behalf of kylez.

@matt2e
matt2e merged commit 03731ae into main Nov 9, 2026
62 checks passed
@matt2e
matt2e deleted the warn-before-delete-1 branch November 9, 2026 21:42
wpfleger96 added a commit that referenced this pull request Nov 9, 2026
…restricted-communities

* origin/main:
  ci: give WebKit shards headroom and keep fixture servers' idle connections open (#3074)
  fix(messages): offer Retry as soon as a send fails (#3080)
  fix(agents): link Settings from key failures and quote the provider (#3081)
  fix(identity): link Builderlab from Identity sync where its page holds the next step (#3082)
  fix(startup): show a recoverable screen when Buzz fails to open or crashes (#3085)
  fix(attention): ask before deleting a watch (#3092)
  fix(agents): remove the owner-access read tools (#3123)
  fix(channels): keep the side pane mounted under the image viewer (#3111)
  fix(solo): ask before Escape or Close drops a new workspace's typed fields (#3114)

# Conflicts:
#	docs/configuration.md
#	vite.config.ts
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.

3 participants