Repository navigation
fix(app-shell): a record page's delete asks through the console's own confirm dialog (objectui#11001) - #11074
Conversation
… confirm dialog The record header's `sys_delete` action asked through the browser's native `window.confirm`. It now awaits the page's own confirm runtime, the same promise-based handler the page hands the action runner as `onConfirm`, which renders the in-app `ActionConfirmDialog` the list view's delete uses. One argument, like the runner's call, so the dialog shows the same default title and buttons as the list view. Cancel leaves the record and the page as they are. Two comments that said the handler had exactly one caller now name the second. Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec Co-authored-by: Claude <noreply@anthropic.com>
…app confirm dialog Mounts the real record page under a real `I18nProvider` with the real `ActionConfirmDialog`, chooses Delete from the header overflow, and pins three things: the alert dialog opens with the page's own delete question and the dialog's default buttons while nothing is deleted yet; confirming runs the existing delete and leaves for the object's list; cancelling deletes nothing and leaves the router where it was. A `window.confirm` spy that answers yes stays uncalled in all three. Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec Co-authored-by: Claude <noreply@anthropic.com>
… confirm Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec Co-authored-by: Claude <noreply@anthropic.com>
…r, no any-casts The pin now saves the window's own `confirm` descriptor, defines the spy over it, and hands the original back (or removes the own slot) after each test. Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: Inputs read, and nothing else: card #11001 (body and all three comments: triage 5874827009, claim 5886653563, os-dev-report 5887544880); PR #11074 (body, four-file list, net diff against Check-runs on the headRead complete at 2026-09-29T09:43Z: 43 latest runs, 40 success, 3 skipped, 0 failure, 0 in progress. The skipped three are ① Derived judgments
② Semver level
Clause-②: no — matches the claim (5886653563, ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #11001
Clause-②: no
What changed
On a record page, More actions then Delete asked through the browser's native
window.confirm. The header'ssys_deleteaction inpackages/app-shell/src/views/RecordDetailView.tsxnow awaitsconfirmHandler(msg): the page's own promise-based confirm handler, the one it already hands the action runner asonConfirm, which opens the in-appActionConfirmDialog. That is the same dialog the list view's delete opens: app-shell'sObjectViewhandsuseConsoleActionRuntime's confirm handler touseObjectActionsasonConfirm, and the runner calls it with the delete question. Confirm runs the existing delete unchanged (dataSource.delete, the success toast, back to the object's list). Cancel returns before anything runs, so the record and the page stay as they are.detail.deleteConfirmation. The dialog's title and buttons are its defaults (actionConfirm.title,actionConfirm.confirm,actionConfirm.cancel), exactly what the list view's delete shows, because both callers pass one argument. No pack key is added, so this is not serial behind objectui#11039.ConfirmationHandlernote aboveconfirmHandlerinRecordDetailView.tsx, and the header ofRecordDetailView.confirmRuntimeParity-5835.test.tsx. This change made both false, so both now name the second caller. That test file is outside the claim's declared file surface; the edit is comment-only, and the file's tests ran green (below).Premises checked on
origin/main827550193sys_deleteaction'sonClickinRecordDetailView.tsxcalledif (!window.confirm(msg)) return;. Confirmed.ObjectViewhandsactionRuntime.confirmHandlertouseObjectActionsasonConfirmand rendersactionRuntime.dialogs, which includeActionConfirmDialog. Confirmed; the row delete goes throughactions.deleteRecord, then the runner, then that handler with one argument.useObjectActionsdocumentsonConfirmas falling back towindow.confirm. The record page does not mount that hook. It already owns a handler of the same publishedConfirmationHandlertype feeding the sameActionConfirmDialog(parity pinned byRecordDetailView.confirmRuntimeParity-5835.test.tsx), so the seam used is that existing handler, not a second hook mount.detail.deleteConfirmationand the threeactionConfirmkeys exist in all ten packs.Pin
packages/app-shell/src/views/RecordDetailView.deleteConfirmDialog-11001.test.tsxmounts the real record page under a realI18nProvider(en) with the REALActionConfirmDialog, opens the header overflow and chooses Delete. Every test installs awindow.confirmspy that answers yes, so the old code would delete at once with no dialog.alertdialogopens carryingdetail.deleteConfirmationand the dialog's default buttons; nothing is deleted yet; the spy is not called.dataSource.deleteis called once with the object and record id, one success toast, and the router leaves for the object's list.Strings are read from the
enpack by key, not written out.Verification (final commit
64c0db025)pnpm exec vitest runover every test file that namesRecordDetailView(104 files: all 37RecordDetailView.*pins, 36 existing plus the new one; the three app-shell ratchets that read it;useConsoleActionRuntime.test.tsx; the console and package tests that mention it):Test Files 104 passed (104),Tests 1028 passed (1028).ablation-replace.mjs(anchor hits 1 then 0, blob changed) and was restored to the HEAD blob withgit diff HEADempty. Withif (!window.confirm(msg)) return;put back, the new pin readsTests 3 failed (3), eachUnable to find role="alertdialog". Run ata537ec3e7and again at64c0db025, same result. No build or dist step is involved: the pin imports./RecordDetailViewfrom source.pnpm --filter @object-ui/app-shell type-check(tsc --noEmit && tsc -p tsconfig.test.json): exit 0, after building the@object-ui/app-shell^...closure with turbo (28 of 28 tasks).tsc -p tsconfig.test.json --listFilesOnlylists the new pin and the edited parity test.pnpm exec eslint --format jsonon the three changed.tsxfiles: 3 files, 0 errors. Narrowing proof: the population is the**/*.{ts,tsx}block ofeslint.config.js; noparserOptions.projectorprojectServiceis set, so linting is not type-aware and this diff cannot move a verdict on an untouched file. Warnings on the two edited files are unchanged from the base (111 and 17, read through--stdinat827550193).check-changeset-presence,check-changeset-no-major,check-changeset-fixed,check-changeset-overwrite,check-changeset-claims(report-only; it names.changeset/7997-detail-view-related-retired.mdbecause that body mentionsRecordDetailView.tsx; its paragraph is about the retiredDetailViewschema mirror and this change does not touch that),check-control-bytes,check-new-cross-file-line-citations(0 new),check-vi-mock-specifiers,check-vi-mock-inherit,check-vi-mock-override-shape,check-test-path-roots,check-type-check-coverage,check-lint-coverage,check:i18n-keys,check:handler-key-reads,check:pending-changeset-literals.check-governed-queue-guard --testover the four paths: NOT GOVERNED.packages/app-shell/src/views/directory (565 test files) was NOT run locally. The 104-file set took about 6 minutes under the shared lock, so the directory would not fit the 10-minute foreground cap; CI's shardedpnpm testruns all of it. The set run is every test file that namesRecordDetailView; a test that reaches the page only through a transitive import, without naming it, is not in it.Acceptance notes
recordDeletecore in@object-ui/core(objectui#10383) that the list view's delete uses. So for a package-ownedsys_permission_setrow (ADR-0094) the record page would ask the plain delete question and toast "Record deleted" where the list view asks the reset question. Not measured on a live page, and whether the record page offers Delete on that object at all was not checked. Carrier: none.Generated by Claude Code