From b334b8b228ea16c60c3bb3a962ee3441675d3b7a Mon Sep 17 00:00:00 2001 From: Luke Norland <217919286+Luke-Norland@users.noreply.github.com> Date: Tue, 6 Oct 2026 11:39:03 +0000 Subject: [PATCH] fix(sidebar): keep the notification repair state from blocking the session row A watched session whose browser has no push subscription shows the repair state: "Repair notifications when the assistant has a reply ready on this device". The bell rendered that sentence as visible row text (max-w-48, about 192px, wrapping to five lines) inside a shrink-0 wrapper in the row's actions slot. It squeezed the row's open button to about 12px, covered the session name so clicks landed on the text, and pushed the repair (wrench) button past the sidebar's edge, where it was clipped. The session could not be opened from the sidebar. The status span is now always sr-only. It is still announced and still the buttons' aria-describedby. In the repair state the row shows only the bell and the wrench at the bell's existing size; the wrench already carries the repair sentence as its title and aria-label and still runs repairDevice. Environmental reasons that used to show visible text (permission denied, insecure context, iOS install, unsupported) become part of the bell's tooltip. External and live rows share the component. Co-Authored-By: Claude Opus 5.5 --- .../SessionCompletionBell.test.tsx | 17 ++++++++++++++++- .../subcomponents/SessionCompletionBell.tsx | 10 ++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/components/sidebar/view/subcomponents/SessionCompletionBell.test.tsx b/src/components/sidebar/view/subcomponents/SessionCompletionBell.test.tsx index 3add7281..9753a958 100644 --- a/src/components/sidebar/view/subcomponents/SessionCompletionBell.test.tsx +++ b/src/components/sidebar/view/subcomponents/SessionCompletionBell.test.tsx @@ -143,7 +143,11 @@ test('SessionCompletionBell shows localized environmental guidance without a rep ] as const satisfies readonly (readonly [CompletionNotificationReason, string])[]) { const html = await renderBell({ error }); assert.match(html, new RegExp(message.replace(/[.?]/g, '\\$&')), `${error} explains what prevents notifications`); - assert.match(html, /class="max-w-48 text-xs text-destructive"/, `${error} guidance is visible`); + // Visible text in the row's action slot squeezed the open button; the guidance is a tooltip. + assert.doesNotMatch(html, /max-w-48|text-xs text-destructive/, `${error} guidance is not visible row text`); + assert.match(html, /class="sr-only" role="status"/, `${error} guidance is still announced`); + const bellTitle = /]*title="([^"]*)"/.exec(html)?.[1] ?? ''; + assert.ok(bellTitle.includes(message.replace(/'/g, ''')), `${error} guidance is the bell's tooltip`); assert.equal((html.match(/