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)
$isCircular, diff --git a/packages/panels/docs/05-dashboard.md b/packages/panels/docs/05-dashboard.md index e3942cf9b2..594dfb850f 100644 --- a/packages/panels/docs/05-dashboard.md +++ b/packages/panels/docs/05-dashboard.md @@ -215,6 +215,39 @@ class Dashboard extends BaseDashboard Handling data from the filter action is the same as handling data from the filters header form, except that the data is validated before being passed to the widget. The `InteractsWithPageFilters` trait still applies. +### Persisting widget filters in the user's session + +By default, the dashboard filters applied will persist in the user's session between page loads. To disable this, override the `$persistsFiltersInSession` property in the dashboard page class: + +```php +use Filament\Pages\Dashboard as BaseDashboard; +use Filament\Pages\Dashboard\Concerns\HasFiltersForm; + +class Dashboard extends BaseDashboard +{ + use HasFiltersForm; + + protected bool $persistsFiltersInSession = false; +} +``` + +Alternatively, override the `persistsFiltersInSession()` method in the dashboard page class: + +```php +use Filament\Pages\Dashboard as BaseDashboard; +use Filament\Pages\Dashboard\Concerns\HasFiltersForm; + +class Dashboard extends BaseDashboard +{ + use HasFiltersForm; + + public function persistsFiltersInSession(): bool + { + return false; + } +} +``` + ## Disabling the default widgets By default, two widgets are displayed on the dashboard. These widgets can be disabled by updating the `widgets()` array of the [configuration](configuration): diff --git a/packages/panels/resources/lang/fi/global-search.php b/packages/panels/resources/lang/fi/global-search.php index 7dca9975c4..e5d93a047a 100644 --- a/packages/panels/resources/lang/fi/global-search.php +++ b/packages/panels/resources/lang/fi/global-search.php @@ -4,7 +4,7 @@ return [ 'field' => [ 'label' => 'Globaali haku', - 'placeholder' => 'Etsi', + 'placeholder' => 'Hae', ], 'no_results_message' => 'Hakutuloksia ei löytynyt.', diff --git a/packages/panels/resources/lang/fi/pages/auth/email-verification/email-verification-prompt.php b/packages/panels/resources/lang/fi/pages/auth/email-verification/email-verification-prompt.php index d776777730..cb9991e9a0 100644 --- a/packages/panels/resources/lang/fi/pages/auth/email-verification/email-verification-prompt.php +++ b/packages/panels/resources/lang/fi/pages/auth/email-verification/email-verification-prompt.php @@ -9,7 +9,7 @@ return [ 'actions' => [ 'resend_notification' => [ - 'label' => 'Lähetä uudelleen ', + 'label' => 'Lähetä uudelleen', ], ], diff --git a/packages/panels/resources/lang/fi/pages/auth/password-reset/request-password-reset.php b/packages/panels/resources/lang/fi/pages/auth/password-reset/request-password-reset.php index d6dd28b943..11b72102f6 100644 --- a/packages/panels/resources/lang/fi/pages/auth/password-reset/request-password-reset.php +++ b/packages/panels/resources/lang/fi/pages/auth/password-reset/request-password-reset.php @@ -32,6 +32,10 @@ return [ 'notifications' => [ + 'sent' => [ + 'body' => 'Jos tiliä ei ole olemassa, et vastaanota sähköpostia.', + ], + 'throttled' => [ 'title' => 'Liian monta pyyntöä', 'body' => 'Yritä uudelleen :seconds sekunnin kuluttua.', diff --git a/packages/panels/resources/lang/pt_BR/pages/auth/password-reset/request-password-reset.php b/packages/panels/resources/lang/pt_BR/pages/auth/password-reset/request-password-reset.php index cb28a4a578..dff5cfcdef 100644 --- a/packages/panels/resources/lang/pt_BR/pages/auth/password-reset/request-password-reset.php +++ b/packages/panels/resources/lang/pt_BR/pages/auth/password-reset/request-password-reset.php @@ -32,6 +32,10 @@ return [ 'notifications' => [ + 'sent' => [ + 'body' => 'Se sua conta não existir, você não receberá o e-mail.', + ], + 'throttled' => [ 'title' => 'Muitas solicitações', 'body' => 'Por favor tente novamente em :seconds segundos.', diff --git a/packages/panels/resources/lang/sv/pages/auth/email-verification/email-verification-prompt.php b/packages/panels/resources/lang/sv/pages/auth/email-verification/email-verification-prompt.php index 67d37a94a1..02aa3bbb56 100644 --- a/packages/panels/resources/lang/sv/pages/auth/email-verification/email-verification-prompt.php +++ b/packages/panels/resources/lang/sv/pages/auth/email-verification/email-verification-prompt.php @@ -15,7 +15,7 @@ return [ ], 'messages' => [ - 'notification_not_received' => 'Inte fått mejlet vi skickade?', + 'notification_not_received' => 'Inte fått meddelandet vi skickade?', 'notification_sent' => 'Vi skickade ett meddelande till :email med instruktioner på hur du verifierar din mejladress.', ], diff --git a/packages/panels/resources/lang/sv/pages/auth/password-reset/request-password-reset.php b/packages/panels/resources/lang/sv/pages/auth/password-reset/request-password-reset.php index 0c4b470b38..9599853aa2 100644 --- a/packages/panels/resources/lang/sv/pages/auth/password-reset/request-password-reset.php +++ b/packages/panels/resources/lang/sv/pages/auth/password-reset/request-password-reset.php @@ -23,7 +23,7 @@ return [ 'actions' => [ 'request' => [ - 'label' => 'Skicka mejlmeddelande', + 'label' => 'Skicka meddelande', ], ], @@ -32,6 +32,10 @@ return [ 'notifications' => [ + 'sent' => [ + 'body' => 'Om ditt konto inte finns, kommer du inte att få något meddelande.', + ], + 'throttled' => [ 'title' => 'För många förfrågningar', 'body' => 'Vänligen försök igen om :seconds sekunder.', diff --git a/packages/panels/resources/views/components/layout/base.blade.php b/packages/panels/resources/views/components/layout/base.blade.php index 1bc67e2631..b70551b30b 100644 --- a/packages/panels/resources/views/components/layout/base.blade.php +++ b/packages/panels/resources/views/components/layout/base.blade.php @@ -12,7 +12,7 @@ ]) > - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::HEAD_START, scopes: $livewire->getRenderHookScopes()) }} + {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::HEAD_START, scopes: $livewire?->getRenderHookScopes()) }} @@ -31,7 +31,7 @@ {{ filled($title) ? "{$title} - " : null }} {{ $brandName }} - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::STYLES_BEFORE, scopes: $livewire->getRenderHookScopes()) }} + {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::STYLES_BEFORE, scopes: $livewire?->getRenderHookScopes()) }}