Skip to content

fix(web): keep the inline "New quick action" form open on click (BUG-2281)#1005

Merged
xarmian merged 1 commit into
mainfrom
fix/quickactions-inline-form-2281
Jul 22, 2026
Merged

fix(web): keep the inline "New quick action" form open on click (BUG-2281)#1005
xarmian merged 1 commit into
mainfrom
fix/quickactions-inline-form-2281

Conversation

@xarmian

@xarmian xarmian commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Started as /pad ultra-codex BUG-2129. BUG-2129 turned out to be already fixed and merged (#961) — the Pad item was just never flipped to fixed (now done, verified green). The mandated independent switch-safety Codex sweep it asked for surfaced two adjacent findings in QuickActionsMenu; this PR ships the one that's real.

BUG-2281 (real bug, fixed) — inline "New quick action" form closed instantly

Clicking the QuickActionsMenu footer "+ New quick action" flipped showCreateForm=true, unmounting the footer's {:else} branch (the very button clicked). Svelte 5 flushSyncs after a delegated event handler, so by the time that click bubbled on to the <svelte:window> click-outside handler the button was detachedtarget.closest('.quick-actions-menu') returned null, handleWindowClick treated it as an outside click, and the whole menu closed, wiping the create form the instant it opened. The Cancel button had the same quirk (closed the menu instead of returning to the action list).

handleTriggerClick already guards this with e.stopPropagation(); handleOpenCreateForm and the Cancel handler didn't. This adds the same guard to both.

Regression test (web/e2e/quickactions-inline-form.spec.ts): mutation-tested — fails on the pre-fix code, passes after. The inline form is exercised in a real Chromium event pipeline for the first time (jsdom doesn't reproduce the mid-bubble detach; the capstone spec only asserted the button was visible, never clicked it).

BUG-2280 (investigated, not a live bug — wontfix)

Codex initially flagged the QuickActionsMenu oncollectionupdated callback's {@const keyedSlug = itemSlug} fence as a no-op that lets a cross-collection switch land collection A onto item B. Empirically disproven: the destroyed instance's collection prop reads the live parent value (collB), so the existing child-side guard (collection?.id !== baseCollection.id) drops the callback; loadData's identity clause is a second backstop. The dead no-op fence is replaced with a comment documenting why the callback is safe and warning against re-adding a no-op snapshot fence (the literal BUG-2129 trap). No behavior change in ItemDetail.

Testing

  • npm run check (svelte-check): 0 errors
  • npm run test (vitest): 464 passed
  • e2e: quickactions-inline-form.spec.ts (BUG-2281) + pane-collection-migration-race.spec.ts (BUG-2129 ×2) all green; BUG-2281 mutation-tested
  • Independent Codex review (high reasoning): CLEAN

https://claude.ai/code/session_01EZ6yr6pAUFb1uffan912ra

…2281)

Clicking the QuickActionsMenu footer "+ New quick action" flipped
showCreateForm=true, unmounting the footer's {:else} branch (the very
button clicked). Svelte 5 flushSyncs after a delegated event handler, so
by the time that click bubbled on to the <svelte:window> click-outside
handler the button was detached — target.closest('.quick-actions-menu')
returned null, and handleWindowClick treated it as an outside click and
closed the whole menu, wiping the create form the instant it opened. The
create-form Cancel button had the same detach-then-close quirk (closed
the menu instead of returning to the action list).

handleTriggerClick already guards this with e.stopPropagation();
handleOpenCreateForm and the Cancel handler did not. Add the same guard
to both. Adds a Playwright regression test (mutation-tested: fails on the
pre-fix code, passes after) — the inline form is exercised in a real
Chromium event pipeline for the first time (jsdom doesn't reproduce the
mid-bubble detach, and the capstone spec only asserted the button was
visible, never clicked it).

Also documents BUG-2280 in ItemDetail.svelte: the QuickActionsMenu
oncollectionupdated callback's `{@const keyedSlug = itemSlug}` fence was a
Svelte-5 no-op, but the callback is already switch-safe by two independent
layers (the child-side collection-id guard reads the LIVE parent
collection and drops a cross-collection callback; loadData's identity
clause forces the correct collection regardless). Replaces the dead no-op
fence with a comment explaining why it's safe and warning against
re-adding a no-op snapshot fence (the literal BUG-2129 trap). No
behavior change in ItemDetail.

BUG-2281: real, fixed. BUG-2280: investigated, not a live bug (wontfix).

Claude-Session: https://claude.ai/code/session_01EZ6yr6pAUFb1uffan912ra
@xarmian
xarmian merged commit 06d7e42 into main Jul 22, 2026
6 checks passed
@xarmian
xarmian deleted the fix/quickactions-inline-form-2281 branch July 22, 2026 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant