7.1 KiB
spec, created, status
| spec | created | status |
|---|---|---|
| docs/specs/ui/session-tab-delete-feedback.md | 2026-08-05 | shipped |
Implementation Plan: Session tab delete feedback
Overview
Give the desktop Dockview session-tab close flow local pending feedback while preserving the shared session lifecycle behavior used by context menus and mobile. First make the shared delete action selectively suppress progress/success toasts, then replace Dockview's opaque close icon with a small repository-owned action that can render an X or spinner. Finish with focused desktop and mobile Playwright coverage.
Frontend
Shared session delete action
Update apps/web/hooks/domains/session/use-session-actions.ts so remove accepts an optional
feedback mode and returns whether deletion succeeded. Keep the current loading-to-success toast
sequence as the default for existing callers. Add an error-only mode for the tab-X flow: it emits
no loading or success toast, but emits one error toast on rejection and leaves store/panel cleanup
behind the success result. Existing active-session handoff and onDeleted ordering remain intact.
Session tab close action
Add apps/web/components/task/session-tab-close-action.tsx as the repository-owned close action.
It preserves Dockview's dv-default-tab-action class and the existing
session-tab-close-<sessionId> test ID, prevents the close target from becoming tab-activation
intent, and renders either IconX or GridSpinner. While pending it is disabled, carries
aria-busy, and retains a localized accessible name.
Update apps/web/components/task/session-tab.tsx to render DockviewDefaultTab without its opaque
close control and place the new action in the same tab chrome. Track whether the open confirmation
came from the X or the context menu. Only confirmed X-originated deletion uses error-only feedback
and drives the close spinner; context-menu deletion retains the default toast mode. Cancelling the
dialog clears the origin without entering the pending state.
Add the close action's accessible label to apps/web/src/locales/en/common.json and
apps/web/src/locales/zh-cn/common.json, then regenerate
apps/web/src/locales/pseudo/common.json with pnpm run i18n:pseudo.
Mobile design contract
- Desktop outcome: the session-tab X is the progress surface and remains in the existing tab strip; no overlay or layout change is introduced.
- Mobile entry point: the existing
MobileSessionsPickerpill opensMobilePickerSheet, and a session row's visible actions menu owns deletion. There is no Dockview X on phone. - Nearest shipped exemplar:
apps/web/components/task/mobile/mobile-sessions-section.tsxremains authoritative for the phone hierarchy, bottom-sheet surface, internal scroll owner, safe-area handling, and touch targets. - Shared versus specialized behavior: the delete transport/store mutation remains shared in
useSessionActions; only the desktop tab-X presentation and feedback mode specialize. Mobile markup and its default feedback mode do not change. - Parity proof: a mobile Playwright scenario deletes one of two sessions through the Sessions picker and verifies the selected session disappears while the remaining session stays reachable.
Tests
- Feedback modes and cleanup: extend
apps/web/hooks/domains/session/use-session-actions.test.tsto prove default callers still receive loading/success toasts, error-only deletion receives neither, failures receive one error toast,removereports success/failure, and store/panel cleanup remains success-only. - Close action state: add
apps/web/components/task/session-tab-close-action.test.tsxto prove the idle X is operable, the pending state renders a status spinner witharia-busy, and pending activation cannot dispatch a second callback.
E2E Tests
- Scenario: GIVEN two deletable sessions, WHEN the desktop user clicks a tab X and confirms,
THEN the tab/session is removed and no
Deleting session...or successful-deletion toast appears. File:apps/web/e2e/tests/session/session-tab-management.spec.ts. - Scenario: GIVEN two deletable sessions on a phone viewport, WHEN the user opens the Sessions
picker and deletes one through its row action, THEN that row disappears and the remaining session
stays reachable. File:
apps/web/e2e/tests/session/mobile-session-deletion.spec.ts, run by themobile-chromeproject.
The transient spinner is covered deterministically by the component test because the real delete response can settle too quickly for a race-free Playwright observation. Playwright covers the integrated no-toast result and session reconciliation.
Verification Results
rtk pnpm --filter @kandev/web test -- components/task/session-tab-close-action.test.tsx hooks/domains/session/use-session-actions.test.ts— 2 files, 15 tests passed.rtk pnpm run typecheck— passed.rtk pnpm run i18n:check— passed; pseudo locale is synchronized. The existing catalog audit remains advisory with 670 zh-cn parity notices.rtk pnpm run i18n:ratchet— passed.rtk pnpm exec eslint components/task/session-tab.tsx components/task/session-tab-close-action.tsx hooks/domains/session/use-session-actions.ts hooks/domains/session/use-session-actions.test.ts components/task/session-tab-close-action.test.tsx e2e/tests/session/session-tab-management.spec.ts e2e/tests/session/mobile-session-deletion.spec.ts— passed with no errors or warnings.rtk pnpm exec prettier --check ...— all changed source, test, locale, spec, and plan files passed formatting checks.rtk git diff --check— passed.rtk pnpm e2e:run tests/session/session-tab-management.spec.ts -- --grep "tab close button shows delete confirmation"— 1 desktop test passed with a production build.rtk pnpm e2e:run --no-build --project mobile-chrome tests/session/mobile-session-deletion.spec.ts— 1 mobile test passed.rtk pnpm e2e:run --no-build tests/session/session-tab-management.spec.ts tests/session/session-tab-close-guard.spec.ts— 9 desktop tests passed.
The pseudo-locale artifact updated is apps/web/src/locales/pseudo/common.json. Managed E2E runs
used isolated temporary backends and cleaned their generated results; no external systems were
changed.
Implementation Waves And Parallel Candidates
Wave 1:
Wave 2:
Execution is sequential in the primary conversation. The E2E task depends on the production and unit-test changes from task 01; these tasks are not parallel-safe.
Risks
- Dockview owns its default X markup, so the custom action must preserve the
dv-default-tab-actionclass, pointer suppression, visibility behavior, and activation-intent guard while avoiding a fork of the full tab implementation. - X-origin tracking must be reset on cancel and failure so a later context-menu delete cannot inherit error-only feedback or a stale spinner.
- The backend delete response can be faster than a rendered frame; deterministic transient-state proof belongs in the component test rather than a timing-sensitive E2E assertion.