Skip to content

fix: resolve nested schema component actions inside card actions - #165

Merged
ManukMinasyan merged 2 commits into
4.xfrom
fix/nested-schema-component-actions
Aug 19, 2026
Merged

fix: resolve nested schema component actions inside card actions#165
ManukMinasyan merged 2 commits into
4.xfrom
fix/nested-schema-component-actions

Conversation

@ManukMinasyan

@ManukMinasyan ManukMinasyan commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Fixes #156.

The bug

With an EditAction in cardActions() whose schema contains a Repeater, clicking the repeater's add (or remove) button closes the modal without applying the change. Afterwards no card action responds to clicks until the page is reloaded.

Root cause

Filament\Actions\Action::getContext() adds recordKey to the context of any action that has a record. A schema component action nested inside a mounted card action inherits the card's record, so it arrives with both keys set:

mountAction('add', {}, { recordKey: "01kxkp4y…", schemaComponent: "mountedActionSchema0.items" })

BoardResourcePage::resolveActions() checked recordKey first, so the entry was routed to resolveBoardAction()$parentAction->getModalAction('add')nullcontinue. The mounted entry was silently dropped (no exception, nothing logged).

Both reported symptoms follow from that one dropped entry:

  • mountedActions holds 2 entries but only 1 resolves, so syncActionModals() targets a nesting index that was never rendered and the open modal closes.
  • The orphaned entry is never popped, so getMountedAction() can never match count($mountedActions) - 1 again. Every later card click appends another unreachable entry (["edit", "add", "edit"]), and nothing opens until reload.

Filament core checks schemaComponent and table before falling back, so this is a divergence from upstream ordering rather than a new rule.

The fix

Check schemaComponent and table before recordKey, matching InteractsWithActions::resolveActions(). Board card actions still route to resolveBoardAction(); they simply no longer shadow the more specific contexts.

This also covers the repeater's delete/reorder/clone actions and every other nested schema component action inside a card action modal (Builder, Select::createOptionAction(), nested ->schema() modals). BoardPage was never affected, it has no override.

Backward compatibility

The reorder only changes routing for entries whose context has recordKey and schemaComponent or table. Everything else takes the same branch as before.

  • Card actions never carry schemaComponent or table. They are built by getBoardRecordActions(), which sets only livewire() and record(), and Action::getTable() resolves from $this->table ?? $this->getGroup()?->getTable(), both null here. Confirmed against a running board: a mounted card action's context is {recordKey} and nothing else.
  • Modal actions registered on a card action are unaffected. getContext() returns early once an action has a parent action, so they carry only recordKey and keep resolving through resolveBoardAction()'s getModalAction() lookup. Covered by a dedicated test that passes both before and after the change.
  • Column actions are untouched, they are detected by the column argument. The existing BoardResourcePageColumnActionTest still passes.
  • The entries whose routing does change (top-level schema component actions, and table actions on a page that also implements HasTable) previously resolved to null and were dropped, so there is no working behaviour to preserve.

Test plan

Five tests in tests/Feature/BoardResourcePageNestedActionTest.php, driven through TestBoardResourcePage (a real BoardResourcePage with a Repeater in a card action):

  • repeater add keeps the card action mounted and increments the item count
  • repeater delete keeps the card action mounted and decrements the item count
  • card actions are still mountable after a nested action has run (the freeze)
  • the card action still resolves its record (guards the behaviour the override exists for)
  • modal actions registered on a card action still resolve through the board resolver (the backward-compatibility guard above)

Three of the five fail on 4.x with Failed asserting that actual size 2 matches expected size 1, which is the orphaned entry. The other two pass before and after, which is the point of them. All five pass with the fix.

Verified locally beyond the test suite:

  • vendor/bin/pest: 152 passed
  • vendor/bin/pint: passed
  • vendor/bin/phpstan analyse: 7 errors, identical to the count on unmodified 4.x (pre-existing, none in the changed code)
  • Browser check in a real Filament 5.4 app: repeater add 1 → 2 items with the modal still open, repeater delete 2 → 1 with the modal still open, mountedActions stays at a single entry, and a card action mounts normally afterwards

Filament adds `recordKey` to the context of any action that has a record. A
schema component action nested inside a mounted card action (a Repeater's
add/delete button, `Select::createOptionAction()`, a nested action modal)
inherits the card's record, so it arrives with both `recordKey` and
`schemaComponent` set.

BoardResourcePage::resolveActions() checked `recordKey` first, routing those
actions to resolveBoardAction(), which cannot find them. The mounted entry was
silently dropped: the open modal closed without applying the change, and the
orphaned entry left in `mountedActions` meant no card action could be mounted
again until the page was reloaded.

Check `schemaComponent` and `table` before `recordKey`, matching the ordering in
Filament's own InteractsWithActions::resolveActions().

Fixes #156
Copilot AI lite review requested due to automatic review settings August 19, 2026 09:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ManukMinasyan
ManukMinasyan merged commit 3f76191 into 4.x Aug 19, 2026
4 checks passed
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.

[Bug]: Modal closes on Repeater add/remove action inside cardActions & freezes card interactions

2 participants