diff --git a/packages/actions/resources/views/components/modals.blade.php b/packages/actions/resources/views/components/modals.blade.php index b095a76e0a..b2bb5f1300 100644 --- a/packages/actions/resources/views/components/modals.blade.php +++ b/packages/actions/resources/views/components/modals.blade.php @@ -27,6 +27,10 @@ :wire:key="$action ? $this->getId() . '.actions.' . $action->getName() . '.modal' : null" x-on:closed-form-component-action-modal.window="if (($event.detail.id === '{{ $this->getId() }}') && $wire.mountedActions.length) open()" x-on:modal-closed.stop=" + if (!$event.detail?.id?.startsWith('{{ $this->getId() }}-')) { + return + } + const mountedActionShouldOpenModal = {{ \Illuminate\Support\Js::from($action && $this->mountedActionShouldOpenModal(mountedAction: $action)) }} if (! mountedActionShouldOpenModal) { @@ -89,6 +93,10 @@ :wire:key="$action ? $this->getId() . '.table.actions.' . $action->getName() . '.modal' : null" x-on:closed-form-component-action-modal.window="if (($event.detail.id === '{{ $this->getId() }}') && $wire.mountedTableActions.length) open()" x-on:modal-closed.stop=" + if (!$event.detail?.id?.startsWith('{{ $this->getId() }}-')) { + return + } + const mountedTableActionShouldOpenModal = {{ \Illuminate\Support\Js::from($action && $this->mountedTableActionShouldOpenModal(mountedAction: $action)) }} if (! mountedTableActionShouldOpenModal) { @@ -145,6 +153,10 @@ :wire:key="$action ? $this->getId() . '.table.bulk-actions.' . $action->getName() . '.modal' : null" x-on:closed-form-component-action-modal.window="if (($event.detail.id === '{{ $this->getId() }}') && $wire.mountedTableBulkAction) open()" x-on:modal-closed.stop=" + if (!$event.detail?.id?.startsWith('{{ $this->getId() }}-')) { + return + } + const mountedTableBulkActionShouldOpenModal = {{ \Illuminate\Support\Js::from($action && $this->mountedTableBulkActionShouldOpenModal(mountedBulkAction: $action)) }} if (! mountedTableBulkActionShouldOpenModal) { @@ -207,6 +219,10 @@ :wire:key="$action ? $this->getId() . '.infolist.actions.' . $action->getName() . '.modal' : null" x-on:closed-form-component-action-modal.window="if (($event.detail.id === '{{ $this->getId() }}') && $wire.mountedInfolistActions.length) open()" x-on:modal-closed.stop=" + if (!$event.detail?.id?.startsWith('{{ $this->getId() }}-')) { + return + } + const mountedInfolistActionShouldOpenModal = {{ \Illuminate\Support\Js::from($action && $this->mountedInfolistActionShouldOpenModal(mountedAction: $action)) }} if (! mountedInfolistActionShouldOpenModal) { @@ -268,6 +284,10 @@ :width="$action?->getModalWidth()" :wire:key="$action ? $this->getId() . '.' . $action->getComponent()->getStatePath() . '.actions.' . $action->getName() . '.modal' : null" x-on:modal-closed.stop=" + if (!$event.detail?.id?.startsWith('{{ $this->getId() }}-')) { + return + } + const mountedFormComponentActionShouldOpenModal = {{ \Illuminate\Support\Js::from($action && $this->mountedFormComponentActionShouldOpenModal()) }} if (mountedFormComponentActionShouldOpenModal) { diff --git a/packages/forms/docs/07-advanced.md b/packages/forms/docs/07-advanced.md index 5e7fe04b87..aa2c0cae9e 100644 --- a/packages/forms/docs/07-advanced.md +++ b/packages/forms/docs/07-advanced.md @@ -560,7 +560,7 @@ Group::make() Please note that if you are saving the data to a `BelongsTo` relationship, then the foreign key column in your database must be `nullable()`. This is because Filament saves the form first, before saving the relationship. Since the form is saved first, the foreign ID does not exist yet, so it must be nullable. Immediately after the form is saved, Filament saves the relationship, which will then fill in the foreign ID and save it again. -It is worth noting that if you have an observer on your form model, then you may need to adapt it to ensure that it does not depend on the relationship existing when it it created. For example, if you have an observer that sends an email to a related record when a form is created, you may need to switch to using a different hook that runs after the relationship is attached, like `updated()`. +It is worth noting that if you have an observer on your form model, then you may need to adapt it to ensure that it does not depend on the relationship existing when it is created. For example, if you have an observer that sends an email to a related record when a form is created, you may need to switch to using a different hook that runs after the relationship is attached, like `updated()`. ### Conditionally saving data to a relationship diff --git a/packages/forms/resources/lang/fi/components.php b/packages/forms/resources/lang/fi/components.php index fff106f3de..4a41660b6f 100644 --- a/packages/forms/resources/lang/fi/components.php +++ b/packages/forms/resources/lang/fi/components.php @@ -111,7 +111,7 @@ return [ 'actions' => [ 'deselect_all' => [ - 'label' => 'Poista valinta kaikista', + 'label' => 'Poista valinnat', ], 'select_all' => [ @@ -408,6 +408,8 @@ return [ 'create_option' => [ + 'label' => 'Uusi', + 'modal' => [ 'heading' => 'Uusi', @@ -430,6 +432,8 @@ return [ 'edit_option' => [ + 'label' => 'Muokkaa', + 'modal' => [ 'heading' => 'Muokkaa', @@ -455,7 +459,7 @@ return [ 'loading_message' => 'Ladataan...', - 'max_items_message' => 'Vain :count voi valita.', + 'max_items_message' => 'Voit valita enintään :count.', 'no_search_results_message' => 'Haku ei löytänyt tuloksia.', diff --git a/packages/forms/resources/lang/fr/components.php b/packages/forms/resources/lang/fr/components.php index 81d23f1196..e2a5b7bc55 100644 --- a/packages/forms/resources/lang/fr/components.php +++ b/packages/forms/resources/lang/fr/components.php @@ -384,7 +384,7 @@ return [ 'actions' => [ 'create_option' => [ - + 'label' => 'Créer', 'modal' => [ 'heading' => 'Créer', @@ -406,7 +406,7 @@ return [ ], 'edit_option' => [ - + 'label' => 'Modifier', 'modal' => [ 'heading' => 'Modifier', diff --git a/packages/forms/src/Components/Concerns/HasState.php b/packages/forms/src/Components/Concerns/HasState.php index 04358a6b59..f90d9a744a 100644 --- a/packages/forms/src/Components/Concerns/HasState.php +++ b/packages/forms/src/Components/Concerns/HasState.php @@ -89,7 +89,7 @@ trait HasState return $this; } - public function callAfterStateUpdated(): static + public function callAfterStateUpdated(bool $shouldBubbleToParents = true): static { foreach ($this->afterStateUpdated as $callback) { $runId = spl_object_id($callback) . md5(json_encode($this->getState())); @@ -103,6 +103,10 @@ trait HasState store($this)->push('executedAfterStateUpdatedCallbacks', value: $runId, iKey: $runId); } + if ($shouldBubbleToParents) { + $this->getContainer()->getParentComponent()?->callAfterStateUpdated(); + } + return $this; } @@ -189,7 +193,7 @@ trait HasState // we need to dehydrate the child component containers while // informing them that they are not dehydrated, so that their // child components get removed from the state. - foreach ($this->getChildComponentContainers() as $container) { + foreach ($this->getChildComponentContainers(withHidden: true) as $container) { $container->dehydrateState($state, isDehydrated: false); } diff --git a/packages/forms/src/Components/Select.php b/packages/forms/src/Components/Select.php index 7d2589bac1..98f2def572 100644 --- a/packages/forms/src/Components/Select.php +++ b/packages/forms/src/Components/Select.php @@ -778,6 +778,14 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has ]) ?? $relationshipQuery; } + $baseRelationshipQuery = $relationshipQuery->getQuery(); + + if (isset($baseRelationshipQuery->limit)) { + $component->optionsLimit($baseRelationshipQuery->limit); + } elseif ($component->isSearchable() && filled($component->getSearchColumns())) { + $relationshipQuery->limit($component->getOptionsLimit()); + } + $qualifiedRelatedKeyName = $component->getQualifiedRelatedKeyNameForRelationship($relationship); if ($component->hasOptionLabelFromRecordUsingCallback()) { @@ -1081,7 +1089,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has $query->where(function (Builder $query) use ($databaseConnection, $isForcedCaseInsensitive, $search): Builder { $isFirst = true; - foreach ($this->getSearchColumns() as $searchColumn) { + foreach ($this->getSearchColumns() ?? [] as $searchColumn) { $whereClause = $isFirst ? 'where' : 'orWhere'; $query->{$whereClause}( @@ -1207,8 +1215,8 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has public function hasDynamicSearchResults(): bool { - if ($this->hasRelationship() && empty($this->searchColumns)) { - return ! $this->isPreloaded(); + if ($this->hasRelationship() && blank($this->getSearchColumns())) { + return false; } return $this->getSearchResultsUsing instanceof Closure; diff --git a/packages/forms/src/Concerns/HasState.php b/packages/forms/src/Concerns/HasState.php index 9b670880de..cba5227c36 100644 --- a/packages/forms/src/Concerns/HasState.php +++ b/packages/forms/src/Concerns/HasState.php @@ -27,13 +27,13 @@ trait HasState { foreach ($this->getComponents(withHidden: true) as $component) { if ($component->getStatePath() === $path) { - $component->callAfterStateUpdated(); + $component->callAfterStateUpdated(shouldBubbleToParents: false); return true; } if (str($path)->startsWith("{$component->getStatePath()}.")) { - $component->callAfterStateUpdated(); + $component->callAfterStateUpdated(shouldBubbleToParents: false); } foreach ($component->getChildComponentContainers() as $container) { diff --git a/packages/infolists/resources/views/components/image-entry.blade.php b/packages/infolists/resources/views/components/image-entry.blade.php index 00f7a38e72..ccb6cf545b 100644 --- a/packages/infolists/resources/views/components/image-entry.blade.php +++ b/packages/infolists/resources/views/components/image-entry.blade.php @@ -116,10 +116,6 @@ @if ($hasLimitedRemainingText && (! $isLimitedRemainingTextSeparate) && $isCircular)