From 02dbbf59b14774cd532dfa306f2ff4704df9d075 Mon Sep 17 00:00:00 2001 From: "[._.]/ Adam Eivy" Date: Tue, 28 Jul 2026 16:18:22 -0700 Subject: [PATCH 1/7] fix: fold never-dismissing toasts into a corner pill so they stop eating clicks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The toast stack is fixed, z-[9999] and pointer-events-auto, so a toast that never dismisses is a permanent click sink over the page. On this install the "Install out of sync" notice (duration: Infinity) sat on top of the CoS task form and silently absorbed every click aimed at Screenshot and Attach — no file picker, no error, nothing in the console, which is why it read as a broken button rather than something covering one. Measured in headless Chrome against the running instance at 1280x720: the notice blocks 520x86px starting at x=744, and the Attach label occupies x=744-837 — a direct hit. Removing the toast from the DOM made the same click open the picker. A duration: Infinity toast now collapses to a 40x40px corner pill after 8s (1600px^2, clear of the form); clicking the pill restores the full message, and it stays open while hovered or while focus is inside it. Collapsing hides the body with an inline display:none rather than unmounting it, so render-prop toasts that own their own dismiss timer (the agent-feedback card) keep them. Only unbounded toasts collapse. A finite duration is a bound the caller already chose and clears itself — folding one early would hide an action meant to stay offered for its whole life, e.g. the manuscript Undo-fix toast, whose 10s Undo button is the only undo there is once the source card unmounts. The pill takes its accessible name from string content; JSX and render-prop content have no text to take, so those call sites now pass `label`, and a11yConventions.test.js gains a fourth rule that fails the suite if a new one forgets — the same shape as the existing file-input guards, because nothing at runtime complains. --- .changelog/NEXT.md | 1 + client/src/a11yConventions.test.js | 53 +++++++++ client/src/components/ui/Toast.jsx | 127 ++++++++++++++++++--- client/src/components/ui/Toast.test.jsx | 104 ++++++++++++++++- client/src/hooks/useAgentFeedbackToast.jsx | 1 + client/src/hooks/useUpdateChecker.jsx | 6 +- client/src/services/staleBuildToast.jsx | 2 +- 7 files changed, 270 insertions(+), 24 deletions(-) diff --git a/.changelog/NEXT.md b/.changelog/NEXT.md index d76cb8df7e..3fc98a3df8 100644 --- a/.changelog/NEXT.md +++ b/.changelog/NEXT.md @@ -23,6 +23,7 @@ ## Fixed +- **The task form's Screenshot and Attach buttons work again — a stuck notification was eating the clicks.** A notice that never goes away (the "Install out of sync" warning, "Update available", "New build available") parks in the bottom-right corner, and on a desktop window it landed on top of the Chief of Staff task form and silently absorbed every click meant for the buttons underneath. They did nothing at all — no file picker, no error, nothing in the browser console — which is why it read as a broken button rather than something covering one, and why the same page still worked on a phone, where the layout puts those buttons elsewhere. On a 1280×720 window the notice covered a 520×86px block starting at the exact pixel the Attach button begins. Notices that never dismiss themselves now fold into a small badge in the corner after 8 seconds (1600px², clear of the page); clicking the badge brings the message back, and it stays open while you hover it or use its buttons. Toasts with a set lifetime — including the manuscript Undo prompt — are untouched. - **CoS agent PRs no longer open with TUI startup noise as their description.** A PR that PortOS opened for a Codex/Antigravity/OpenCode agent led with the session's own lifecycle log — `📟 TUI session started: … (codex …)`, `💡 Open the Shell tab…`, `📟 Prompt pasted…` — before getting to what the agent actually did. The PR description now starts at the agent's completion summary and drops PortOS's status lines, along with the trailing `## Branch` / `## PR` section that only repeats what the PR page already shows. - **Review Hub success-rate alerts now require recent runs.** Low lifetime rates for task types that have been idle no longer appear as current health anomalies; alerts are shown only after enough runs occur in the rolling 30-day performance window. - **Malware scan reports now open inside PortOS.** Scan links from Brain, the Review Hub, and completed CoS agents render the markdown in a mobile-friendly PortOS page instead of navigating a Home Screen install to the raw `.md` API response. Brain Links also has a Scan Reports filter, so clean and caution results are just as discoverable as dangerous findings. diff --git a/client/src/a11yConventions.test.js b/client/src/a11yConventions.test.js index e261cbc7b0..c9ba18024d 100644 --- a/client/src/a11yConventions.test.js +++ b/client/src/a11yConventions.test.js @@ -20,6 +20,10 @@ * picker at all in WebKit-as-installed-PWA — the shape PortOS is opened in * from a second machine over the tailnet. `components/ui/FilePickerButton.jsx` * is the shared widget (sr-only input + native `