Skip to content

(ui): replace native confirm/alert with the designed dialog everywhere, and ban them #585

Closed

Description

@devsuitup

Decision (maintainer, 12/10): every confirmation and message in the renderer goes through the app's designed dialog, the same one as the close-session confirmation (showChoiceDialog, public/choice-dialog.js). Native confirm(), alert() and prompt() are banned. A lint rule enforces the ban, and a small substitution module is the only entry point.

Why

  • The native dialogs look out of place: the resume, attach and live-elsewhere guards, deletes and save failures all use them.
  • They block the renderer.
  • Playwright auto-dismisses them, so e2e journeys cannot drive them. QA run 2 hit this.

Inventory on be8566c (grep -nE "\b(window\.)?(confirm|alert|prompt)\(" public/*.js)

  • resume-guard.js:33,42,56,62,68,72: scheduled task already running, live elsewhere, continuation choice. Injected as confirm from app.js:307,1519,1551.
  • app.js:1054: delete plan confirm.
  • agents-view.js:421: delete background session.
  • sidebar.js:1169,1236,1238,1241: archive messages. sidebar.js:1313,1316: remap. sidebar.js:1343,1360: hide or delete worktree.
  • settings-panel.js:715: hide project.
  • viewer-panel.js:283,290,293: delete file. viewer-panel.js:473: overwrite a file changed on disk. viewer-panel.js:594: discard unsaved edits.
  • file-panel.js:438,448,451: overwrite and save failure. file-panel.js:1456: discard unsaved edits. This one is sync, inside the unsaved guard ((restore): save the open sessions when the app closes #479/(window): ask before a window close ends the app #478), so take care.
  • activity-trace-panel.js:70,120,133: read, delete, delete failure.

Expected

  1. A module, for example public/app-dialogs.js, exposing async appConfirm({ title, message, confirmLabel, danger }) and appAlert({ title, message }), built on showChoiceDialog.
  2. Every call site above migrated. Sync callers become async. This matters most on the save and unsaved-edit paths, and wherever an injected confirm is used: resume-guard.js takes an async confirm.
  3. ESLint no-restricted-globals / no-restricted-properties for confirm, alert and prompt (bare and window.) over public/**, with a message pointing to the module.
  4. Tests:
    • The module: queueing, focus, Escape = cancel.
    • Each migrated guard keeps its semantics.
    • One e2e journey drives a formerly native confirm, for example Delete on a background session, or a resume guard.
  5. Main-process native dialogs (dialog.showMessageBox, for example the "Close Switchboard?" quit question) are out of scope. List them in the PR as a follow-up.

Activity

  1. added 20 commits that reference this issue on Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions