From 2058210b4b83d22c16af133d2f4260bda6fe57dd Mon Sep 17 00:00:00 2001 From: William Nettmann Date: Thu, 8 Feb 2024 13:53:46 +0200 Subject: [PATCH 01/87] Update 12-repeater.md Add suggestion to use `saveRelationshipsUsing(null)` when using a Select field depending on a relationship nested within the Repeater schema, to avoid a `Call to undefined method Illuminate\Database\Eloquent\Relations\HasOne::associate()` exception. --- packages/forms/docs/03-fields/12-repeater.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/forms/docs/03-fields/12-repeater.md b/packages/forms/docs/03-fields/12-repeater.md index 90d3a2a068..d83ea88f17 100644 --- a/packages/forms/docs/03-fields/12-repeater.md +++ b/packages/forms/docs/03-fields/12-repeater.md @@ -219,6 +219,22 @@ Repeater::make('qualifications') ]) ``` +When using a Select field depending on a relationship nested within the Repeater schema, it may be necesary to use `saveRelationshipsUsing(null)` if you experience an `Call to undefined method Illuminate\Database\Eloquent\Relations\HasOne::associate()` exception. + +```php +use Filament\Forms\Components\Repeater; +use Filament\Forms\Components\Select; + +Repeater::make('specimens') + ->relationship('specimens') + ->schema([ + Select::make('specimen_container_id') + ->relationship('specimen_container') + ->saveRelationshipsUsing(null), + // ... + ]) +``` + When using `disabled()` with `relationship()`, ensure that `disabled()` is called before `relationship()`. This ensures that the `dehydrated()` call from within `relationship()` is not overridden by the call from `disabled()`: ```php From baf8333b1048818b90a293f38a3d4c9c3ec35e7b Mon Sep 17 00:00:00 2001 From: shepard153 Date: Mon, 12 Feb 2024 11:40:09 +0100 Subject: [PATCH 02/87] Add Polish export/import translations --- packages/actions/resources/lang/pl/export.php | 77 +++++++++++++++++++ packages/actions/resources/lang/pl/import.php | 77 +++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 packages/actions/resources/lang/pl/export.php create mode 100644 packages/actions/resources/lang/pl/import.php diff --git a/packages/actions/resources/lang/pl/export.php b/packages/actions/resources/lang/pl/export.php new file mode 100644 index 0000000000..5d12f1d820 --- /dev/null +++ b/packages/actions/resources/lang/pl/export.php @@ -0,0 +1,77 @@ + 'Eksportuj :label', + + 'modal' => [ + + 'heading' => 'Eksportuj :label', + + 'form' => [ + + 'columns' => [ + + 'label' => 'Kolumny', + + 'form' => [ + + 'is_enabled' => [ + 'label' => ':column włączony', + ], + + 'label' => [ + 'label' => 'Etykieta :column', + ], + + ], + + ], + + ], + + 'actions' => [ + + 'export' => [ + 'label' => 'Eksportuj', + ], + + ], + + ], + + 'notifications' => [ + + 'completed' => [ + + 'title' => 'Eksport zakończony', + + 'actions' => [ + + 'download_csv' => [ + 'label' => 'Pobierz .csv', + ], + + 'download_xlsx' => [ + 'label' => 'Pobierz .xlsx', + ], + + ], + + ], + + 'max_rows' => [ + 'title' => 'Zbyt dużo wierszy', + 'body' => 'Nie możesz wyeksportować więcej niż 1 wiersz na raz.|Nie możesz wyeksportować więcej niż :count wierszy na raz.', + ], + + 'started' => [ + 'title' => 'Eksport rozpoczęty', + 'body' => 'Rozpoczęto eksport i 1 wiersz zostanie przetworzony w tle.|Rozpoczęto eksport i :count wierszy zostanie przetworzonych w tle.', + ], + + ], + + 'file_name' => 'eksport-:export_id-:model', + +]; diff --git a/packages/actions/resources/lang/pl/import.php b/packages/actions/resources/lang/pl/import.php new file mode 100644 index 0000000000..461e28b216 --- /dev/null +++ b/packages/actions/resources/lang/pl/import.php @@ -0,0 +1,77 @@ + 'Importuj :label', + + 'modal' => [ + + 'heading' => 'Importuj :label', + + 'form' => [ + + 'file' => [ + 'label' => 'Plik', + 'placeholder' => 'Wybierz plik CSV', + ], + + 'columns' => [ + 'label' => 'Kolumny', + 'placeholder' => 'Wybierz kolumnę', + ], + + ], + + 'actions' => [ + + 'download_example' => [ + 'label' => 'Pobierz przykładowy plik CSV', + ], + + 'import' => [ + 'label' => 'Importuj', + ], + + ], + + ], + + 'notifications' => [ + + 'completed' => [ + + 'title' => 'Import zakończony', + + 'actions' => [ + + 'download_failed_rows_csv' => [ + 'label' => 'Pobierz informacje o niepowodzeniach', + ], + + ], + + ], + + 'max_rows' => [ + 'title' => 'Przesłany plik CSV jest zbyt duży', + 'body' => 'Nie możesz zaimportować więcej niż 1 wiersz na raz.|Nie możesz zaimportować więcej niż :count wierszy na raz.', + ], + + 'started' => [ + 'title' => 'Import rozpoczęty', + 'body' => 'Import rozpoczęty i 1 wiersz zostanie przetworzony w tle.|Import rozpoczęty i :count wierszy zostanie przetworzonych w tle.', + ], + + ], + + 'example_csv' => [ + 'file_name' => ':importer-example', + ], + + 'failure_csv' => [ + 'file_name' => 'import-:import_id-:csv_name-failed-rows', + 'error_header' => 'błąd', + 'system_error' => 'Błąd systemu, skontaktuj się z pomocą techniczną.', + ], + +]; From eab726d3046155ce0589260e28173e924563ecb1 Mon Sep 17 00:00:00 2001 From: Zep Fietje Date: Mon, 12 Feb 2024 12:29:18 +0100 Subject: [PATCH 03/87] Add CSS hook class for button group --- .../support/resources/views/components/button/group.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/support/resources/views/components/button/group.blade.php b/packages/support/resources/views/components/button/group.blade.php index a7d90aa31b..d06423bfe5 100644 --- a/packages/support/resources/views/components/button/group.blade.php +++ b/packages/support/resources/views/components/button/group.blade.php @@ -1,7 +1,7 @@
class([ - 'grid grid-flow-col rounded-lg shadow-sm ring-1 ring-gray-950/10 dark:ring-white/20', + 'fi-btn-group grid grid-flow-col rounded-lg shadow-sm ring-1 ring-gray-950/10 dark:ring-white/20', ]) }} > From d1fba024db42d689c196f6bcb5d6abcbc4aa3702 Mon Sep 17 00:00:00 2001 From: Remzi Kocak Date: Mon, 12 Feb 2024 14:33:35 +0300 Subject: [PATCH 04/87] Add Turkish translations for Export functionality --- packages/actions/resources/lang/tr/export.php | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 packages/actions/resources/lang/tr/export.php diff --git a/packages/actions/resources/lang/tr/export.php b/packages/actions/resources/lang/tr/export.php new file mode 100644 index 0000000000..9dbadbd2ee --- /dev/null +++ b/packages/actions/resources/lang/tr/export.php @@ -0,0 +1,77 @@ + 'Dışa Aktar :label', + + 'modal' => [ + + 'heading' => 'Dışa Aktar :label', + + 'form' => [ + + 'columns' => [ + + 'label' => 'Sütunlar', + + 'form' => [ + + 'is_enabled' => [ + 'label' => ':column etkin', + ], + + 'label' => [ + 'label' => ':column etiketi', + ], + + ], + + ], + + ], + + 'actions' => [ + + 'export' => [ + 'label' => 'Dışa Aktar', + ], + + ], + + ], + + 'notifications' => [ + + 'completed' => [ + + 'title' => 'Dışa Aktarım Tamamlandı', + + 'actions' => [ + + 'download_csv' => [ + 'label' => '.csv Olarak İndir', + ], + + 'download_xlsx' => [ + 'label' => '.xlsx Olarak İndir', + ], + + ], + + ], + + 'max_rows' => [ + 'title' => 'Maksimum Satır Sayısı Aşıldı', + 'body' => 'Birden fazla satırı dışa aktaramazsınız.|:count satırı dışa aktaramazsınız.', + ], + + 'started' => [ + 'title' => 'Dışa Aktarım Başladı', + 'body' => 'Dışa aktarım başladı ve 1 satır arka planda işlenecek.|Dışa aktarım başladı ve :count satır arka planda işlenecek.', + ], + + ], + + 'file_name' => 'export-:export_id-:model', + +]; From 2d6fc2a5ad9a7905e2aa10e6bc4a9ed562787b8e Mon Sep 17 00:00:00 2001 From: Remzi Kocak Date: Mon, 12 Feb 2024 14:38:38 +0300 Subject: [PATCH 05/87] Add Turkish translations for import functionality --- packages/actions/resources/lang/tr/import.php | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 packages/actions/resources/lang/tr/import.php diff --git a/packages/actions/resources/lang/tr/import.php b/packages/actions/resources/lang/tr/import.php new file mode 100644 index 0000000000..fcd5b01167 --- /dev/null +++ b/packages/actions/resources/lang/tr/import.php @@ -0,0 +1,77 @@ + 'İçe Aktar: :label', + + 'modal' => [ + + 'heading' => 'İçe Aktar: :label', + + 'form' => [ + + 'file' => [ + 'label' => 'Dosya', + 'placeholder' => 'Bir CSV dosyası seçin', + ], + + 'columns' => [ + 'label' => 'Kolonlar', + 'placeholder' => 'Kolonları eşleştirin', + ], + + ], + + 'actions' => [ + + 'download_example' => [ + 'label' => 'Örnek CSV Dosyasını İndir', + ], + + 'import' => [ + 'label' => 'İçe Aktar', + ], + + ], + + ], + + 'notifications' => [ + + 'completed' => [ + + 'title' => 'İçe Aktarım Tamamlandı', + + 'actions' => [ + + 'download_failed_rows_csv' => [ + 'label' => 'Başarısız satır hakkında bilgileri indir|Başarısız satırlar hakkında bilgileri indir', + ], + + ], + + ], + + 'max_rows' => [ + 'title' => 'Yüklenen Dosya Çok Büyük', + 'body' => 'Aynı anda 1\'den fazla satır içeren dosyaları içe aktaramazsınız.|Aynı anda :count\'den fazla satır içeren dosyaları içe aktaramazsınız.', + ], + + 'started' => [ + 'title' => 'İçe Aktarım Başladı', + 'body' => 'İçe aktarım başladı ve 1 satır arka planda işlenecek.|İçe aktarım başladı ve :count satır arka planda işlenecek.', + ], + + ], + + 'example_csv' => [ + 'file_name' => ':importer-example', + ], + + 'failure_csv' => [ + 'file_name' => 'import-:import_id-:csv_name-failed-rows', + 'error_header' => 'hata', + 'system_error' => 'Sistem Hatası', + ], + +]; From 04b9aa1dbe74c31fef07e352e123cd41ef293be1 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Mon, 12 Feb 2024 11:52:46 +0000 Subject: [PATCH 06/87] issue --- .../panels/src/Commands/MakeIssueCommand.php | 62 ------------------- .../panels/src/FilamentServiceProvider.php | 1 - .../Commands/Aliases/MakeIssueCommand.php | 4 +- .../support/src/Commands/MakeIssueCommand.php | 37 +++++++++++ .../support/src/SupportServiceProvider.php | 5 ++ 5 files changed, 44 insertions(+), 65 deletions(-) delete mode 100644 packages/panels/src/Commands/MakeIssueCommand.php rename packages/panels/src/{ => Support}/Commands/Aliases/MakeIssueCommand.php (65%) create mode 100644 packages/support/src/Commands/MakeIssueCommand.php diff --git a/packages/panels/src/Commands/MakeIssueCommand.php b/packages/panels/src/Commands/MakeIssueCommand.php deleted file mode 100644 index c882b0f532..0000000000 --- a/packages/panels/src/Commands/MakeIssueCommand.php +++ /dev/null @@ -1,62 +0,0 @@ - $issueTemplate, - 'package-version' => $filament, - 'laravel-version' => $laravel, - 'livewire-version' => $livewire, - 'php-version' => $php, - ]; - - $fullUrl = "{$baseGithubUrl}" . http_build_query($queryParams); - - $this->openGithubIssueInBrowser($fullUrl); - } - - public function openGithubIssueInBrowser(string $url): void - { - if (PHP_OS_FAMILY === 'Darwin') { - exec('open "' . $url . '"'); - } - if (PHP_OS_FAMILY === 'Linux') { - exec('xdg-open "' . $url . '"'); - } - if (PHP_OS_FAMILY === 'Windows') { - exec('start "" "' . $url . '"'); - } - } -} diff --git a/packages/panels/src/FilamentServiceProvider.php b/packages/panels/src/FilamentServiceProvider.php index f880b3b631..bdbcfa2ed8 100644 --- a/packages/panels/src/FilamentServiceProvider.php +++ b/packages/panels/src/FilamentServiceProvider.php @@ -108,7 +108,6 @@ class FilamentServiceProvider extends PackageServiceProvider Commands\CacheComponentsCommand::class, Commands\ClearCachedComponentsCommand::class, Commands\MakeClusterCommand::class, - Commands\MakeIssueCommand::class, Commands\MakePageCommand::class, Commands\MakePanelCommand::class, Commands\MakeRelationManagerCommand::class, diff --git a/packages/panels/src/Commands/Aliases/MakeIssueCommand.php b/packages/panels/src/Support/Commands/Aliases/MakeIssueCommand.php similarity index 65% rename from packages/panels/src/Commands/Aliases/MakeIssueCommand.php rename to packages/panels/src/Support/Commands/Aliases/MakeIssueCommand.php index f47ff6b193..42da90f261 100644 --- a/packages/panels/src/Commands/Aliases/MakeIssueCommand.php +++ b/packages/panels/src/Support/Commands/Aliases/MakeIssueCommand.php @@ -1,8 +1,8 @@ openUrlInBrowser('https://github.com/filamentphp/filament/issues/new?' . http_build_query([ + 'template' => 'bug_report.yml', + 'package-version' => InstalledVersions::getPrettyVersion('filament/support'), + 'laravel-version' => InstalledVersions::getPrettyVersion('laravel/framework'), + 'livewire-version' => InstalledVersions::getPrettyVersion('livewire/livewire'), + 'php-version' => PHP_VERSION, + ])); + } + + public function openUrlInBrowser(string $url): void + { + if (PHP_OS_FAMILY === 'Darwin') { + exec('open "' . $url . '"'); + } + if (PHP_OS_FAMILY === 'Linux') { + exec('xdg-open "' . $url . '"'); + } + if (PHP_OS_FAMILY === 'Windows') { + exec('start "" "' . $url . '"'); + } + } +} diff --git a/packages/support/src/SupportServiceProvider.php b/packages/support/src/SupportServiceProvider.php index d041b1417e..59e30cf275 100644 --- a/packages/support/src/SupportServiceProvider.php +++ b/packages/support/src/SupportServiceProvider.php @@ -7,9 +7,11 @@ use Filament\Support\Assets\AssetManager; use Filament\Support\Assets\Css; use Filament\Support\Assets\Js; use Filament\Support\Colors\ColorManager; +use Filament\Support\Commands\Aliases\MakeIssueCommand as MakeIssueCommandAlias; use Filament\Support\Commands\AssetsCommand; use Filament\Support\Commands\CheckTranslationsCommand; use Filament\Support\Commands\InstallCommand; +use Filament\Support\Commands\MakeIssueCommand; use Filament\Support\Commands\UpgradeCommand; use Filament\Support\Components\ComponentManager; use Filament\Support\Components\Contracts\ScopedComponentManager; @@ -39,6 +41,9 @@ class SupportServiceProvider extends PackageServiceProvider CheckTranslationsCommand::class, InstallCommand::class, UpgradeCommand::class, + + MakeIssueCommand::class, + MakeIssueCommandAlias::class, ]) ->hasConfigFile() ->hasTranslations() From 2be8d8be99057697bffd9d927982aeb39f8fb511 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Mon, 12 Feb 2024 16:40:36 +0000 Subject: [PATCH 07/87] feature: Collapsed sidebar group dropdowns --- .../views/components/layout/index.blade.php | 31 ++--- .../page/sub-navigation/sidebar.blade.php | 1 + .../views/components/sidebar/group.blade.php | 106 +++++++++++++++++- .../views/components/sidebar/index.blade.php | 1 + .../views/components/sidebar/item.blade.php | 6 +- .../panels/src/Navigation/NavigationGroup.php | 35 +----- 6 files changed, 124 insertions(+), 56 deletions(-) diff --git a/packages/panels/resources/views/components/layout/index.blade.php b/packages/panels/resources/views/components/layout/index.blade.php index 2ef3e459fc..c496b7cb39 100644 --- a/packages/panels/resources/views/components/layout/index.blade.php +++ b/packages/panels/resources/views/components/layout/index.blade.php @@ -5,20 +5,10 @@ @endphp -
- @if (filament()->hasNavigation()) -
- - - @endif - + {{-- The sidebar is after the page content in the markup to fix issues with page content overlapping dropdown content from the sidebar --}} +
isSidebarCollapsibleOnDesktop()) x-data="{}" @@ -89,5 +79,18 @@ {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::FOOTER, scopes: $livewire->getRenderHookScopes()) }}
+ + @if (filament()->hasNavigation()) +
+ + + @endif
diff --git a/packages/panels/resources/views/components/page/sub-navigation/sidebar.blade.php b/packages/panels/resources/views/components/page/sub-navigation/sidebar.blade.php index 679c9ec7ad..c32acc28f8 100644 --- a/packages/panels/resources/views/components/page/sub-navigation/sidebar.blade.php +++ b/packages/panels/resources/views/components/page/sub-navigation/sidebar.blade.php @@ -8,6 +8,7 @@ > @foreach ($navigation as $navigationGroup) false, 'collapsible' => true, 'icon' => null, 'items' => [], @@ -7,6 +8,11 @@ 'subNavigation' => false, ]) +@php + $sidebarCollapsible = $sidebarCollapsible && filament()->isSidebarCollapsibleOnDesktop(); + $hasDropdown = filled($label) && filled($icon) && $sidebarCollapsible; +@endphp +
  • isSidebarCollapsibleOnDesktop()) + @if ($sidebarCollapsible) x-show="$store.sidebar.isOpen" x-transition:enter="delay-100 lg:transition" x-transition:enter-start="opacity-0" @@ -56,14 +62,104 @@
  • @endif + @if ($hasDropdown) + + + + + + @php + $lists = []; + + foreach ($items as $item) { + if ($childItems = $item->getChildItems()) { + $lists[] = [ + $item, + ...$childItems, + ]; + $lists[] = []; + + continue; + } + + if (empty($lists)) { + $lists[] = [$item]; + + continue; + } + + $lists[count($lists) - 1][] = $item; + } + + if (empty($lists[count($lists) - 1])) { + array_pop($lists); + } + @endphp + + @foreach ($lists as $list) + + @foreach ($list as $item) + @php + $itemIsActive = $item->isActive(); + @endphp + + + {{ $item->getLabel() }} + + @endforeach + + @endforeach + + @endif +
      isSidebarCollapsibleOnDesktop()) + @if (filled($label)) + @if ($sidebarCollapsible) + x-show="$store.sidebar.isOpen ? ! $store.sidebar.groupIsCollapsed(label) : ! @js($hasDropdown)" + @else + x-show="! $store.sidebar.groupIsCollapsed(label)" + @endif + x-collapse.duration.200ms + @endif + @if ($sidebarCollapsible) x-transition:enter="delay-100 lg:transition" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" @endif - x-collapse.duration.200ms class="fi-sidebar-group-items flex flex-col gap-y-1" > @foreach ($items as $item) @@ -77,7 +173,7 @@ :child-items="$item->getChildItems()" :first="$loop->first" :grouped="filled($label)" - :icon="$item->getIcon()" + :icon="$icon ? ($hasDropdown ? null : throw new \Exception('Navigation group [' . $label . '] has an icon but one or more of its items also have icons. Either the group or its items can have icons, but not both. This is to ensure a proper user experience.')) : $item->getIcon()" :last="$loop->last" :should-open-url-in-new-tab="$item->shouldOpenUrlInNewTab()" :sidebar-collapsible="$sidebarCollapsible" diff --git a/packages/panels/resources/views/components/sidebar/index.blade.php b/packages/panels/resources/views/components/sidebar/index.blade.php index d51499912e..2fd8370c4c 100644 --- a/packages/panels/resources/views/components/sidebar/index.blade.php +++ b/packages/panels/resources/views/components/sidebar/index.blade.php @@ -117,6 +117,7 @@
        @foreach ($navigation as $group) $active, ]) > - @if (filled($icon) && ((! $subGrouped) || filament()->isSidebarCollapsibleOnDesktop())) + @if (filled($icon) && ((! $subGrouped) || $sidebarCollapsible)) ! $active, @@ -65,7 +65,7 @@ @if ((blank($icon) && $grouped) || $subGrouped)
        isSidebarCollapsibleOnDesktop()) + @if (filled($icon) && $subGrouped && $sidebarCollapsible) x-show="$store.sidebar.isOpen" @endif class="fi-sidebar-item-grouped-border relative flex h-6 w-6 items-center justify-center" diff --git a/packages/panels/src/Navigation/NavigationGroup.php b/packages/panels/src/Navigation/NavigationGroup.php index 18765ac68e..0a20d4e566 100644 --- a/packages/panels/src/Navigation/NavigationGroup.php +++ b/packages/panels/src/Navigation/NavigationGroup.php @@ -3,7 +3,6 @@ namespace Filament\Navigation; use Closure; -use Exception; use Filament\Support\Components\Component; use Filament\Support\Concerns\HasExtraSidebarAttributes; use Filament\Support\Concerns\HasExtraTopbarAttributes; @@ -82,13 +81,7 @@ class NavigationGroup extends Component public function getIcon(): ?string { - $icon = $this->evaluate($this->icon); - - if ($this->hasItemIcons() && filled($icon)) { - throw new Exception("Navigation group [{$this->getLabel()}] has an icon but one or more of its items also have icons. Either the group or its items can have icons, but not both. This is to ensure a proper user experience."); - } - - return $icon; + return $this->evaluate($this->icon); } /** @@ -126,30 +119,4 @@ class NavigationGroup extends Component return false; } - - public function hasItemIcons(): bool - { - $hasIconCount = 0; - $hasNoIconCount = 0; - - foreach ($this->getItems() as $item) { - if (! $item instanceof NavigationItem) { - continue; - } - - if (blank($item->getIcon())) { - $hasNoIconCount++; - - continue; - } - - $hasIconCount++; - } - - if (($hasIconCount > 0) && ($hasNoIconCount > 0) && filled($label = $this->getLabel())) { - throw new Exception("Navigation group [{$label}] has items with and without icons. All items must have icons or none of them can have icons. This is to ensure a proper user experience."); - } - - return $hasIconCount > 0; - } } From 88bf3790e375cef6e3d31afece25a557a1195e5a Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Mon, 12 Feb 2024 16:45:52 +0000 Subject: [PATCH 08/87] Update 06-navigation.md --- packages/panels/docs/06-navigation.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/panels/docs/06-navigation.md b/packages/panels/docs/06-navigation.md index bf36b92c60..5e30b7b5e9 100644 --- a/packages/panels/docs/06-navigation.md +++ b/packages/panels/docs/06-navigation.md @@ -229,6 +229,14 @@ public function panel(Panel $panel): Panel } ``` +### Navigation groups in a collapsible sidebar + +> This section only applies to `sidebarCollapsibleOnDesktop()`, not `sidebarFullyCollapsibleOnDesktop()`, since the fully collapsible UI simply hides the entire sidebar instead of making its design minimal. + +When using a collapsible sidebar on desktop, you will also often be using [navigation groups](#grouping-navigation-items). By default, the labels of each navigation group will be hidden when the sidebar is collapsed, since there is no space to display them. Even if the navigation group itself is [collapsible](#making-navigation-groups-not-collapsible), all items will still be visible in the collapsed sidebar, since there is no group label to click on to expand the group. + +These issues can be solved, to achieve a very minimal sidebar design, by [passing an `icon()`](#customizing-navigation-groups) to the navigation group objects. When an icon is defined, the icon will be displayed in the collapsed sidebar instead of the items at all times. When the icon is clicked, a dropdown will open to the side of the icon, revealing the items in the group. + ## Registering custom navigation items To register new navigation items, you can use the [configuration](configuration): From 2e330c8fa1f9b73175ae9bb65b297c51ed0e6242 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Mon, 12 Feb 2024 16:46:01 +0000 Subject: [PATCH 09/87] Update 06-navigation.md --- packages/panels/docs/06-navigation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/panels/docs/06-navigation.md b/packages/panels/docs/06-navigation.md index 5e30b7b5e9..a640a37212 100644 --- a/packages/panels/docs/06-navigation.md +++ b/packages/panels/docs/06-navigation.md @@ -229,7 +229,7 @@ public function panel(Panel $panel): Panel } ``` -### Navigation groups in a collapsible sidebar +### Navigation groups in a collapsible sidebar on desktop > This section only applies to `sidebarCollapsibleOnDesktop()`, not `sidebarFullyCollapsibleOnDesktop()`, since the fully collapsible UI simply hides the entire sidebar instead of making its design minimal. From 94816a852d7ac679a87d3d3f7fdfd441788dcad7 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Mon, 12 Feb 2024 16:46:22 +0000 Subject: [PATCH 10/87] Update 06-navigation.md --- packages/panels/docs/06-navigation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/panels/docs/06-navigation.md b/packages/panels/docs/06-navigation.md index a640a37212..59a2bb1f23 100644 --- a/packages/panels/docs/06-navigation.md +++ b/packages/panels/docs/06-navigation.md @@ -231,7 +231,7 @@ public function panel(Panel $panel): Panel ### Navigation groups in a collapsible sidebar on desktop -> This section only applies to `sidebarCollapsibleOnDesktop()`, not `sidebarFullyCollapsibleOnDesktop()`, since the fully collapsible UI simply hides the entire sidebar instead of making its design minimal. +> This section only applies to `sidebarCollapsibleOnDesktop()`, not `sidebarFullyCollapsibleOnDesktop()`, since the fully collapsible UI just hides the entire sidebar instead of changing its design. When using a collapsible sidebar on desktop, you will also often be using [navigation groups](#grouping-navigation-items). By default, the labels of each navigation group will be hidden when the sidebar is collapsed, since there is no space to display them. Even if the navigation group itself is [collapsible](#making-navigation-groups-not-collapsible), all items will still be visible in the collapsed sidebar, since there is no group label to click on to expand the group. From 481683b85ce2c8486e5b9b4177c0f156dcfb613f Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Mon, 12 Feb 2024 16:50:05 +0000 Subject: [PATCH 11/87] wip --- packages/panels/docs/06-navigation.md | 2 ++ .../resources/views/components/topbar/index.blade.php | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/panels/docs/06-navigation.md b/packages/panels/docs/06-navigation.md index 59a2bb1f23..3efad6efcb 100644 --- a/packages/panels/docs/06-navigation.md +++ b/packages/panels/docs/06-navigation.md @@ -237,6 +237,8 @@ When using a collapsible sidebar on desktop, you will also often be using [navig These issues can be solved, to achieve a very minimal sidebar design, by [passing an `icon()`](#customizing-navigation-groups) to the navigation group objects. When an icon is defined, the icon will be displayed in the collapsed sidebar instead of the items at all times. When the icon is clicked, a dropdown will open to the side of the icon, revealing the items in the group. +When passing an icon to a navigation group, even if the items also have icons, the expanded sidebar UI will not show the item icons. This is to keep the navigation hierarchy clear, and the design minimal. However, the icons for the items will be shown in the collapsed sidebar's dropdowns though, since the hierarchy is already clear from the fact that the dropdown is open. + ## Registering custom navigation items To register new navigation items, you can use the [configuration](configuration): diff --git a/packages/panels/resources/views/components/topbar/index.blade.php b/packages/panels/resources/views/components/topbar/index.blade.php index d24f1dfd5a..cd5002e561 100644 --- a/packages/panels/resources/views/components/topbar/index.blade.php +++ b/packages/panels/resources/views/components/topbar/index.blade.php @@ -82,17 +82,16 @@ @foreach ($group->getItems() as $item) @php - $icon = $item->getIcon(); - $isActive = $item->isActive(); + $itemIsActive = $item->isActive(); @endphp From 2abffeae93574c1b88216923c101458e11a3e074 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Mon, 12 Feb 2024 16:52:43 +0000 Subject: [PATCH 12/87] handle parent nav items in topbar using multiple lists --- .../views/components/topbar/index.blade.php | 68 +++++++++++++------ 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/packages/panels/resources/views/components/topbar/index.blade.php b/packages/panels/resources/views/components/topbar/index.blade.php index cd5002e561..982daaddbd 100644 --- a/packages/panels/resources/views/components/topbar/index.blade.php +++ b/packages/panels/resources/views/components/topbar/index.blade.php @@ -79,26 +79,56 @@ - - @foreach ($group->getItems() as $item) - @php - $itemIsActive = $item->isActive(); - @endphp + @php + $lists = []; - - {{ $item->getLabel() }} - - @endforeach - + foreach ($group->getItems() as $item) { + if ($childItems = $item->getChildItems()) { + $lists[] = [ + $item, + ...$childItems, + ]; + $lists[] = []; + + continue; + } + + if (empty($lists)) { + $lists[] = [$item]; + + continue; + } + + $lists[count($lists) - 1][] = $item; + } + + if (empty($lists[count($lists) - 1])) { + array_pop($lists); + } + @endphp + + @foreach ($lists as $list) + + @foreach ($list as $item) + @php + $itemIsActive = $item->isActive(); + @endphp + + + {{ $item->getLabel() }} + + @endforeach + + @endforeach @else @foreach ($group->getItems() as $item) From 7d50ef68286ead0d1c57b8493b98fc3d763562fc Mon Sep 17 00:00:00 2001 From: shepard153 Date: Mon, 12 Feb 2024 22:24:16 +0100 Subject: [PATCH 13/87] Add option to skip columns selection on Export Action --- .../actions/src/Concerns/CanExportRecords.php | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index 9293b3def6..cd9ce6124d 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -61,6 +61,8 @@ trait CanExportRecords protected ?Closure $modifyQueryUsing = null; + protected bool $skippableSelection = false; + protected function setUp(): void { parent::setUp(); @@ -73,13 +75,13 @@ trait CanExportRecords $this->groupedIcon(FilamentIcon::resolve('actions::export-action.grouped') ?? 'heroicon-m-arrow-down-tray'); - $this->form(fn (ExportAction | ExportTableAction | ExportTableBulkAction $action): array => array_merge([ + $this->form(fn(ExportAction|ExportTableAction|ExportTableBulkAction $action): array => array_merge([ Fieldset::make(__('filament-actions::export.modal.form.columns.label')) ->columns(1) ->inlineLabel() ->schema(function () use ($action): array { return array_map( - fn (ExportColumn $column): Split => Split::make([ + fn(ExportColumn $column): Split => Split::make([ Forms\Components\Checkbox::make('isEnabled') ->label(__('filament-actions::export.modal.form.columns.form.is_enabled.label', ['column' => $column->getName()])) ->hiddenLabel() @@ -91,8 +93,8 @@ trait CanExportRecords ->hiddenLabel() ->default($column->getLabel()) ->placeholder($column->getLabel()) - ->disabled(fn (Forms\Get $get): bool => ! $get('isEnabled')) - ->required(fn (Forms\Get $get): bool => (bool) $get('isEnabled')), + ->disabled(fn(Forms\Get $get): bool => !$get('isEnabled')) + ->required(fn(Forms\Get $get): bool => (bool)$get('isEnabled')), ]) ->verticallyAlignCenter() ->statePath($column->getName()), @@ -100,7 +102,7 @@ trait CanExportRecords ); }) ->statePath('columnMap'), - ], $action->getExporter()::getOptionsFormComponents())); + ], $action->getExporter()::getOptionsFormComponents())); $this->action(function (ExportAction | ExportTableAction | ExportTableBulkAction $action, array $data, Component $livewire) { if ($livewire instanceof HasTable) { @@ -139,14 +141,20 @@ trait CanExportRecords Arr::except($data, ['columnMap']), ); - $columnMap = collect($data['columnMap']) - ->dot() - ->reduce(fn (Collection $carry, mixed $value, string $key): Collection => $carry->mergeRecursive([ - Str::beforeLast($key, '.') => [Str::afterLast($key, '.') => $value], - ]), collect()) - ->filter(fn (array $column): bool => $column['isEnabled'] ?? false) - ->mapWithKeys(fn (array $column, string $columnName): array => [$columnName => $column['label']]) - ->all(); + if ($this->skippableSelection) { + $columnMap = collect($action->getExporter()::getColumns()) + ->mapWithKeys(fn(ExportColumn $column): array => [$column->getName() => $column->getLabel()] + )->all(); + } else { + $columnMap = collect($data['columnMap']) + ->dot() + ->reduce(fn(Collection $carry, mixed $value, string $key): Collection => $carry->mergeRecursive([ + Str::beforeLast($key, '.') => [Str::afterLast($key, '.') => $value], + ]), collect()) + ->filter(fn(array $column): bool => $column['isEnabled'] ?? false) + ->mapWithKeys(fn(array $column, string $columnName): array => [$columnName => $column['label']]) + ->all(); + } $export = app(Export::class); $export->user()->associate($user); @@ -387,4 +395,11 @@ trait CanExportRecords return $this; } + + public function skippableSelection(bool $skippable = true): static + { + $this->skippableSelection = $skippable; + + return $this; + } } From 1c73eedae557d707e3e2fb5248ca2741ad57444d Mon Sep 17 00:00:00 2001 From: shepard153 Date: Mon, 12 Feb 2024 22:42:37 +0100 Subject: [PATCH 14/87] Add option to skip columns selection on Export Action --- .../actions/docs/07-prebuilt-actions/09-export.md | 13 +++++++++++++ packages/actions/src/Concerns/CanExportRecords.php | 11 +---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/actions/docs/07-prebuilt-actions/09-export.md b/packages/actions/docs/07-prebuilt-actions/09-export.md index e0e93158a1..965ee64cec 100644 --- a/packages/actions/docs/07-prebuilt-actions/09-export.md +++ b/packages/actions/docs/07-prebuilt-actions/09-export.md @@ -124,6 +124,19 @@ ExportColumn::make('description') ->enabledByDefault(false) ``` +### Disabling column selection + +By default, user will be asked which columns they would like to export. You can disable this functionality by passing `null` to `form()` method: + +```php +use App\Filament\Exports\ProductExporter; +use Filament\Actions\ExportAction; + +ExportAction::make() + ->exporter(ProductExporter::class) + ->form(null) +``` + ### Calculated export column state Sometimes you need to calculate the state of a column, instead of directly reading it from a database column. diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index cd9ce6124d..4f54d52822 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -61,8 +61,6 @@ trait CanExportRecords protected ?Closure $modifyQueryUsing = null; - protected bool $skippableSelection = false; - protected function setUp(): void { parent::setUp(); @@ -141,7 +139,7 @@ trait CanExportRecords Arr::except($data, ['columnMap']), ); - if ($this->skippableSelection) { + if (! $this->form) { $columnMap = collect($action->getExporter()::getColumns()) ->mapWithKeys(fn(ExportColumn $column): array => [$column->getName() => $column->getLabel()] )->all(); @@ -395,11 +393,4 @@ trait CanExportRecords return $this; } - - public function skippableSelection(bool $skippable = true): static - { - $this->skippableSelection = $skippable; - - return $this; - } } From 66746518c0b2bc5cfd816465f7728cc3ebbcd1c8 Mon Sep 17 00:00:00 2001 From: shepard153 Date: Mon, 12 Feb 2024 22:50:29 +0100 Subject: [PATCH 15/87] Add option to skip columns selection on Export Action --- packages/actions/src/Concerns/CanExportRecords.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index 4f54d52822..b04df5fa10 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -73,13 +73,13 @@ trait CanExportRecords $this->groupedIcon(FilamentIcon::resolve('actions::export-action.grouped') ?? 'heroicon-m-arrow-down-tray'); - $this->form(fn(ExportAction|ExportTableAction|ExportTableBulkAction $action): array => array_merge([ + $this->form(fn (ExportAction | ExportTableAction | ExportTableBulkAction $action): array => array_merge([ Fieldset::make(__('filament-actions::export.modal.form.columns.label')) ->columns(1) ->inlineLabel() ->schema(function () use ($action): array { return array_map( - fn(ExportColumn $column): Split => Split::make([ + fn (ExportColumn $column): Split => Split::make([ Forms\Components\Checkbox::make('isEnabled') ->label(__('filament-actions::export.modal.form.columns.form.is_enabled.label', ['column' => $column->getName()])) ->hiddenLabel() @@ -91,8 +91,8 @@ trait CanExportRecords ->hiddenLabel() ->default($column->getLabel()) ->placeholder($column->getLabel()) - ->disabled(fn(Forms\Get $get): bool => !$get('isEnabled')) - ->required(fn(Forms\Get $get): bool => (bool)$get('isEnabled')), + ->disabled(fn (Forms\Get $get): bool => ! $get('isEnabled')) + ->required(fn (Forms\Get $get): bool => (bool) $get('isEnabled')), ]) ->verticallyAlignCenter() ->statePath($column->getName()), @@ -100,7 +100,7 @@ trait CanExportRecords ); }) ->statePath('columnMap'), - ], $action->getExporter()::getOptionsFormComponents())); + ], $action->getExporter()::getOptionsFormComponents())); $this->action(function (ExportAction | ExportTableAction | ExportTableBulkAction $action, array $data, Component $livewire) { if ($livewire instanceof HasTable) { From 8172ff2b3d6571d3ac19afcc2955f7f9fb87ae30 Mon Sep 17 00:00:00 2001 From: Ash Monsh Date: Tue, 13 Feb 2024 01:42:49 +0300 Subject: [PATCH 16/87] adding header to sidebar dropdown --- .../resources/views/components/sidebar/group.blade.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/panels/resources/views/components/sidebar/group.blade.php b/packages/panels/resources/views/components/sidebar/group.blade.php index 2e338638e2..7e45099444 100644 --- a/packages/panels/resources/views/components/sidebar/group.blade.php +++ b/packages/panels/resources/views/components/sidebar/group.blade.php @@ -121,6 +121,12 @@ } @endphp + @if (filled($label)) + + {{ $label }} + + @endif + @foreach ($lists as $list) @foreach ($list as $item) From 14c040343829a34b8b63c2e2c2ab25aa297f1f0d Mon Sep 17 00:00:00 2001 From: Anthony Rappa Date: Tue, 13 Feb 2024 00:03:15 -0500 Subject: [PATCH 17/87] Add mask to TextInputColumn --- .../views/columns/text-input-column.blade.php | 6 ++++++ packages/tables/src/Columns/TextInputColumn.php | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/packages/tables/resources/views/columns/text-input-column.blade.php b/packages/tables/resources/views/columns/text-input-column.blade.php index ff02801f8e..a18e00f7f7 100644 --- a/packages/tables/resources/views/columns/text-input-column.blade.php +++ b/packages/tables/resources/views/columns/text-input-column.blade.php @@ -4,12 +4,17 @@ $isDisabled = $isDisabled(); $state = $getState(); $type = $getType(); + $mask = $getMask(); $alignment = $getAlignment() ?? Alignment::Start; if (! $alignment instanceof Alignment) { $alignment = filled($alignment) ? (Alignment::tryFrom($alignment) ?? $alignment) : null; } + + if (filled($mask)) { + $type = 'text'; + } @endphp
        filled($mask) ? $mask : null, ]) ->class([ match ($alignment) { diff --git a/packages/tables/src/Columns/TextInputColumn.php b/packages/tables/src/Columns/TextInputColumn.php index 2189da45a2..0b0ff9e280 100644 --- a/packages/tables/src/Columns/TextInputColumn.php +++ b/packages/tables/src/Columns/TextInputColumn.php @@ -6,6 +6,7 @@ use Closure; use Filament\Forms\Components\Concerns\HasExtraInputAttributes; use Filament\Forms\Components\Concerns\HasInputMode; use Filament\Forms\Components\Concerns\HasStep; +use Filament\Support\RawJs; use Filament\Tables\Columns\Contracts\Editable; class TextInputColumn extends Column implements Editable @@ -21,6 +22,8 @@ class TextInputColumn extends Column implements Editable */ protected string $view = 'filament-tables::columns.text-input-column'; + protected string | RawJs | Closure | null $mask = null; + protected string | Closure | null $type = null; protected function setUp(): void @@ -41,4 +44,16 @@ class TextInputColumn extends Column implements Editable { return $this->evaluate($this->type) ?? 'text'; } + + public function mask(string | RawJs | Closure | null $mask): static + { + $this->mask = $mask; + + return $this; + } + + public function getMask(): string | RawJs | null + { + return $this->evaluate($this->mask); + } } From 8ace7c85d86f4bb750d8a61d3fa2f021ac7effd2 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Tue, 13 Feb 2024 06:29:22 +0000 Subject: [PATCH 18/87] Update MakeIssueCommand.php --- .../Support => support/src}/Commands/Aliases/MakeIssueCommand.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/{panels/src/Support => support/src}/Commands/Aliases/MakeIssueCommand.php (100%) diff --git a/packages/panels/src/Support/Commands/Aliases/MakeIssueCommand.php b/packages/support/src/Commands/Aliases/MakeIssueCommand.php similarity index 100% rename from packages/panels/src/Support/Commands/Aliases/MakeIssueCommand.php rename to packages/support/src/Commands/Aliases/MakeIssueCommand.php From 8694474393d0cdc675874d25995aadd76573272b Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Tue, 13 Feb 2024 06:40:20 +0000 Subject: [PATCH 19/87] Update text-input-column.blade.php --- .../tables/resources/views/columns/text-input-column.blade.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/tables/resources/views/columns/text-input-column.blade.php b/packages/tables/resources/views/columns/text-input-column.blade.php index a18e00f7f7..d1ac776979 100644 --- a/packages/tables/resources/views/columns/text-input-column.blade.php +++ b/packages/tables/resources/views/columns/text-input-column.blade.php @@ -3,7 +3,6 @@ $isDisabled = $isDisabled(); $state = $getState(); - $type = $getType(); $mask = $getMask(); $alignment = $getAlignment() ?? Alignment::Start; @@ -14,6 +13,8 @@ if (filled($mask)) { $type = 'text'; + } else { + $type = $getType(); } @endphp From cf5083905760c9754f0f3732c3c5281656a0eb9e Mon Sep 17 00:00:00 2001 From: shepard153 Date: Tue, 13 Feb 2024 09:19:45 +0100 Subject: [PATCH 20/87] Add `columnMapping()` method --- .../docs/07-prebuilt-actions/09-export.md | 4 +- .../actions/src/Concerns/CanExportRecords.php | 86 ++++++++++++------- 2 files changed, 55 insertions(+), 35 deletions(-) diff --git a/packages/actions/docs/07-prebuilt-actions/09-export.md b/packages/actions/docs/07-prebuilt-actions/09-export.md index 965ee64cec..3d91bded86 100644 --- a/packages/actions/docs/07-prebuilt-actions/09-export.md +++ b/packages/actions/docs/07-prebuilt-actions/09-export.md @@ -126,7 +126,7 @@ ExportColumn::make('description') ### Disabling column selection -By default, user will be asked which columns they would like to export. You can disable this functionality by passing `null` to `form()` method: +By default, user will be asked which columns they would like to export. You can disable this functionality with the `columnMapping()` method: ```php use App\Filament\Exports\ProductExporter; @@ -134,7 +134,7 @@ use Filament\Actions\ExportAction; ExportAction::make() ->exporter(ProductExporter::class) - ->form(null) + ->columnMapping(false) ``` ### Calculated export column state diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index b04df5fa10..d2f3e1d6d9 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -61,6 +61,8 @@ trait CanExportRecords protected ?Closure $modifyQueryUsing = null; + protected bool $hasColumnMapping = true; + protected function setUp(): void { parent::setUp(); @@ -73,34 +75,40 @@ trait CanExportRecords $this->groupedIcon(FilamentIcon::resolve('actions::export-action.grouped') ?? 'heroicon-m-arrow-down-tray'); - $this->form(fn (ExportAction | ExportTableAction | ExportTableBulkAction $action): array => array_merge([ - Fieldset::make(__('filament-actions::export.modal.form.columns.label')) - ->columns(1) - ->inlineLabel() - ->schema(function () use ($action): array { - return array_map( - fn (ExportColumn $column): Split => Split::make([ - Forms\Components\Checkbox::make('isEnabled') - ->label(__('filament-actions::export.modal.form.columns.form.is_enabled.label', ['column' => $column->getName()])) - ->hiddenLabel() - ->default($column->isEnabledByDefault()) - ->live() - ->grow(false), - Forms\Components\TextInput::make('label') - ->label(__('filament-actions::export.modal.form.columns.form.label.label', ['column' => $column->getName()])) - ->hiddenLabel() - ->default($column->getLabel()) - ->placeholder($column->getLabel()) - ->disabled(fn (Forms\Get $get): bool => ! $get('isEnabled')) - ->required(fn (Forms\Get $get): bool => (bool) $get('isEnabled')), - ]) - ->verticallyAlignCenter() - ->statePath($column->getName()), - $action->getExporter()::getColumns(), - ); - }) - ->statePath('columnMap'), - ], $action->getExporter()::getOptionsFormComponents())); + $this->form(function (ExportAction | ExportTableAction | ExportTableBulkAction $action): array { + if ($action->hasColumnMapping()) { + return array_merge([ + Fieldset::make(__('filament-actions::export.modal.form.columns.label')) + ->columns(1) + ->inlineLabel() + ->schema(function () use ($action): array { + return array_map( + fn (ExportColumn $column): Split => Split::make([ + Forms\Components\Checkbox::make('isEnabled') + ->label(__('filament-actions::export.modal.form.columns.form.is_enabled.label', ['column' => $column->getName()])) + ->hiddenLabel() + ->default($column->isEnabledByDefault()) + ->live() + ->grow(false), + Forms\Components\TextInput::make('label') + ->label(__('filament-actions::export.modal.form.columns.form.label.label', ['column' => $column->getName()])) + ->hiddenLabel() + ->default($column->getLabel()) + ->placeholder($column->getLabel()) + ->disabled(fn (Forms\Get $get): bool => ! $get('isEnabled')) + ->required(fn (Forms\Get $get): bool => (bool) $get('isEnabled')), + ]) + ->verticallyAlignCenter() + ->statePath($column->getName()), + $action->getExporter()::getColumns(), + ); + }) + ->statePath('columnMap'), + ], $action->getExporter()::getOptionsFormComponents()); + } else { + return $action->getExporter()::getOptionsFormComponents(); + } + }); $this->action(function (ExportAction | ExportTableAction | ExportTableBulkAction $action, array $data, Component $livewire) { if ($livewire instanceof HasTable) { @@ -139,11 +147,7 @@ trait CanExportRecords Arr::except($data, ['columnMap']), ); - if (! $this->form) { - $columnMap = collect($action->getExporter()::getColumns()) - ->mapWithKeys(fn(ExportColumn $column): array => [$column->getName() => $column->getLabel()] - )->all(); - } else { + if ($action->hasColumnMapping()) { $columnMap = collect($data['columnMap']) ->dot() ->reduce(fn(Collection $carry, mixed $value, string $key): Collection => $carry->mergeRecursive([ @@ -152,6 +156,10 @@ trait CanExportRecords ->filter(fn(array $column): bool => $column['isEnabled'] ?? false) ->mapWithKeys(fn(array $column, string $columnName): array => [$columnName => $column['label']]) ->all(); + } else { + $columnMap = collect($action->getExporter()::getColumns()) + ->mapWithKeys(fn(ExportColumn $column): array => [$column->getName() => $column->getLabel()]) + ->all(); } $export = app(Export::class); @@ -393,4 +401,16 @@ trait CanExportRecords return $this; } + + public function columnMapping(bool $columnMapping): static + { + $this->hasColumnMapping = $columnMapping; + + return $this; + } + + public function hasColumnMapping(): bool + { + return $this->evaluate($this->hasColumnMapping); + } } From e44e4dd4c1f7fed7fe9b005551af8840206f07f1 Mon Sep 17 00:00:00 2001 From: Zep Fietje Date: Tue, 13 Feb 2024 09:49:49 +0100 Subject: [PATCH 21/87] Format comment --- .../panels/resources/views/components/layout/index.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/panels/resources/views/components/layout/index.blade.php b/packages/panels/resources/views/components/layout/index.blade.php index c496b7cb39..cbac266630 100644 --- a/packages/panels/resources/views/components/layout/index.blade.php +++ b/packages/panels/resources/views/components/layout/index.blade.php @@ -5,7 +5,7 @@ @endphp - {{-- The sidebar is after the page content in the markup to fix issues with page content overlapping dropdown content from the sidebar --}} + {{-- The sidebar is after the page content in the markup to fix issues with page content overlapping dropdown content from the sidebar. --}}
        From e806b25b5dbd48490058556a6fcb9dbd70173e2c Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Tue, 13 Feb 2024 11:55:07 +0000 Subject: [PATCH 22/87] Update group.blade.php --- .../resources/views/components/sidebar/group.blade.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/panels/resources/views/components/sidebar/group.blade.php b/packages/panels/resources/views/components/sidebar/group.blade.php index 7e45099444..ba5114e8df 100644 --- a/packages/panels/resources/views/components/sidebar/group.blade.php +++ b/packages/panels/resources/views/components/sidebar/group.blade.php @@ -65,6 +65,7 @@ @if ($hasDropdown) @@ -169,6 +170,10 @@ class="fi-sidebar-group-items flex flex-col gap-y-1" > @foreach ($items as $item) + @php + $itemIcon = $item->getIcon(); + @endphp + Date: Wed, 14 Feb 2024 01:09:33 +0000 Subject: [PATCH 23/87] translated export to romanian --- packages/actions/resources/lang/ro/export.php | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 packages/actions/resources/lang/ro/export.php diff --git a/packages/actions/resources/lang/ro/export.php b/packages/actions/resources/lang/ro/export.php new file mode 100644 index 0000000000..6f8eb2dd84 --- /dev/null +++ b/packages/actions/resources/lang/ro/export.php @@ -0,0 +1,77 @@ + 'Exportă :label', + + 'modal' => [ + + 'heading' => 'Exportă :label', + + 'form' => [ + + 'columns' => [ + + 'label' => 'Coloane', + + 'form' => [ + + 'is_enabled' => [ + 'label' => ':column activat', + ], + + 'label' => [ + 'label' => 'Eticheta :column', + ], + + ], + + ], + + ], + + 'actions' => [ + + 'export' => [ + 'label' => 'Exportă', + ], + + ], + + ], + + 'notifications' => [ + + 'completed' => [ + + 'title' => 'Export complet', + + 'actions' => [ + + 'download_csv' => [ + 'label' => 'Descarcă .csv', + ], + + 'download_xlsx' => [ + 'label' => 'Descarcă .xlsx', + ], + + ], + + ], + + 'max_rows' => [ + 'title' => 'Exportul este prea mare', + 'body' => 'Nu puteți exporta mai mult de 1 rând odată.|Nu puteți exporta mai mult de :count rânduri odată', + ], + + 'started' => [ + 'title' => 'Exportul a început', + 'body' => 'Exportul dvs. a început și 1 rând va fi procesat în fundal.|Exportul dvs. a început și :count rânduri vor fi procesate în fundal.', + ], + + ], + + 'file_name' => 'export-:export_id-:model', + +]; \ No newline at end of file From d9a34b36d4102625b0a91a9c2f9bff459dc6fc4d Mon Sep 17 00:00:00 2001 From: Zep Fietje Date: Wed, 14 Feb 2024 08:45:52 +0100 Subject: [PATCH 24/87] Fix code style --- packages/actions/resources/lang/ro/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/actions/resources/lang/ro/export.php b/packages/actions/resources/lang/ro/export.php index 6f8eb2dd84..e1394adc0d 100644 --- a/packages/actions/resources/lang/ro/export.php +++ b/packages/actions/resources/lang/ro/export.php @@ -74,4 +74,4 @@ return [ 'file_name' => 'export-:export_id-:model', -]; \ No newline at end of file +]; From 793a5bd954076df726ed57432165f75c74f4b9db Mon Sep 17 00:00:00 2001 From: Zep Fietje Date: Wed, 14 Feb 2024 09:09:07 +0100 Subject: [PATCH 25/87] Vertically center modal heading when it makes sense --- .../views/components/modal/index.blade.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/support/resources/views/components/modal/index.blade.php b/packages/support/resources/views/components/modal/index.blade.php index d5cb67d0cc..9576926aea 100644 --- a/packages/support/resources/views/components/modal/index.blade.php +++ b/packages/support/resources/views/components/modal/index.blade.php @@ -30,6 +30,10 @@ ]) @php + $hasDescription = filled($description); + $hasHeading = filled($heading); + $hasIcon = filled($icon); + if (! $alignment instanceof Alignment) { $alignment = filled($alignment) ? (Alignment::tryFrom($alignment) ?? $alignment) : null; } @@ -207,6 +211,7 @@ Alignment::Center => 'flex-col', default => null, }, + 'items-center' => $hasIcon && $hasHeading && (! $hasDescription) && in_array($alignment, [Alignment::Start, Alignment::Left]), ]) > @if ($closeButton) @@ -233,7 +238,7 @@ @if ($header) {{ $header }} @else - @if ($icon) + @if ($hasIcon)
        $alignment === Alignment::Center, @@ -284,7 +289,7 @@ {{ $heading }} - @if (filled($description)) + @if ($hasDescription) @@ -301,8 +306,8 @@ @class([ 'fi-modal-content flex flex-col gap-y-4 py-6', 'flex-1' => ($width === MaxWidth::Screen) || $slideOver, - 'pe-6 ps-[5.25rem]' => $icon && ($alignment === Alignment::Start), - 'px-6' => ! ($icon && ($alignment === Alignment::Start)), + 'pe-6 ps-[5.25rem]' => $hasIcon && ($alignment === Alignment::Start), + 'px-6' => ! ($hasIcon && ($alignment === Alignment::Start)), ]) > {{ $slot }} @@ -313,8 +318,8 @@
        $icon && ($alignment === Alignment::Start) && ($footerActionsAlignment !== Alignment::Center) && (! $stickyFooter), - 'px-6' => ! ($icon && ($alignment === Alignment::Start) && ($footerActionsAlignment !== Alignment::Center) && (! $stickyFooter)), + 'pe-6 ps-[5.25rem]' => $hasIcon && ($alignment === Alignment::Start) && ($footerActionsAlignment !== Alignment::Center) && (! $stickyFooter), + 'px-6' => ! ($hasIcon && ($alignment === Alignment::Start) && ($footerActionsAlignment !== Alignment::Center) && (! $stickyFooter)), 'fi-sticky sticky bottom-0 border-t border-gray-200 bg-white py-5 dark:border-white/10 dark:bg-gray-900' => $stickyFooter, 'rounded-b-xl' => $stickyFooter && ! ($slideOver || ($width === MaxWidth::Screen)), 'pb-6' => ! $stickyFooter, From 61393f1784a97aa6d07f10d77fbab003fc23236b Mon Sep 17 00:00:00 2001 From: Vitalie Jalbu <40239902+vitalijalbu@users.noreply.github.com> Date: Wed, 14 Feb 2024 09:37:59 +0100 Subject: [PATCH 26/87] Update edit-profile.php --- packages/panels/resources/lang/it/pages/auth/edit-profile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/panels/resources/lang/it/pages/auth/edit-profile.php b/packages/panels/resources/lang/it/pages/auth/edit-profile.php index a7183fc1aa..484cf68a4b 100644 --- a/packages/panels/resources/lang/it/pages/auth/edit-profile.php +++ b/packages/panels/resources/lang/it/pages/auth/edit-profile.php @@ -43,7 +43,7 @@ return [ 'actions' => [ 'cancel' => [ - 'label' => 'indietro', + 'label' => 'Indietro', ], ], From 5369589c1967b6c19f87e53f09a1b290a9d510b2 Mon Sep 17 00:00:00 2001 From: Jeremias Wolff Date: Wed, 14 Feb 2024 14:51:38 +0100 Subject: [PATCH 27/87] use framework to check if slot is empty --- packages/support/src/helpers.php | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/support/src/helpers.php b/packages/support/src/helpers.php index 62ecdf5f03..988cb2c2c7 100644 --- a/packages/support/src/helpers.php +++ b/packages/support/src/helpers.php @@ -118,18 +118,7 @@ if (! function_exists('Filament\Support\is_slot_empty')) { return true; } - return trim( - str_replace( - [ - '', - '', - '', - '', - ], - '', - $slot->toHtml() - ), - ) === ''; + return $slot->hasActualContent(); } } From 6a3b09435d0453cfdb6e440178726dd40d6973ce Mon Sep 17 00:00:00 2001 From: Arne Becker Date: Thu, 15 Feb 2024 11:25:32 +0100 Subject: [PATCH 28/87] Fix typo in modal sticky header docs --- packages/actions/docs/04-modals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/actions/docs/04-modals.md b/packages/actions/docs/04-modals.md index 2161d957f3..8806d01708 100644 --- a/packages/actions/docs/04-modals.md +++ b/packages/actions/docs/04-modals.md @@ -293,7 +293,7 @@ Instead of opening in the center of the screen, the modal content will now slide ## Making the modal header sticky -The header of a modal scrolls out of view with the modal content when it overflows the modal size. However, slide-overs have a sticky modal that's always visible. You may control this behavior using `stickyModalHeader()`: +The header of a modal scrolls out of view with the modal content when it overflows the modal size. However, slide-overs have a sticky header that's always visible. You may control this behavior using `stickyModalHeader()`: ```php Action::make('updateAuthor') From cdf8e5ad554ea0177c129e64e6144cb67c0060f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugen=20-=20Lucian=20Pa=C8=99ca?= Date: Thu, 15 Feb 2024 13:30:43 +0000 Subject: [PATCH 29/87] Translated missing fields to Romanian --- packages/actions/resources/lang/ro/import.php | 77 +++++++++++++++++++ .../resources/lang/ro/pages/dashboard.php | 27 +++++++ .../lang/ro/components/pagination.php | 8 ++ packages/tables/resources/lang/ro/table.php | 8 ++ 4 files changed, 120 insertions(+) create mode 100644 packages/actions/resources/lang/ro/import.php diff --git a/packages/actions/resources/lang/ro/import.php b/packages/actions/resources/lang/ro/import.php new file mode 100644 index 0000000000..5e332656d9 --- /dev/null +++ b/packages/actions/resources/lang/ro/import.php @@ -0,0 +1,77 @@ + 'Importă :label', + + 'modal' => [ + + 'heading' => 'Importă :label', + + 'form' => [ + + 'file' => [ + 'label' => 'Fișier', + 'placeholder' => 'Încarcă un fișier CSV', + ], + + 'columns' => [ + 'label' => 'Coloane', + 'placeholder' => 'Alege Coloanele', + ], + + ], + + 'actions' => [ + + 'download_example' => [ + 'label' => 'Descarcă exemplu în format CSV', + ], + + 'import' => [ + 'label' => 'Importă', + ], + + ], + + ], + + 'notifications' => [ + + 'completed' => [ + + 'title' => 'Import finalizat', + + 'actions' => [ + + 'download_failed_rows_csv' => [ + 'label' => 'Descarcă informațiiler despre câmpul ce a avut eroaro|Descarcă informații despre câmpurile ce au auvt erori', + ], + + ], + + ], + + 'max_rows' => [ + 'title' => 'Fișierul CSV file este prea mare', + 'body' => 'Nu este permis importul a mai mult de o linile într-un singur fișier.|Nu este permis imporutl a mai mult de :count linii într-un singur fișier.', + ], + + 'started' => [ + 'title' => 'Importul a început', + 'body' => 'Importul dumneavostră a început, iar rândul va fi procesa în fundal.|Importul dumneavoastră a început, iar cele :count rânduri vor fi procesate în fundal.', + ], + + ], + + 'example_csv' => [ + 'file_name' => ':importer-example', + ], + + 'failure_csv' => [ + 'file_name' => 'import-:import_id-:csv_name-câmpuri-gresite', + 'error_header' => 'error', + 'system_error' => 'Eroare de sistem, vă rugăm contactați echipa de suport.', + ], + +]; diff --git a/packages/panels/resources/lang/ro/pages/dashboard.php b/packages/panels/resources/lang/ro/pages/dashboard.php index 9f4c224464..2534e8777b 100644 --- a/packages/panels/resources/lang/ro/pages/dashboard.php +++ b/packages/panels/resources/lang/ro/pages/dashboard.php @@ -4,4 +4,31 @@ return [ 'title' => 'Panoul de control', + 'actions' => [ + + 'filter' => [ + + 'label' => 'Filtru', + + 'modal' => [ + + 'heading' => 'Filtru', + + 'actions' => [ + + 'apply' => [ + + 'label' => 'Aplică', + + ], + + ], + + ], + + ], + + ], + + ]; diff --git a/packages/support/resources/lang/ro/components/pagination.php b/packages/support/resources/lang/ro/components/pagination.php index 2ae858e932..090b9be011 100644 --- a/packages/support/resources/lang/ro/components/pagination.php +++ b/packages/support/resources/lang/ro/components/pagination.php @@ -22,10 +22,18 @@ return [ 'actions' => [ + 'first' => [ + 'label' => 'Prima pagină', + ], + 'go_to_page' => [ 'label' => 'Mergi la pagina :page', ], + 'last' => [ + 'label' => 'Ultima pagină', + ], + 'next' => [ 'label' => 'Pagina următoare', ], diff --git a/packages/tables/resources/lang/ro/table.php b/packages/tables/resources/lang/ro/table.php index 46d4935399..9f3e417ba8 100644 --- a/packages/tables/resources/lang/ro/table.php +++ b/packages/tables/resources/lang/ro/table.php @@ -26,6 +26,10 @@ return [ 'label' => 'Selectează/Deselectează elementul :key pentru operațiuni in masă.', ], + 'bulk_select_group' => [ + 'label' => 'Selectează/Deselectează grupul :title pentru operațiuni in masă.', + ], + 'search' => [ 'label' => 'Căutare', 'placeholder' => 'Căutare', @@ -102,6 +106,10 @@ return [ 'actions' => [ + 'apply' => [ + 'label' => 'Aplică filtrele', + ], + 'remove' => [ 'label' => 'Elimină filtru', ], From 3ed6f30f73032e89846b8cf43dc0d04439a53368 Mon Sep 17 00:00:00 2001 From: Saade Date: Thu, 15 Feb 2024 17:11:38 -0300 Subject: [PATCH 30/87] feat: selects and checkbox lists have pivot attributes --- .../forms/src/Components/CheckboxList.php | 3 ++- .../Concerns/HasPivotAttributes.php | 22 +++++++++++++++++++ packages/forms/src/Components/Select.php | 7 +++--- 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 packages/forms/src/Components/Concerns/HasPivotAttributes.php diff --git a/packages/forms/src/Components/CheckboxList.php b/packages/forms/src/Components/CheckboxList.php index 28db14e1dc..deda4ff8a7 100644 --- a/packages/forms/src/Components/CheckboxList.php +++ b/packages/forms/src/Components/CheckboxList.php @@ -24,6 +24,7 @@ class CheckboxList extends Field implements Contracts\CanDisableOptions, Contrac use Concerns\HasGridDirection; use Concerns\HasNestedRecursiveValidationRules; use Concerns\HasOptions; + use Concerns\HasPivotAttributes; /** * @var view-string @@ -185,7 +186,7 @@ class CheckboxList extends Field implements Contracts\CanDisableOptions, Contrac }); $this->saveRelationshipsUsing(static function (CheckboxList $component, ?array $state) { - $component->getRelationship()->sync($state ?? []); + $component->getRelationship()->syncWithPivotValues($state ?? [], $component->getPivotAttributes()); }); $this->dehydrated(false); diff --git a/packages/forms/src/Components/Concerns/HasPivotAttributes.php b/packages/forms/src/Components/Concerns/HasPivotAttributes.php new file mode 100644 index 0000000000..990fc640df --- /dev/null +++ b/packages/forms/src/Components/Concerns/HasPivotAttributes.php @@ -0,0 +1,22 @@ +pivotAttributes = $attributes; + + return $this; + } + + public function getPivotAttributes(): ?array + { + return $this->evaluate($this->pivotAttributes) ?? []; + } +} diff --git a/packages/forms/src/Components/Select.php b/packages/forms/src/Components/Select.php index d196f28e7a..7f17b2a62e 100644 --- a/packages/forms/src/Components/Select.php +++ b/packages/forms/src/Components/Select.php @@ -46,6 +46,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has use Concerns\HasLoadingMessage; use Concerns\HasNestedRecursiveValidationRules; use Concerns\HasOptions; + use Concerns\HasPivotAttributes; use Concerns\HasPlaceholder; use HasExtraAlpineAttributes; @@ -196,7 +197,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has ]); } - public function boolean(?string $trueLabel = null, ?string $falseLabel = null, ?string $placeholder = null): static + public function boolean(string $trueLabel = null, string $falseLabel = null, string $placeholder = null): static { $this->options([ 1 => $trueLabel ?? __('filament-forms::components.select.boolean.true'), @@ -691,7 +692,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has return $this->evaluate($this->isSearchable) || $this->isMultiple(); } - public function relationship(string | Closure | null $name = null, string | Closure | null $titleAttribute = null, ?Closure $modifyQueryUsing = null, bool $ignoreRecord = false): static + public function relationship(string | Closure $name = null, string | Closure $titleAttribute = null, Closure $modifyQueryUsing = null, bool $ignoreRecord = false): static { $this->relationship = $name ?? $this->getName(); $this->relationshipTitleAttribute = $titleAttribute; @@ -963,7 +964,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has return; } - $relationship->sync($state ?? []); + $relationship->syncWithPivotValues($state ?? [], $component->getPivotAttributes()); }); $this->createOptionUsing(static function (Select $component, array $data, Form $form) { From 1a460bed4a56b6165bf420f846acb76b79a9d03e Mon Sep 17 00:00:00 2001 From: Saade Date: Thu, 15 Feb 2024 17:16:26 -0300 Subject: [PATCH 31/87] docs --- packages/forms/docs/03-fields/03-select.md | 13 +++++++++++++ packages/forms/docs/03-fields/06-checkbox-list.md | 12 ++++++++++++ 2 files changed, 25 insertions(+) diff --git a/packages/forms/docs/03-fields/03-select.md b/packages/forms/docs/03-fields/03-select.md index f64aa14eec..4bef10b888 100644 --- a/packages/forms/docs/03-fields/03-select.md +++ b/packages/forms/docs/03-fields/03-select.md @@ -179,6 +179,19 @@ Select::make('technologies') ->relationship(titleAttribute: 'name') ``` +If you're using a `BelongsToMany` relationship and your pivot table has additional columns, you can use the `pivotAttributes()` method to specify the pivot attributes that should be saved: + +```php +use Filament\Forms\Components\Select; + +Select::make('technologies') + ->relationship(titleAttribute: 'name') + ->pivotAttributes([ + 'is_primary' => true, + ]) +``` + + ### Searching relationship options across multiple columns By default, if the select is also searchable, Filament will return search results for the relationship based on the title column of the relationship. If you'd like to search across multiple columns, you can pass an array of columns to the `searchable()` method: diff --git a/packages/forms/docs/03-fields/06-checkbox-list.md b/packages/forms/docs/03-fields/06-checkbox-list.md index 0969434b9a..e21e827204 100644 --- a/packages/forms/docs/03-fields/06-checkbox-list.md +++ b/packages/forms/docs/03-fields/06-checkbox-list.md @@ -196,6 +196,18 @@ CheckboxList::make('technologies') ->relationship(titleAttribute: 'name') ``` +If you're using a `BelongsToMany` relationship and your pivot table has additional columns, you can use the `pivotAttributes()` method to specify the pivot attributes that should be saved: + +```php +use Filament\Forms\Components\Select; + +CheckboxList::make('technologies') + ->relationship(titleAttribute: 'name') + ->pivotAttributes([ + 'is_primary' => true, + ]) +``` + ### Customizing the relationship query You may customize the database query that retrieves options using the `modifyOptionsQueryUsing` parameter of the `relationship()` method: From 68278681e6e9db226112aaa52805568084f971d1 Mon Sep 17 00:00:00 2001 From: saade Date: Thu, 15 Feb 2024 20:22:47 +0000 Subject: [PATCH 32/87] chore: fix code style --- packages/forms/src/Components/Select.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/forms/src/Components/Select.php b/packages/forms/src/Components/Select.php index 7f17b2a62e..193be941d0 100644 --- a/packages/forms/src/Components/Select.php +++ b/packages/forms/src/Components/Select.php @@ -197,7 +197,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has ]); } - public function boolean(string $trueLabel = null, string $falseLabel = null, string $placeholder = null): static + public function boolean(?string $trueLabel = null, ?string $falseLabel = null, ?string $placeholder = null): static { $this->options([ 1 => $trueLabel ?? __('filament-forms::components.select.boolean.true'), @@ -692,7 +692,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has return $this->evaluate($this->isSearchable) || $this->isMultiple(); } - public function relationship(string | Closure $name = null, string | Closure $titleAttribute = null, Closure $modifyQueryUsing = null, bool $ignoreRecord = false): static + public function relationship(string | Closure | null $name = null, string | Closure | null $titleAttribute = null, ?Closure $modifyQueryUsing = null, bool $ignoreRecord = false): static { $this->relationship = $name ?? $this->getName(); $this->relationshipTitleAttribute = $titleAttribute; From c9e41fd67851afb196b37567e3cef9d235de96d5 Mon Sep 17 00:00:00 2001 From: Saade Date: Thu, 15 Feb 2024 17:26:46 -0300 Subject: [PATCH 33/87] fix phpstan errors --- .../Components/Concerns/HasPivotAttributes.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/forms/src/Components/Concerns/HasPivotAttributes.php b/packages/forms/src/Components/Concerns/HasPivotAttributes.php index 990fc640df..bba59853c2 100644 --- a/packages/forms/src/Components/Concerns/HasPivotAttributes.php +++ b/packages/forms/src/Components/Concerns/HasPivotAttributes.php @@ -6,17 +6,26 @@ use Closure; trait HasPivotAttributes { - protected array | Closure | null $pivotAttributes = null; + /** + * @var array | Closure> + */ + protected array | Closure $pivotAttributes = []; - public function pivotAttributes(array | Closure | null $attributes): static + /** + * @param array | Closure $attributes + */ + public function pivotAttributes(array | Closure $attributes): static { $this->pivotAttributes = $attributes; return $this; } + /** + * @return array + */ public function getPivotAttributes(): ?array { - return $this->evaluate($this->pivotAttributes) ?? []; + return $this->evaluate($this->pivotAttributes); } } From 4848fb63cb081483742568c35a85c60ac360f712 Mon Sep 17 00:00:00 2001 From: Ehsan Mahmoodi Date: Fri, 16 Feb 2024 00:02:43 +0330 Subject: [PATCH 34/87] Fixed: Addressed $loop->iteration placement outside loops and corrected minor structural issues. When using limitedRemainingText and no remaining image is present, we currently display +0, which is not ideal. Instead, if the number of images exceeds the set limit, for example, if we have 5 images and the limit is set to 3, we should display +2. Additionally, to address a performance issue, we are currently using count($limitedState) in 6 instances and count($state) in 2 instances. To avoid duplication, I have created separate variables. Note: We have $loop->iteration in 2 lines of code, but these lines are not within a loop. Additionally, there is a minor structural problem which has been corrected as expected. --- .../views/columns/image-column.blade.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/tables/resources/views/columns/image-column.blade.php b/packages/tables/resources/views/columns/image-column.blade.php index ad4ea2b10f..3c1df7c846 100644 --- a/packages/tables/resources/views/columns/image-column.blade.php +++ b/packages/tables/resources/views/columns/image-column.blade.php @@ -10,10 +10,15 @@ $height = $getHeight() ?? ($isStacked ? '2rem' : '2.5rem'); $width = $getWidth() ?? (($isCircular || $isSquare) ? $height : null); + $countState = count($state); + $countLimitedState = count($limitedState); + $defaultImageUrl = $getDefaultImageUrl(); - if ((! count($limitedState)) && filled($defaultImageUrl)) { + if ((! $countLimitedState) && filled($defaultImageUrl)) { $limitedState = [null]; + + $countLimitedState = 1; } $ringClasses = \Illuminate\Support\Arr::toCssClasses([ @@ -50,7 +55,7 @@ ]) }} > - @if (count($limitedState)) + @if ($countLimitedState)
        @endforeach - @if ($hasLimitedRemainingText && ($loop->iteration < count($limitedState)) && (! $isLimitedRemainingTextSeparate) && $isCircular) + @if ($hasLimitedRemainingText && ($countLimitedState < $countState) && (! $isLimitedRemainingTextSeparate) && $isCircular)
        - +{{ count($state) - count($limitedState) }} + +{{ $countState - $countLimitedState }}
        @endif
        - @if ($hasLimitedRemainingText && ($loop->iteration < count($limitedState)) && ($isLimitedRemainingTextSeparate || (! $isCircular))) + @if ($hasLimitedRemainingText && ($countLimitedState < $countState) && ($isLimitedRemainingTextSeparate || (! $isCircular)))
        - +{{ count($state) - count($limitedState) }} + +{{ $countState - $countLimitedState }}
        @endif
        From 936ce34599e40030683b4266a68ead917bb3cd32 Mon Sep 17 00:00:00 2001 From: ahinkle Date: Thu, 15 Feb 2024 21:56:00 -0600 Subject: [PATCH 35/87] ability to add Helper Text to Import Column --- packages/actions/src/Imports/ImportColumn.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/actions/src/Imports/ImportColumn.php b/packages/actions/src/Imports/ImportColumn.php index bc8d9418c1..175f4491c0 100644 --- a/packages/actions/src/Imports/ImportColumn.php +++ b/packages/actions/src/Imports/ImportColumn.php @@ -3,6 +3,7 @@ namespace Filament\Actions\Imports; use Closure; +use Filament\Forms\Components\Concerns\HasHelperText; use Filament\Forms\Components\Select; use Filament\Support\Components\Component; use Illuminate\Database\Eloquent\Model; @@ -13,6 +14,8 @@ use Illuminate\Support\Str; class ImportColumn extends Component { + use HasHelperText; + protected string $name; protected string | Closure | null $label = null; @@ -88,7 +91,8 @@ class ImportColumn extends Component return Select::make($this->getName()) ->label($this->getLabel()) ->placeholder(__('filament-actions::import.modal.form.columns.placeholder')) - ->required($this->isMappingRequired()); + ->required($this->isMappingRequired()) + ->helperText($this->getHelperText()); } public function name(string $name): static From 9600471fc4f915a2cf6dc724103fc589f1169516 Mon Sep 17 00:00:00 2001 From: ahinkle Date: Thu, 15 Feb 2024 22:03:54 -0600 Subject: [PATCH 36/87] Add docs for helper text on import column --- .../actions/docs/07-prebuilt-actions/08-import.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/actions/docs/07-prebuilt-actions/08-import.md b/packages/actions/docs/07-prebuilt-actions/08-import.md index 0486e60069..e0ca79f8b7 100644 --- a/packages/actions/docs/07-prebuilt-actions/08-import.md +++ b/packages/actions/docs/07-prebuilt-actions/08-import.md @@ -104,6 +104,19 @@ ImportColumn::make('sku') ->label('SKU') ``` +## Adding helper text below the import column + +Sometimes, you may wish to provide extra information for the import column before validation. + +The `helperText()` method is used to add helper text: + +```php +use Filament\Forms\Components\TextInput; + +ImportColumn::make('skus') + ->helperText('A comma-separated list of SKUs.') +``` + ### Requiring an importer column to be mapped to a CSV column You can call the `requiredMapping()` method to make a column required to be mapped to a column in the CSV. Columns that are required in the database should be required to be mapped: From e8641a905744e79f5041cd16c37c7672373edb51 Mon Sep 17 00:00:00 2001 From: Mischa Sigtermans Date: Fri, 16 Feb 2024 12:59:11 +0100 Subject: [PATCH 37/87] Add iconColor option for dropdown list item --- .../views/components/dropdown/list/item.blade.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/support/resources/views/components/dropdown/list/item.blade.php b/packages/support/resources/views/components/dropdown/list/item.blade.php index e486278d59..bdc12946fc 100644 --- a/packages/support/resources/views/components/dropdown/list/item.blade.php +++ b/packages/support/resources/views/components/dropdown/list/item.blade.php @@ -11,6 +11,7 @@ 'href' => null, 'icon' => null, 'iconAlias' => null, + 'iconColor' => null, 'iconSize' => IconSize::Medium, 'image' => null, 'keyBindings' => null, @@ -43,7 +44,7 @@ alias: 'dropdown.list.item', ) => $color !== 'gray', ]); - + $iconClasses = \Illuminate\Support\Arr::toCssClasses([ 'fi-dropdown-list-item-icon', match ($iconSize) { @@ -52,7 +53,7 @@ IconSize::Large, 'lg' => 'h-6 w-6', default => $iconSize, }, - match ($color) { + match ($iconColor ?? $color) { 'gray' => 'text-gray-400 dark:text-gray-500', default => 'text-custom-500 dark:text-custom-400', }, @@ -60,10 +61,10 @@ $iconStyles = \Illuminate\Support\Arr::toCssStyles([ \Filament\Support\get_color_css_variables( - $color, + $iconColor ?? $color, shades: [400, 500], alias: 'dropdown.list.item.icon', - ) => $color !== 'gray', + ) => ($iconColor ?? $color) !== 'gray', ]); $imageClasses = 'fi-dropdown-list-item-image h-5 w-5 rounded-full bg-cover bg-center'; From fb5f3f777b333c6a20ead47a395fcaab9f683e44 Mon Sep 17 00:00:00 2001 From: Ahmed Naseef Date: Fri, 16 Feb 2024 16:11:05 +0400 Subject: [PATCH 38/87] modifiable select alias for Average, Count and Sum Summerizers --- packages/tables/src/Columns/Summarizers/Average.php | 6 ++++++ packages/tables/src/Columns/Summarizers/Count.php | 6 ++++++ packages/tables/src/Columns/Summarizers/Sum.php | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/packages/tables/src/Columns/Summarizers/Average.php b/packages/tables/src/Columns/Summarizers/Average.php index 9c27ad43ee..c84c60872f 100644 --- a/packages/tables/src/Columns/Summarizers/Average.php +++ b/packages/tables/src/Columns/Summarizers/Average.php @@ -40,6 +40,12 @@ class Average extends Summarizer return $this->selectedState[$this->getSelectAlias()]; } + public function selectAlias(string $alias): static + { + $this->selectAlias = $alias; + return $this; + } + public function getSelectAlias(): string { return $this->selectAlias ??= Str::random(); diff --git a/packages/tables/src/Columns/Summarizers/Count.php b/packages/tables/src/Columns/Summarizers/Count.php index 81d6445cca..d6640f48e9 100644 --- a/packages/tables/src/Columns/Summarizers/Count.php +++ b/packages/tables/src/Columns/Summarizers/Count.php @@ -75,6 +75,12 @@ class Count extends Summarizer return $this->selectedState[$this->getSelectAlias()]; } + public function selectAlias(string $alias): static + { + $this->selectAlias = $alias; + return $this; + } + public function getSelectAlias(): string { return $this->selectAlias ??= Str::random(); diff --git a/packages/tables/src/Columns/Summarizers/Sum.php b/packages/tables/src/Columns/Summarizers/Sum.php index fb278c79bb..16569af230 100644 --- a/packages/tables/src/Columns/Summarizers/Sum.php +++ b/packages/tables/src/Columns/Summarizers/Sum.php @@ -40,6 +40,12 @@ class Sum extends Summarizer return $this->selectedState[$this->getSelectAlias()]; } + public function selectAlias(string $alias): static + { + $this->selectAlias = $alias; + return $this; + } + public function getSelectAlias(): string { return $this->selectAlias ??= Str::random(); From 546d46ce56be28547774cf5a0818284adedeed03 Mon Sep 17 00:00:00 2001 From: Mischa Sigtermans Date: Fri, 16 Feb 2024 13:19:44 +0100 Subject: [PATCH 39/87] Update Dropdown Blade component docs --- .../docs/09-blade-components/02-dropdown.md | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/support/docs/09-blade-components/02-dropdown.md b/packages/support/docs/09-blade-components/02-dropdown.md index a2eb33a4a6..ae3ade4017 100644 --- a/packages/support/docs/09-blade-components/02-dropdown.md +++ b/packages/support/docs/09-blade-components/02-dropdown.md @@ -69,6 +69,32 @@ By default, the color of a dropdown item is "gray". You can change it to be `dan ``` +## Changing the icon color of a dropdown item + +By default, the icon color of a dropdown item is "gray". You can change it to be `danger`, `info`, `primary`, `success` or `warning` by using the `iconColor` attribute: + +```blade + + Edit + + + + Edit + + + + Edit + + + + Edit + + + + Edit + +``` + ## Adding an icon to a dropdown item You can add an [icon](https://blade-ui-kit.com/blade-icons?set=1#search) to a dropdown item by using the `icon` attribute: From eb0f12679900c17a1cc276b41d843f5d08411f0d Mon Sep 17 00:00:00 2001 From: Mischa Sigtermans Date: Sat, 17 Feb 2024 14:07:48 +0100 Subject: [PATCH 40/87] cs --- .../resources/views/components/dropdown/list/item.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/support/resources/views/components/dropdown/list/item.blade.php b/packages/support/resources/views/components/dropdown/list/item.blade.php index bdc12946fc..fe51d947f8 100644 --- a/packages/support/resources/views/components/dropdown/list/item.blade.php +++ b/packages/support/resources/views/components/dropdown/list/item.blade.php @@ -44,7 +44,7 @@ alias: 'dropdown.list.item', ) => $color !== 'gray', ]); - + $iconClasses = \Illuminate\Support\Arr::toCssClasses([ 'fi-dropdown-list-item-icon', match ($iconSize) { From 122f799258c86425ca2d2d07559f93d8ec9cb29e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Schr=C3=B6er?= Date: Sat, 17 Feb 2024 17:34:20 +0100 Subject: [PATCH 41/87] Fix no sorting in ColumnGroup --- packages/tables/src/Columns/ColumnGroup.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/tables/src/Columns/ColumnGroup.php b/packages/tables/src/Columns/ColumnGroup.php index a583cdcc5e..8ec8a93a7e 100644 --- a/packages/tables/src/Columns/ColumnGroup.php +++ b/packages/tables/src/Columns/ColumnGroup.php @@ -82,9 +82,11 @@ class ColumnGroup extends Component */ public function getColumns(): array { - return array_map(function (Column $column): Column { - return $column->group($this); - }, $this->evaluate($this->columns) ?? []); + return array_reduce($this->evaluate($this->columns) ?? [], function (array $result, Column $column): array { + $result[$column->getName()] = $column->group($this); + + return $result; + }, []); } /** From 1492c4d823b70e5f4cc3528d939346894cab8a7f Mon Sep 17 00:00:00 2001 From: Alexis <287688+AlexisSerneels@users.noreply.github.com> Date: Sun, 18 Feb 2024 11:16:46 +0100 Subject: [PATCH 42/87] Translate Export Action in French --- packages/actions/resources/lang/fr/export.php | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 packages/actions/resources/lang/fr/export.php diff --git a/packages/actions/resources/lang/fr/export.php b/packages/actions/resources/lang/fr/export.php new file mode 100644 index 0000000000..6b671323d6 --- /dev/null +++ b/packages/actions/resources/lang/fr/export.php @@ -0,0 +1,78 @@ + 'Exporter :label', + + 'modal' => [ + + 'heading' => 'Exporter :label', + + 'form' => [ + + 'columns' => [ + + 'label' => 'Colonnes', + + 'form' => [ + + 'is_enabled' => [ + 'label' => ':column sélectionnée', + ], + + 'label' => [ + 'label' => ':column label', + ], + + ], + + ], + + ], + + 'actions' => [ + + 'export' => [ + 'label' => 'Exporter', + ], + + ], + + ], + + 'notifications' => [ + + 'completed' => [ + + 'title' => 'Exportation terminée', + + 'actions' => [ + + 'download_csv' => [ + 'label' => 'Télécharger .csv', + ], + + 'download_xlsx' => [ + 'label' => 'Télécharger .xlsx', + ], + + ], + + ], + + 'max_rows' => [ + 'title' => 'L\'exportation est trop volumineuse', + 'body' => 'Vous ne pouvez pas exporter plus d’une ligne à la fois.|Vous ne pouvez pas exporter plus de :count lignes à la fois', + ], + + 'started' => [ + 'title' => 'L’exportation a commencé', + 'body' => 'Votre exportation a commencé et 1 ligne sera traitée en arrière-plan.|Votre exportation a commencé et :count lignes seront traitées en arrière-plan.', + ], + + ], + + 'file_name' => 'export-:export_id-:model', + +]; From cf4cd134b0e5af85a15446f8458c667a28e96b8e Mon Sep 17 00:00:00 2001 From: Sacha Corazzi Date: Mon, 19 Feb 2024 12:22:17 +0000 Subject: [PATCH 43/87] Strip tags from getBrandName within title tag --- .../panels/resources/views/components/layout/base.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/panels/resources/views/components/layout/base.blade.php b/packages/panels/resources/views/components/layout/base.blade.php index 7ec3f2376e..220f262d7f 100644 --- a/packages/panels/resources/views/components/layout/base.blade.php +++ b/packages/panels/resources/views/components/layout/base.blade.php @@ -24,7 +24,7 @@ {{ filled($title = strip_tags(($livewire ?? null)?->getTitle() ?? '')) ? "{$title} - " : null }} - {{ filament()->getBrandName() }} + {{ strip_tags(filament()->getBrandName()) }} {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::STYLES_BEFORE, scopes: $livewire->getRenderHookScopes()) }} From 9824c5a5ea3ac8a46f72ac53a98bc40477f2a5ab Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Mon, 19 Feb 2024 13:15:43 +0000 Subject: [PATCH 44/87] cs --- .../docs/07-prebuilt-actions/09-export.md | 3 +- .../actions/src/Concerns/CanExportRecords.php | 79 +++++++++---------- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/packages/actions/docs/07-prebuilt-actions/09-export.md b/packages/actions/docs/07-prebuilt-actions/09-export.md index 3d91bded86..38f7cdbe14 100644 --- a/packages/actions/docs/07-prebuilt-actions/09-export.md +++ b/packages/actions/docs/07-prebuilt-actions/09-export.md @@ -126,11 +126,10 @@ ExportColumn::make('description') ### Disabling column selection -By default, user will be asked which columns they would like to export. You can disable this functionality with the `columnMapping()` method: +By default, user will be asked which columns they would like to export. You can disable this functionality using `columnMapping(false)`: ```php use App\Filament\Exports\ProductExporter; -use Filament\Actions\ExportAction; ExportAction::make() ->exporter(ProductExporter::class) diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index d2f3e1d6d9..c5116d7bc9 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -61,7 +61,7 @@ trait CanExportRecords protected ?Closure $modifyQueryUsing = null; - protected bool $hasColumnMapping = true; + protected bool | Closure $hasColumnMapping = true; protected function setUp(): void { @@ -75,40 +75,35 @@ trait CanExportRecords $this->groupedIcon(FilamentIcon::resolve('actions::export-action.grouped') ?? 'heroicon-m-arrow-down-tray'); - $this->form(function (ExportAction | ExportTableAction | ExportTableBulkAction $action): array { - if ($action->hasColumnMapping()) { - return array_merge([ - Fieldset::make(__('filament-actions::export.modal.form.columns.label')) - ->columns(1) - ->inlineLabel() - ->schema(function () use ($action): array { - return array_map( - fn (ExportColumn $column): Split => Split::make([ - Forms\Components\Checkbox::make('isEnabled') - ->label(__('filament-actions::export.modal.form.columns.form.is_enabled.label', ['column' => $column->getName()])) - ->hiddenLabel() - ->default($column->isEnabledByDefault()) - ->live() - ->grow(false), - Forms\Components\TextInput::make('label') - ->label(__('filament-actions::export.modal.form.columns.form.label.label', ['column' => $column->getName()])) - ->hiddenLabel() - ->default($column->getLabel()) - ->placeholder($column->getLabel()) - ->disabled(fn (Forms\Get $get): bool => ! $get('isEnabled')) - ->required(fn (Forms\Get $get): bool => (bool) $get('isEnabled')), - ]) - ->verticallyAlignCenter() - ->statePath($column->getName()), - $action->getExporter()::getColumns(), - ); - }) - ->statePath('columnMap'), - ], $action->getExporter()::getOptionsFormComponents()); - } else { - return $action->getExporter()::getOptionsFormComponents(); - } - }); + $this->form(fn (ExportAction | ExportTableAction | ExportTableBulkAction $action): array => [ + ...($action->hasColumnMapping() ? [Fieldset::make(__('filament-actions::export.modal.form.columns.label')) + ->columns(1) + ->inlineLabel() + ->schema(function () use ($action): array { + return array_map( + fn (ExportColumn $column): Split => Split::make([ + Forms\Components\Checkbox::make('isEnabled') + ->label(__('filament-actions::export.modal.form.columns.form.is_enabled.label', ['column' => $column->getName()])) + ->hiddenLabel() + ->default($column->isEnabledByDefault()) + ->live() + ->grow(false), + Forms\Components\TextInput::make('label') + ->label(__('filament-actions::export.modal.form.columns.form.label.label', ['column' => $column->getName()])) + ->hiddenLabel() + ->default($column->getLabel()) + ->placeholder($column->getLabel()) + ->disabled(fn (Forms\Get $get): bool => ! $get('isEnabled')) + ->required(fn (Forms\Get $get): bool => (bool) $get('isEnabled')), + ]) + ->verticallyAlignCenter() + ->statePath($column->getName()), + $action->getExporter()::getColumns(), + ); + }) + ->statePath('columnMap')] : []), + ...$action->getExporter()::getOptionsFormComponents(), + ]); $this->action(function (ExportAction | ExportTableAction | ExportTableBulkAction $action, array $data, Component $livewire) { if ($livewire instanceof HasTable) { @@ -150,15 +145,15 @@ trait CanExportRecords if ($action->hasColumnMapping()) { $columnMap = collect($data['columnMap']) ->dot() - ->reduce(fn(Collection $carry, mixed $value, string $key): Collection => $carry->mergeRecursive([ + ->reduce(fn (Collection $carry, mixed $value, string $key): Collection => $carry->mergeRecursive([ Str::beforeLast($key, '.') => [Str::afterLast($key, '.') => $value], ]), collect()) - ->filter(fn(array $column): bool => $column['isEnabled'] ?? false) - ->mapWithKeys(fn(array $column, string $columnName): array => [$columnName => $column['label']]) + ->filter(fn (array $column): bool => $column['isEnabled'] ?? false) + ->mapWithKeys(fn (array $column, string $columnName): array => [$columnName => $column['label']]) ->all(); } else { $columnMap = collect($action->getExporter()::getColumns()) - ->mapWithKeys(fn(ExportColumn $column): array => [$column->getName() => $column->getLabel()]) + ->mapWithKeys(fn (ExportColumn $column): array => [$column->getName() => $column->getLabel()]) ->all(); } @@ -402,15 +397,15 @@ trait CanExportRecords return $this; } - public function columnMapping(bool $columnMapping): static + public function columnMapping(bool | Closure $condition = true): static { - $this->hasColumnMapping = $columnMapping; + $this->hasColumnMapping = $condition; return $this; } public function hasColumnMapping(): bool { - return $this->evaluate($this->hasColumnMapping); + return (bool) $this->evaluate($this->hasColumnMapping); } } From dff3b6aa746bf0941d577c39fcd256c89123c492 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Mon, 19 Feb 2024 13:28:23 +0000 Subject: [PATCH 45/87] cs --- composer.lock | 281 +++++++++--------- .../Commands/Concerns/CanGenerateForms.php | 1 + .../panels/src/Commands/MakePageCommand.php | 2 +- 3 files changed, 145 insertions(+), 139 deletions(-) diff --git a/composer.lock b/composer.lock index 93b697067d..6ea2ccb7e5 100644 --- a/composer.lock +++ b/composer.lock @@ -129,16 +129,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.298.4", + "version": "3.299.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "c61e8f8640352c4cad1ec364c0801b8adae8adb9" + "reference": "a0f87b8e8bfb9afd0ffd702fcda556b465eee457" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c61e8f8640352c4cad1ec364c0801b8adae8adb9", - "reference": "c61e8f8640352c4cad1ec364c0801b8adae8adb9", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a0f87b8e8bfb9afd0ffd702fcda556b465eee457", + "reference": "a0f87b8e8bfb9afd0ffd702fcda556b465eee457", "shasum": "" }, "require": { @@ -218,32 +218,32 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.298.4" + "source": "https://github.com/aws/aws-sdk-php/tree/3.299.1" }, - "time": "2024-02-06T19:09:25+00:00" + "time": "2024-02-16T19:08:34+00:00" }, { "name": "blade-ui-kit/blade-heroicons", - "version": "2.2.1", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/blade-ui-kit/blade-heroicons.git", - "reference": "bcf4be8f6bbde0bb4c23f2e3fb189b88dec1580a" + "reference": "a265dbcf2a098121aad05752d0bba9f59022e4ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/blade-ui-kit/blade-heroicons/zipball/bcf4be8f6bbde0bb4c23f2e3fb189b88dec1580a", - "reference": "bcf4be8f6bbde0bb4c23f2e3fb189b88dec1580a", + "url": "https://api.github.com/repos/blade-ui-kit/blade-heroicons/zipball/a265dbcf2a098121aad05752d0bba9f59022e4ba", + "reference": "a265dbcf2a098121aad05752d0bba9f59022e4ba", "shasum": "" }, "require": { - "blade-ui-kit/blade-icons": "^1.1", - "illuminate/support": "^9.0|^10.0", + "blade-ui-kit/blade-icons": "^1.6", + "illuminate/support": "^9.0|^10.0|^11.0", "php": "^8.0" }, "require-dev": { - "orchestra/testbench": "^7.0|^8.0", - "phpunit/phpunit": "^9.0" + "orchestra/testbench": "^7.0|^8.0|^9.0", + "phpunit/phpunit": "^9.0|^10.5|^11.0" }, "type": "library", "extra": { @@ -277,7 +277,7 @@ ], "support": { "issues": "https://github.com/blade-ui-kit/blade-heroicons/issues", - "source": "https://github.com/blade-ui-kit/blade-heroicons/tree/2.2.1" + "source": "https://github.com/blade-ui-kit/blade-heroicons/tree/2.3.0" }, "funding": [ { @@ -289,35 +289,35 @@ "type": "paypal" } ], - "time": "2023-12-18T20:44:03+00:00" + "time": "2024-02-07T16:33:46+00:00" }, { "name": "blade-ui-kit/blade-icons", - "version": "1.5.3", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/blade-ui-kit/blade-icons.git", - "reference": "b5e6603218e2347ac81cb780bc6f71c8c3b31f5b" + "reference": "89660d93f9897d231e9113ba203cd17f4c5efade" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/blade-ui-kit/blade-icons/zipball/b5e6603218e2347ac81cb780bc6f71c8c3b31f5b", - "reference": "b5e6603218e2347ac81cb780bc6f71c8c3b31f5b", + "url": "https://api.github.com/repos/blade-ui-kit/blade-icons/zipball/89660d93f9897d231e9113ba203cd17f4c5efade", + "reference": "89660d93f9897d231e9113ba203cd17f4c5efade", "shasum": "" }, "require": { - "illuminate/contracts": "^8.0|^9.0|^10.0", - "illuminate/filesystem": "^8.0|^9.0|^10.0", - "illuminate/support": "^8.0|^9.0|^10.0", - "illuminate/view": "^8.0|^9.0|^10.0", + "illuminate/contracts": "^8.0|^9.0|^10.0|^11.0", + "illuminate/filesystem": "^8.0|^9.0|^10.0|^11.0", + "illuminate/support": "^8.0|^9.0|^10.0|^11.0", + "illuminate/view": "^8.0|^9.0|^10.0|^11.0", "php": "^7.4|^8.0", - "symfony/console": "^5.3|^6.0", - "symfony/finder": "^5.3|^6.0" + "symfony/console": "^5.3|^6.0|^7.0", + "symfony/finder": "^5.3|^6.0|^7.0" }, "require-dev": { - "mockery/mockery": "^1.3", - "orchestra/testbench": "^6.0|^7.0|^8.0", - "phpunit/phpunit": "^9.0" + "mockery/mockery": "^1.5.1", + "orchestra/testbench": "^6.0|^7.0|^8.0|^9.0", + "phpunit/phpunit": "^9.0|^10.5|^11.0" }, "bin": [ "bin/blade-icons-generate" @@ -370,7 +370,7 @@ "type": "paypal" } ], - "time": "2023-10-18T10:50:13+00:00" + "time": "2024-02-07T16:09:20+00:00" }, { "name": "brianium/paratest", @@ -895,16 +895,16 @@ }, { "name": "doctrine/dbal", - "version": "3.8.1", + "version": "3.8.2", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "c9ea252cdce4da324ede3d6c5913dd89f769afd2" + "reference": "a19a1d05ca211f41089dffcc387733a6875196cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/c9ea252cdce4da324ede3d6c5913dd89f769afd2", - "reference": "c9ea252cdce4da324ede3d6c5913dd89f769afd2", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/a19a1d05ca211f41089dffcc387733a6875196cb", + "reference": "a19a1d05ca211f41089dffcc387733a6875196cb", "shasum": "" }, "require": { @@ -988,7 +988,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.8.1" + "source": "https://github.com/doctrine/dbal/tree/3.8.2" }, "funding": [ { @@ -1004,7 +1004,7 @@ "type": "tidelift" } ], - "time": "2024-02-03T17:33:49+00:00" + "time": "2024-02-12T18:36:36+00:00" }, { "name": "doctrine/deprecations", @@ -1146,16 +1146,16 @@ }, { "name": "doctrine/inflector", - "version": "2.0.9", + "version": "2.0.10", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "2930cd5ef353871c821d5c43ed030d39ac8cfe65" + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/2930cd5ef353871c821d5c43ed030d39ac8cfe65", - "reference": "2930cd5ef353871c821d5c43ed030d39ac8cfe65", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", "shasum": "" }, "require": { @@ -1217,7 +1217,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.9" + "source": "https://github.com/doctrine/inflector/tree/2.0.10" }, "funding": [ { @@ -1233,7 +1233,7 @@ "type": "tidelift" } ], - "time": "2024-01-15T18:05:13+00:00" + "time": "2024-02-18T20:23:39+00:00" }, { "name": "doctrine/lexer", @@ -2343,27 +2343,27 @@ }, { "name": "kirschbaum-development/eloquent-power-joins", - "version": "3.4.0", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/kirschbaum-development/eloquent-power-joins.git", - "reference": "9238fcb53d777265ee9d8d139810e2cadecde079" + "reference": "13feb3692ab6c0475b2c05de131d5f5822fb250a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kirschbaum-development/eloquent-power-joins/zipball/9238fcb53d777265ee9d8d139810e2cadecde079", - "reference": "9238fcb53d777265ee9d8d139810e2cadecde079", + "url": "https://api.github.com/repos/kirschbaum-development/eloquent-power-joins/zipball/13feb3692ab6c0475b2c05de131d5f5822fb250a", + "reference": "13feb3692ab6c0475b2c05de131d5f5822fb250a", "shasum": "" }, "require": { - "illuminate/database": "^8.0|^9.0|^10.0", - "illuminate/support": "^8.0|^9.0|^10.0", + "illuminate/database": "^8.0|^9.0|^10.0|^11.0", + "illuminate/support": "^8.0|^9.0|^10.0|^11.0", "php": "^8.0" }, "require-dev": { "laravel/legacy-factories": "^1.0@dev", - "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0", - "phpunit/phpunit": "^8.0|^9.0" + "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0|^9.0", + "phpunit/phpunit": "^8.0|^9.0|^10.0" }, "type": "library", "extra": { @@ -2399,22 +2399,22 @@ ], "support": { "issues": "https://github.com/kirschbaum-development/eloquent-power-joins/issues", - "source": "https://github.com/kirschbaum-development/eloquent-power-joins/tree/3.4.0" + "source": "https://github.com/kirschbaum-development/eloquent-power-joins/tree/3.5.0" }, - "time": "2023-12-07T10:44:41+00:00" + "time": "2024-02-13T15:40:14+00:00" }, { "name": "larastan/larastan", - "version": "v2.8.1", + "version": "v2.9.0", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "b7cc6a29c457a7d4f3de90466392ae9ad3e17022" + "reference": "35fa9cbe1895e76215bbe74571a344f2705fbe01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/b7cc6a29c457a7d4f3de90466392ae9ad3e17022", - "reference": "b7cc6a29c457a7d4f3de90466392ae9ad3e17022", + "url": "https://api.github.com/repos/larastan/larastan/zipball/35fa9cbe1895e76215bbe74571a344f2705fbe01", + "reference": "35fa9cbe1895e76215bbe74571a344f2705fbe01", "shasum": "" }, "require": { @@ -2482,7 +2482,7 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v2.8.1" + "source": "https://github.com/larastan/larastan/tree/v2.9.0" }, "funding": [ { @@ -2502,7 +2502,7 @@ "type": "patreon" } ], - "time": "2024-01-08T09:11:17+00:00" + "time": "2024-02-13T11:49:22+00:00" }, { "name": "laravel/cashier", @@ -2593,16 +2593,16 @@ }, { "name": "laravel/framework", - "version": "v10.43.0", + "version": "v10.44.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "4f7802dfc9993cb57cf69615491ce1a7eb2e9529" + "reference": "1199dbe361787bbe9648131a79f53921b4148cf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/4f7802dfc9993cb57cf69615491ce1a7eb2e9529", - "reference": "4f7802dfc9993cb57cf69615491ce1a7eb2e9529", + "url": "https://api.github.com/repos/laravel/framework/zipball/1199dbe361787bbe9648131a79f53921b4148cf6", + "reference": "1199dbe361787bbe9648131a79f53921b4148cf6", "shasum": "" }, "require": { @@ -2650,6 +2650,7 @@ "conflict": { "carbonphp/carbon-doctrine-types": ">=3.0", "doctrine/dbal": ">=4.0", + "phpunit/phpunit": ">=11.0.0", "tightenco/collect": "<5.5.33" }, "provide": { @@ -2794,20 +2795,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-01-30T16:25:02+00:00" + "time": "2024-02-13T16:01:16+00:00" }, { "name": "laravel/pint", - "version": "v1.13.10", + "version": "v1.13.11", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "e2b5060885694ca30ac008c05dc9d47f10ed1abf" + "reference": "60a163c3e7e3346a1dec96d3e6f02e6465452552" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/e2b5060885694ca30ac008c05dc9d47f10ed1abf", - "reference": "e2b5060885694ca30ac008c05dc9d47f10ed1abf", + "url": "https://api.github.com/repos/laravel/pint/zipball/60a163c3e7e3346a1dec96d3e6f02e6465452552", + "reference": "60a163c3e7e3346a1dec96d3e6f02e6465452552", "shasum": "" }, "require": { @@ -2818,13 +2819,13 @@ "php": "^8.1.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.47.1", - "illuminate/view": "^10.41.0", + "friendsofphp/php-cs-fixer": "^3.49.0", + "illuminate/view": "^10.43.0", "larastan/larastan": "^2.8.1", "laravel-zero/framework": "^10.3.0", "mockery/mockery": "^1.6.7", "nunomaduro/termwind": "^1.15.1", - "pestphp/pest": "^2.31.0" + "pestphp/pest": "^2.33.6" }, "bin": [ "builds/pint" @@ -2860,7 +2861,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2024-01-22T09:04:15+00:00" + "time": "2024-02-13T17:20:13+00:00" }, { "name": "laravel/prompts", @@ -4075,41 +4076,41 @@ }, { "name": "moneyphp/money", - "version": "v4.4.0", + "version": "v4.5.0", "source": { "type": "git", "url": "https://github.com/moneyphp/money.git", - "reference": "5e60aebf09f709dd4ea16bf85e66d65301c0d172" + "reference": "a1daa7daf159b4044e3d0c34c41fe2be5860e850" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/moneyphp/money/zipball/5e60aebf09f709dd4ea16bf85e66d65301c0d172", - "reference": "5e60aebf09f709dd4ea16bf85e66d65301c0d172", + "url": "https://api.github.com/repos/moneyphp/money/zipball/a1daa7daf159b4044e3d0c34c41fe2be5860e850", + "reference": "a1daa7daf159b4044e3d0c34c41fe2be5860e850", "shasum": "" }, "require": { "ext-bcmath": "*", "ext-filter": "*", "ext-json": "*", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0" }, "require-dev": { "cache/taggable-cache": "^1.1.0", - "doctrine/coding-standard": "^9.0", - "doctrine/instantiator": "^1.4.0", + "doctrine/coding-standard": "^12.0", + "doctrine/instantiator": "^1.5.0 || ^2.0", "ext-gmp": "*", "ext-intl": "*", - "florianv/exchanger": "^2.6.3", + "florianv/exchanger": "^2.8.1", "florianv/swap": "^4.3.0", - "moneyphp/crypto-currencies": "^1.0.0", - "moneyphp/iso-currencies": "^3.2.1", - "php-http/message": "^1.11.0", - "php-http/mock-client": "^1.4.1", + "moneyphp/crypto-currencies": "^1.1.0", + "moneyphp/iso-currencies": "^3.4", + "php-http/message": "^1.16.0", + "php-http/mock-client": "^1.6.0", "phpbench/phpbench": "^1.2.5", - "phpunit/phpunit": "^9.5.4", + "phpunit/phpunit": "^10.5.9", "psalm/plugin-phpunit": "^0.18.4", "psr/cache": "^1.0.1 || ^2.0 || ^3.0", - "vimeo/psalm": "~5.15.0" + "vimeo/psalm": "~5.20.0" }, "suggest": { "ext-gmp": "Calculate without integer limits", @@ -4157,9 +4158,9 @@ ], "support": { "issues": "https://github.com/moneyphp/money/issues", - "source": "https://github.com/moneyphp/money/tree/v4.4.0" + "source": "https://github.com/moneyphp/money/tree/v4.5.0" }, - "time": "2024-01-24T08:29:16+00:00" + "time": "2024-02-15T19:47:21+00:00" }, { "name": "monolog/monolog", @@ -5341,16 +5342,16 @@ }, { "name": "pestphp/pest", - "version": "v2.33.4", + "version": "v2.34.0", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "4baf27911e088cd27c0114bd9b4ee579203f8810" + "reference": "602b696348efdf4da83c9719de3062462cc1d146" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/4baf27911e088cd27c0114bd9b4ee579203f8810", - "reference": "4baf27911e088cd27c0114bd9b4ee579203f8810", + "url": "https://api.github.com/repos/pestphp/pest/zipball/602b696348efdf4da83c9719de3062462cc1d146", + "reference": "602b696348efdf4da83c9719de3062462cc1d146", "shasum": "" }, "require": { @@ -5360,10 +5361,10 @@ "pestphp/pest-plugin": "^2.1.1", "pestphp/pest-plugin-arch": "^2.7.0", "php": "^8.1.0", - "phpunit/phpunit": "^10.5.9" + "phpunit/phpunit": "^10.5.10" }, "conflict": { - "phpunit/phpunit": ">10.5.9", + "phpunit/phpunit": ">10.5.10", "sebastian/exporter": "<5.1.0", "webmozart/assert": "<1.11.0" }, @@ -5433,7 +5434,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v2.33.4" + "source": "https://github.com/pestphp/pest/tree/v2.34.0" }, "funding": [ { @@ -5445,7 +5446,7 @@ "type": "github" } ], - "time": "2024-02-02T16:54:54+00:00" + "time": "2024-02-17T10:06:53+00:00" }, { "name": "pestphp/pest-plugin", @@ -5590,27 +5591,27 @@ }, { "name": "pestphp/pest-plugin-laravel", - "version": "v2.2.0", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/pestphp/pest-plugin-laravel.git", - "reference": "77a2838c1d3b09d147211e76a48987ba9a758279" + "reference": "2f6ea6233bb74ec65d969ecdea56bdbd3d1e2f0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-laravel/zipball/77a2838c1d3b09d147211e76a48987ba9a758279", - "reference": "77a2838c1d3b09d147211e76a48987ba9a758279", + "url": "https://api.github.com/repos/pestphp/pest-plugin-laravel/zipball/2f6ea6233bb74ec65d969ecdea56bdbd3d1e2f0e", + "reference": "2f6ea6233bb74ec65d969ecdea56bdbd3d1e2f0e", "shasum": "" }, "require": { - "laravel/framework": "^10.18.0|^11.0", - "pestphp/pest": "^2.13.0", + "laravel/framework": "^10.44.0|^11.0", + "pestphp/pest": "^2.33.6", "php": "^8.1.0" }, "require-dev": { - "laravel/dusk": "^7.9.3", - "orchestra/testbench": "^8.6.3", - "pestphp/pest-dev-tools": "^2.14.0" + "laravel/dusk": "^7.12.3", + "orchestra/testbench": "^8.21.1|^9.0.0", + "pestphp/pest-dev-tools": "^2.16.0" }, "type": "library", "extra": { @@ -5618,6 +5619,11 @@ "providers": [ "Pest\\Laravel\\PestServiceProvider" ] + }, + "pest": { + "plugins": [ + "Pest\\Laravel\\Plugin" + ] } }, "autoload": { @@ -5643,7 +5649,7 @@ "unit" ], "support": { - "source": "https://github.com/pestphp/pest-plugin-laravel/tree/v2.2.0" + "source": "https://github.com/pestphp/pest-plugin-laravel/tree/v2.3.0" }, "funding": [ { @@ -5655,7 +5661,7 @@ "type": "github" } ], - "time": "2023-08-10T15:37:09+00:00" + "time": "2024-02-17T10:04:08+00:00" }, { "name": "phar-io/manifest", @@ -6575,16 +6581,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.9", + "version": "10.5.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "0bd663704f0165c9e76fe4f06ffa6a1ca727fdbe" + "reference": "50b8e314b6d0dd06521dc31d1abffa73f25f850c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0bd663704f0165c9e76fe4f06ffa6a1ca727fdbe", - "reference": "0bd663704f0165c9e76fe4f06ffa6a1ca727fdbe", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/50b8e314b6d0dd06521dc31d1abffa73f25f850c", + "reference": "50b8e314b6d0dd06521dc31d1abffa73f25f850c", "shasum": "" }, "require": { @@ -6656,7 +6662,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.9" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.10" }, "funding": [ { @@ -6672,7 +6678,7 @@ "type": "tidelift" } ], - "time": "2024-01-22T14:35:40+00:00" + "time": "2024-02-04T09:07:51+00:00" }, { "name": "pimple/pimple", @@ -8738,16 +8744,16 @@ }, { "name": "spatie/image", - "version": "3.3.4", + "version": "3.3.5", "source": { "type": "git", "url": "https://github.com/spatie/image.git", - "reference": "6bd35eecd44a08f93fd0436f99e9adbe3ebc05da" + "reference": "e74f161b1e28e97752a70ef456f5ae7bad2277c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/image/zipball/6bd35eecd44a08f93fd0436f99e9adbe3ebc05da", - "reference": "6bd35eecd44a08f93fd0436f99e9adbe3ebc05da", + "url": "https://api.github.com/repos/spatie/image/zipball/e74f161b1e28e97752a70ef456f5ae7bad2277c1", + "reference": "e74f161b1e28e97752a70ef456f5ae7bad2277c1", "shasum": "" }, "require": { @@ -8794,7 +8800,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/image/tree/3.3.4" + "source": "https://github.com/spatie/image/tree/3.3.5" }, "funding": [ { @@ -8806,7 +8812,7 @@ "type": "github" } ], - "time": "2024-01-15T12:17:58+00:00" + "time": "2024-02-16T10:03:53+00:00" }, { "name": "spatie/image-optimizer", @@ -8924,28 +8930,28 @@ }, { "name": "spatie/laravel-medialibrary", - "version": "11.2.0", + "version": "11.4.1", "source": { "type": "git", "url": "https://github.com/spatie/laravel-medialibrary.git", - "reference": "3c4021c0ec6d1180b57f40c772b51da5d4e60162" + "reference": "d94b110c2ee9a0602ae1be9bf59e91ae8dab28cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/3c4021c0ec6d1180b57f40c772b51da5d4e60162", - "reference": "3c4021c0ec6d1180b57f40c772b51da5d4e60162", + "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/d94b110c2ee9a0602ae1be9bf59e91ae8dab28cf", + "reference": "d94b110c2ee9a0602ae1be9bf59e91ae8dab28cf", "shasum": "" }, "require": { "ext-exif": "*", "ext-fileinfo": "*", "ext-json": "*", - "illuminate/bus": "^10.0", - "illuminate/conditionable": "^10.0", - "illuminate/console": "^10.0", - "illuminate/database": "^10.0", - "illuminate/pipeline": "^10.0", - "illuminate/support": "^10.0", + "illuminate/bus": "^10.0|^11.0", + "illuminate/conditionable": "^10.0|^11.0", + "illuminate/console": "^10.0|^11.0", + "illuminate/database": "^10.0|^11.0", + "illuminate/pipeline": "^10.0|^11.0", + "illuminate/support": "^10.0|^11.0", "maennchen/zipstream-php": "^3.1", "php": "^8.2", "spatie/image": "^3.3.2", @@ -8958,7 +8964,6 @@ }, "require-dev": { "aws/aws-sdk-php": "^3.293.10", - "doctrine/dbal": "^2.13.9", "ext-imagick": "*", "ext-pdo_sqlite": "*", "ext-zip": "*", @@ -8966,7 +8971,7 @@ "larastan/larastan": "^2.7", "league/flysystem-aws-s3-v3": "^3.22", "mockery/mockery": "^1.6.7", - "orchestra/testbench": "^7.0|^8.17", + "orchestra/testbench": "^7.0|^8.17|^9.0", "pestphp/pest": "^2.28", "phpstan/extension-installer": "^1.3.1", "spatie/laravel-ray": "^1.33", @@ -9017,7 +9022,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-medialibrary/issues", - "source": "https://github.com/spatie/laravel-medialibrary/tree/11.2.0" + "source": "https://github.com/spatie/laravel-medialibrary/tree/11.4.1" }, "funding": [ { @@ -9029,7 +9034,7 @@ "type": "github" } ], - "time": "2024-01-29T07:53:43+00:00" + "time": "2024-02-17T12:22:37+00:00" }, { "name": "spatie/laravel-package-tools", @@ -9586,16 +9591,16 @@ }, { "name": "staudenmeir/eloquent-has-many-deep", - "version": "v1.19.2", + "version": "v1.19.3", "source": { "type": "git", "url": "https://github.com/staudenmeir/eloquent-has-many-deep.git", - "reference": "4192ef405f74a52fbac47f515a40260b7c45e319" + "reference": "35e6a2f18a6605cbeda69573080c4ba008501971" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/staudenmeir/eloquent-has-many-deep/zipball/4192ef405f74a52fbac47f515a40260b7c45e319", - "reference": "4192ef405f74a52fbac47f515a40260b7c45e319", + "url": "https://api.github.com/repos/staudenmeir/eloquent-has-many-deep/zipball/35e6a2f18a6605cbeda69573080c4ba008501971", + "reference": "35e6a2f18a6605cbeda69573080c4ba008501971", "shasum": "" }, "require": { @@ -9642,7 +9647,7 @@ "description": "Laravel Eloquent HasManyThrough relationships with unlimited levels", "support": { "issues": "https://github.com/staudenmeir/eloquent-has-many-deep/issues", - "source": "https://github.com/staudenmeir/eloquent-has-many-deep/tree/v1.19.2" + "source": "https://github.com/staudenmeir/eloquent-has-many-deep/tree/v1.19.3" }, "funding": [ { @@ -9650,7 +9655,7 @@ "type": "custom" } ], - "time": "2023-12-19T15:44:14+00:00" + "time": "2024-02-07T21:23:00+00:00" }, { "name": "staudenmeir/eloquent-has-many-deep-contracts", diff --git a/packages/forms/src/Commands/Concerns/CanGenerateForms.php b/packages/forms/src/Commands/Concerns/CanGenerateForms.php index 486ffd6088..0e63c78848 100644 --- a/packages/forms/src/Commands/Concerns/CanGenerateForms.php +++ b/packages/forms/src/Commands/Concerns/CanGenerateForms.php @@ -155,6 +155,7 @@ trait CanGenerateForms $parameterValue = match (true) { /** @phpstan-ignore-next-line */ is_bool($parameterValue) => $parameterValue ? 'true' : 'false', + /** @phpstan-ignore-next-line */ is_null($parameterValue) => 'null', is_numeric($parameterValue) => $parameterValue, default => "'{$parameterValue}'", diff --git a/packages/panels/src/Commands/MakePageCommand.php b/packages/panels/src/Commands/MakePageCommand.php index 82bdaa7eee..cde6f83709 100644 --- a/packages/panels/src/Commands/MakePageCommand.php +++ b/packages/panels/src/Commands/MakePageCommand.php @@ -266,7 +266,7 @@ class MakePageCommand extends Command $this->copyStubToApp('ResourceManageRelatedRecordsPage', $path, [ 'baseResourcePage' => "Filament\\Resources\\Pages\\{$resourcePage}", 'baseResourcePageClass' => $resourcePage, - 'modifyQueryUsing' => filled($modifyQueryUsing ?? null) ? PHP_EOL . $this->indentString($modifyQueryUsing ?? '', 3) : $modifyQueryUsing ?? '', + 'modifyQueryUsing' => filled($modifyQueryUsing) ? PHP_EOL . $this->indentString($modifyQueryUsing ?? '', 3) : $modifyQueryUsing ?? '', 'namespace' => "{$resourceNamespace}\\{$resource}\\Pages" . ($pageNamespace !== '' ? "\\{$pageNamespace}" : ''), 'recordTitleAttribute' => $recordTitleAttribute ?? null, 'relationship' => $relationship ?? null, From 321d32ec1f10a38755c7619279d36533feb873a3 Mon Sep 17 00:00:00 2001 From: Sacha Corazzi Date: Mon, 19 Feb 2024 14:24:19 +0000 Subject: [PATCH 46/87] Add test, update docs --- packages/panels/docs/12-themes.md | 13 +++++++++++++ tests/src/Panels/Pages/PageTest.php | 12 ++++++++++++ 2 files changed, 25 insertions(+) diff --git a/packages/panels/docs/12-themes.md b/packages/panels/docs/12-themes.md index be8479192f..b680502676 100644 --- a/packages/panels/docs/12-themes.md +++ b/packages/panels/docs/12-themes.md @@ -187,6 +187,19 @@ public function panel(Panel $panel): Panel } ``` +You may also pass an `Htmlable` element. Note that when the brand name is used in the page's `` tag, the HTML tags will be stripped. + +```php +use Filament\Panel; + +public function panel(Panel $panel): Panel +{ + return $panel + // ... + ->brandName(new HtmlString('Filament <i>Demo</i>'); +} +``` + To render an image instead, you can pass a URL to the `brandLogo()` method: ```php diff --git a/tests/src/Panels/Pages/PageTest.php b/tests/src/Panels/Pages/PageTest.php index f7d6cc424c..6317967627 100644 --- a/tests/src/Panels/Pages/PageTest.php +++ b/tests/src/Panels/Pages/PageTest.php @@ -1,9 +1,11 @@ <?php +use Filament\Facades\Filament; use Filament\Notifications\Notification; use Filament\Pages\Page; use Filament\Tests\Panels\Fixtures\Pages\Settings; use Filament\Tests\Panels\Pages\TestCase; +use Illuminate\Support\HtmlString; use Illuminate\Validation\ValidationException; use function Filament\Tests\livewire; @@ -35,3 +37,13 @@ it('can report validation errors', function () { ->assertHasErrors(['name' => ['required']]) ->assertNotified(); }); + +it('strips html tags from brand name in title tag', function () { + $htmlBrandName = '<span>Filament <i>HTML Title</i></span>'; + + Filament::getCurrentPanel()->brandName(new HtmlString($htmlBrandName)); + + $this->get(Settings::getUrl()) + ->assertSee('Filament HTML Title') + ->assertDontSee($htmlBrandName); +}); From 6a257143c7ab086caf3a8126a1d7bf7dff4180f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9lder=20Teixeira?= <corvisierpt@gmail.com> Date: Mon, 19 Feb 2024 15:17:48 +0000 Subject: [PATCH 47/87] European Portuguese Translation Added mising translations and corrected prvious values. --- packages/forms/resources/lang/pt_PT/components.php | 2 +- .../resources/lang/pt_PT/components/pagination.php | 10 +++++++++- packages/tables/resources/lang/pt_PT/table.php | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/forms/resources/lang/pt_PT/components.php b/packages/forms/resources/lang/pt_PT/components.php index 1c8daf41ad..2592984a52 100644 --- a/packages/forms/resources/lang/pt_PT/components.php +++ b/packages/forms/resources/lang/pt_PT/components.php @@ -189,7 +189,7 @@ return [ 'messages' => [ 'confirmation' => 'Não é recomendado editar ficheiros SVG, pois pode resultar em perda de qualidade ao redimensionar.\n Tem a certeza de que deseja prosseguir?', - 'disabled' => 'A edição de ficheiros SVG está desativada, pois pode resultar em perda de qualidade ao redimensionar.', + 'disabled' => 'A edição de ficheiros SVG está desactivada, pois pode resultar em perda de qualidade ao redimensionar.', ], ], diff --git a/packages/support/resources/lang/pt_PT/components/pagination.php b/packages/support/resources/lang/pt_PT/components/pagination.php index 0f86a7c9e2..5989b5952b 100644 --- a/packages/support/resources/lang/pt_PT/components/pagination.php +++ b/packages/support/resources/lang/pt_PT/components/pagination.php @@ -22,12 +22,20 @@ return [ 'actions' => [ + 'first' => [ + 'label' => 'Primeira', + ], + 'go_to_page' => [ 'label' => 'Ir para a página :page', ], + 'last' => [ + 'label' => 'Última', + ], + 'next' => [ - 'label' => 'Próximo', + 'label' => 'Próxima', ], 'previous' => [ diff --git a/packages/tables/resources/lang/pt_PT/table.php b/packages/tables/resources/lang/pt_PT/table.php index 1f0e861195..9c03d09f79 100644 --- a/packages/tables/resources/lang/pt_PT/table.php +++ b/packages/tables/resources/lang/pt_PT/table.php @@ -134,7 +134,7 @@ return [ 'heading' => 'Filtros', - 'indicator' => 'Filtros ativos', + 'indicator' => 'Filtros activos', 'multi_select' => [ 'placeholder' => 'Todos', From 9b7e351d78ee89903b6aba5dba2850752e6ed085 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Mon, 19 Feb 2024 15:37:25 +0000 Subject: [PATCH 48/87] Update MakePageCommand.php --- packages/panels/src/Commands/MakePageCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/panels/src/Commands/MakePageCommand.php b/packages/panels/src/Commands/MakePageCommand.php index cde6f83709..19b61e0faf 100644 --- a/packages/panels/src/Commands/MakePageCommand.php +++ b/packages/panels/src/Commands/MakePageCommand.php @@ -266,7 +266,7 @@ class MakePageCommand extends Command $this->copyStubToApp('ResourceManageRelatedRecordsPage', $path, [ 'baseResourcePage' => "Filament\\Resources\\Pages\\{$resourcePage}", 'baseResourcePageClass' => $resourcePage, - 'modifyQueryUsing' => filled($modifyQueryUsing) ? PHP_EOL . $this->indentString($modifyQueryUsing ?? '', 3) : $modifyQueryUsing ?? '', + 'modifyQueryUsing' => filled($modifyQueryUsing ?? null) ? PHP_EOL . $this->indentString($modifyQueryUsing, 3) : $modifyQueryUsing ?? '', 'namespace' => "{$resourceNamespace}\\{$resource}\\Pages" . ($pageNamespace !== '' ? "\\{$pageNamespace}" : ''), 'recordTitleAttribute' => $recordTitleAttribute ?? null, 'relationship' => $relationship ?? null, From 786cc9035dde76051300b62be359fda14c56cdb7 Mon Sep 17 00:00:00 2001 From: Maarten Paauw <maartenpaauw@gmail.com> Date: Mon, 19 Feb 2024 21:48:53 +0100 Subject: [PATCH 49/87] fix(importer): do not fill unmapped columns When the column map value of a given column name is NULL; it means we do not want to call the fillRecord method. --- packages/actions/src/Imports/Importer.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/actions/src/Imports/Importer.php b/packages/actions/src/Imports/Importer.php index 02a9cec9d2..0886127b85 100644 --- a/packages/actions/src/Imports/Importer.php +++ b/packages/actions/src/Imports/Importer.php @@ -191,6 +191,10 @@ abstract class Importer continue; } + if (array_key_exists($columnName, $this->columnMap) && blank($this->columnMap[$columnName])) { + continue; + } + $state = $this->data[$columnName]; if (blank($state) && $column->isBlankStateIgnored()) { From 5b21b806b3f95c7b26fdb0fe0a9ded719141ae6b Mon Sep 17 00:00:00 2001 From: ziming <ziming@users.noreply.github.com> Date: Tue, 20 Feb 2024 16:47:25 +0800 Subject: [PATCH 50/87] Fix beforeFill() hook in EditRecord.php --- packages/panels/src/Resources/Pages/EditRecord.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/panels/src/Resources/Pages/EditRecord.php b/packages/panels/src/Resources/Pages/EditRecord.php index 6897d1604c..1c25e22a26 100644 --- a/packages/panels/src/Resources/Pages/EditRecord.php +++ b/packages/panels/src/Resources/Pages/EditRecord.php @@ -82,6 +82,8 @@ class EditRecord extends Page protected function fillForm(): void { + $this->callHook('beforeFill'); + $data = $this->getRecord()->attributesToArray(); /** @internal Read the DocBlock above the following method. */ @@ -95,8 +97,6 @@ class EditRecord extends Page */ protected function fillFormWithDataAndCallHooks(array $data): void { - $this->callHook('beforeFill'); - $data = $this->mutateFormDataBeforeFill($data); $this->form->fill($data); From dce99730cff744e17434fc1ec163a0b502b1bb0d Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 09:41:35 +0000 Subject: [PATCH 51/87] Update 12-themes.md --- packages/panels/docs/12-themes.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/panels/docs/12-themes.md b/packages/panels/docs/12-themes.md index b680502676..be8479192f 100644 --- a/packages/panels/docs/12-themes.md +++ b/packages/panels/docs/12-themes.md @@ -187,19 +187,6 @@ public function panel(Panel $panel): Panel } ``` -You may also pass an `Htmlable` element. Note that when the brand name is used in the page's `<title>` tag, the HTML tags will be stripped. - -```php -use Filament\Panel; - -public function panel(Panel $panel): Panel -{ - return $panel - // ... - ->brandName(new HtmlString('Filament <i>Demo</i>'); -} -``` - To render an image instead, you can pass a URL to the `brandLogo()` method: ```php From 14e8bcb9f7336e7a9706a78df8afd024eded765f Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 09:42:10 +0000 Subject: [PATCH 52/87] Update PageTest.php --- tests/src/Panels/Pages/PageTest.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/src/Panels/Pages/PageTest.php b/tests/src/Panels/Pages/PageTest.php index 6317967627..f7d6cc424c 100644 --- a/tests/src/Panels/Pages/PageTest.php +++ b/tests/src/Panels/Pages/PageTest.php @@ -1,11 +1,9 @@ <?php -use Filament\Facades\Filament; use Filament\Notifications\Notification; use Filament\Pages\Page; use Filament\Tests\Panels\Fixtures\Pages\Settings; use Filament\Tests\Panels\Pages\TestCase; -use Illuminate\Support\HtmlString; use Illuminate\Validation\ValidationException; use function Filament\Tests\livewire; @@ -37,13 +35,3 @@ it('can report validation errors', function () { ->assertHasErrors(['name' => ['required']]) ->assertNotified(); }); - -it('strips html tags from brand name in title tag', function () { - $htmlBrandName = '<span>Filament <i>HTML Title</i></span>'; - - Filament::getCurrentPanel()->brandName(new HtmlString($htmlBrandName)); - - $this->get(Settings::getUrl()) - ->assertSee('Filament HTML Title') - ->assertDontSee($htmlBrandName); -}); From e2e1fe203519bf489570dd1ff62ca964133ddd37 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 09:49:53 +0000 Subject: [PATCH 53/87] Update Importer.php --- packages/actions/src/Imports/Importer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/actions/src/Imports/Importer.php b/packages/actions/src/Imports/Importer.php index 0886127b85..42d81fe77f 100644 --- a/packages/actions/src/Imports/Importer.php +++ b/packages/actions/src/Imports/Importer.php @@ -191,7 +191,7 @@ abstract class Importer continue; } - if (array_key_exists($columnName, $this->columnMap) && blank($this->columnMap[$columnName])) { + if (blank($this->columnMap[$columnName] ?? null)) { continue; } From 4323ede70c1d5504e96fd81d758678ad099ca8d6 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 09:52:15 +0000 Subject: [PATCH 54/87] Update Importer.php --- packages/actions/src/Imports/Importer.php | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/actions/src/Imports/Importer.php b/packages/actions/src/Imports/Importer.php index 42d81fe77f..8f21b3c789 100644 --- a/packages/actions/src/Imports/Importer.php +++ b/packages/actions/src/Imports/Importer.php @@ -80,7 +80,12 @@ abstract class Importer foreach ($this->getCachedColumns() as $column) { $columnName = $column->getName(); - $rowColumnName = $this->columnMap[$columnName] ?? null; + + if (blank($this->columnMap[$columnName] ?? null)) { + continue; + } + + $rowColumnName = $this->columnMap[$columnName]; if (! array_key_exists($rowColumnName, $this->data)) { continue; @@ -141,6 +146,10 @@ abstract class Importer foreach ($this->getCachedColumns() as $column) { $columnName = $column->getName(); + if (blank($this->columnMap[$columnName] ?? null)) { + continue; + } + $rules[$columnName] = $column->getDataValidationRules(); if ( @@ -170,13 +179,19 @@ abstract class Importer $attributes = []; foreach ($this->getCachedColumns() as $column) { + $columnName = $column->getName(); + + if (blank($this->columnMap[$columnName] ?? null)) { + continue; + } + $validationAttribute = $column->getValidationAttribute(); if (blank($validationAttribute)) { continue; } - $attributes[$column->getName()] = $validationAttribute; + $attributes[$columnName] = $validationAttribute; } return $attributes; @@ -187,11 +202,11 @@ abstract class Importer foreach ($this->getCachedColumns() as $column) { $columnName = $column->getName(); - if (! array_key_exists($columnName, $this->data)) { + if (blank($this->columnMap[$columnName] ?? null)) { continue; } - if (blank($this->columnMap[$columnName] ?? null)) { + if (! array_key_exists($columnName, $this->data)) { continue; } From e7ba9f0fa78dad9c110a38a185be897d35661979 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 09:58:15 +0000 Subject: [PATCH 55/87] fix --- .../panels/src/Resources/Pages/EditRecord.php | 17 +++++++++-------- .../panels/src/Resources/Pages/ViewRecord.php | 14 ++++++++------ ...asTranslatableFormWithExistingRecordData.php | 5 +---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/panels/src/Resources/Pages/EditRecord.php b/packages/panels/src/Resources/Pages/EditRecord.php index 1c25e22a26..59d433a003 100644 --- a/packages/panels/src/Resources/Pages/EditRecord.php +++ b/packages/panels/src/Resources/Pages/EditRecord.php @@ -82,22 +82,23 @@ class EditRecord extends Page protected function fillForm(): void { - $this->callHook('beforeFill'); - - $data = $this->getRecord()->attributesToArray(); - /** @internal Read the DocBlock above the following method. */ - $this->fillFormWithDataAndCallHooks($data); + $this->fillFormWithDataAndCallHooks($this->getRecord()); } /** * @internal Never override or call this method. If you completely override `fillForm()`, copy the contents of this method into your override. * - * @param array<string, mixed> $data + * @param array<string, mixed> $extraData */ - protected function fillFormWithDataAndCallHooks(array $data): void + protected function fillFormWithDataAndCallHooks(Model $record, array $extraData = []): void { - $data = $this->mutateFormDataBeforeFill($data); + $this->callHook('beforeFill'); + + $data = $this->mutateFormDataBeforeFill([ + ...$record->attributesToArray(), + ...$extraData, + ]); $this->form->fill($data); diff --git a/packages/panels/src/Resources/Pages/ViewRecord.php b/packages/panels/src/Resources/Pages/ViewRecord.php index b086ee74bb..71735d6940 100644 --- a/packages/panels/src/Resources/Pages/ViewRecord.php +++ b/packages/panels/src/Resources/Pages/ViewRecord.php @@ -13,6 +13,7 @@ use Filament\Infolists\Infolist; use Filament\Pages\Concerns\InteractsWithFormActions; use Filament\Support\Facades\FilamentIcon; use Illuminate\Contracts\Support\Htmlable; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Arr; /** @@ -76,22 +77,23 @@ class ViewRecord extends Page protected function fillForm(): void { - $data = $this->getRecord()->attributesToArray(); - /** @internal Read the DocBlock above the following method. */ - $this->fillFormWithDataAndCallHooks($data); + $this->fillFormWithDataAndCallHooks($this->getRecord()); } /** * @internal Never override or call this method. If you completely override `fillForm()`, copy the contents of this method into your override. * - * @param array<string, mixed> $data + * @param array<string, mixed> $extraData */ - protected function fillFormWithDataAndCallHooks(array $data): void + protected function fillFormWithDataAndCallHooks(Model $record, array $extraData = []): void { $this->callHook('beforeFill'); - $data = $this->mutateFormDataBeforeFill($data); + $data = $this->mutateFormDataBeforeFill([ + ...$record->attributesToArray(), + ...$extraData, + ]); $this->form->fill($data); diff --git a/packages/spatie-laravel-translatable-plugin/src/Resources/Pages/Concerns/HasTranslatableFormWithExistingRecordData.php b/packages/spatie-laravel-translatable-plugin/src/Resources/Pages/Concerns/HasTranslatableFormWithExistingRecordData.php index 2e8304ca72..f727d66f11 100644 --- a/packages/spatie-laravel-translatable-plugin/src/Resources/Pages/Concerns/HasTranslatableFormWithExistingRecordData.php +++ b/packages/spatie-laravel-translatable-plugin/src/Resources/Pages/Concerns/HasTranslatableFormWithExistingRecordData.php @@ -30,10 +30,7 @@ trait HasTranslatableFormWithExistingRecordData } /** @internal Read the DocBlock above the following method. */ - $this->fillFormWithDataAndCallHooks([ - ...$record->attributesToArray(), - ...$translatedData, - ]); + $this->fillFormWithDataAndCallHooks($record, $translatedData); } } From 6dbd441d5665c7ae8f3de82c9235a274402d64e2 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 10:04:11 +0000 Subject: [PATCH 56/87] Update item.blade.php --- .../views/components/dropdown/list/item.blade.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/support/resources/views/components/dropdown/list/item.blade.php b/packages/support/resources/views/components/dropdown/list/item.blade.php index fe51d947f8..647071fa1b 100644 --- a/packages/support/resources/views/components/dropdown/list/item.blade.php +++ b/packages/support/resources/views/components/dropdown/list/item.blade.php @@ -45,6 +45,8 @@ ) => $color !== 'gray', ]); + $iconColor ??= $color; + $iconClasses = \Illuminate\Support\Arr::toCssClasses([ 'fi-dropdown-list-item-icon', match ($iconSize) { @@ -53,7 +55,7 @@ IconSize::Large, 'lg' => 'h-6 w-6', default => $iconSize, }, - match ($iconColor ?? $color) { + match ($iconColor) { 'gray' => 'text-gray-400 dark:text-gray-500', default => 'text-custom-500 dark:text-custom-400', }, @@ -61,10 +63,10 @@ $iconStyles = \Illuminate\Support\Arr::toCssStyles([ \Filament\Support\get_color_css_variables( - $iconColor ?? $color, + $iconColor, shades: [400, 500], alias: 'dropdown.list.item.icon', - ) => ($iconColor ?? $color) !== 'gray', + ) => ($iconColor) !== 'gray', ]); $imageClasses = 'fi-dropdown-list-item-image h-5 w-5 rounded-full bg-cover bg-center'; From e45950fff9285c6437db792ba0cfdb042de658a3 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 10:04:33 +0000 Subject: [PATCH 57/87] Update item.blade.php --- .../resources/views/components/dropdown/list/item.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/support/resources/views/components/dropdown/list/item.blade.php b/packages/support/resources/views/components/dropdown/list/item.blade.php index 647071fa1b..7026ca1162 100644 --- a/packages/support/resources/views/components/dropdown/list/item.blade.php +++ b/packages/support/resources/views/components/dropdown/list/item.blade.php @@ -66,7 +66,7 @@ $iconColor, shades: [400, 500], alias: 'dropdown.list.item.icon', - ) => ($iconColor) !== 'gray', + ) => $iconColor !== 'gray', ]); $imageClasses = 'fi-dropdown-list-item-image h-5 w-5 rounded-full bg-cover bg-center'; From db9fbb92c4b1f055e5c76ea9a7f7099ead3c3e90 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 10:06:38 +0000 Subject: [PATCH 58/87] Update 02-dropdown.md --- .../docs/09-blade-components/02-dropdown.md | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/support/docs/09-blade-components/02-dropdown.md b/packages/support/docs/09-blade-components/02-dropdown.md index ae3ade4017..f1cb0c778a 100644 --- a/packages/support/docs/09-blade-components/02-dropdown.md +++ b/packages/support/docs/09-blade-components/02-dropdown.md @@ -69,32 +69,6 @@ By default, the color of a dropdown item is "gray". You can change it to be `dan </x-filament::dropdown.list.item> ``` -## Changing the icon color of a dropdown item - -By default, the icon color of a dropdown item is "gray". You can change it to be `danger`, `info`, `primary`, `success` or `warning` by using the `iconColor` attribute: - -```blade -<x-filament::dropdown.list.item iconColor="danger"> - Edit -</x-filament::dropdown.list.item> - -<x-filament::dropdown.list.item iconColor="info"> - Edit -</x-filament::dropdown.list.item> - -<x-filament::dropdown.list.item iconColor="primary"> - Edit -</x-filament::dropdown.list.item> - -<x-filament::dropdown.list.item iconColor="success"> - Edit -</x-filament::dropdown.list.item> - -<x-filament::dropdown.list.item iconColor="warning"> - Edit -</x-filament::dropdown.list.item> -``` - ## Adding an icon to a dropdown item You can add an [icon](https://blade-ui-kit.com/blade-icons?set=1#search) to a dropdown item by using the `icon` attribute: @@ -105,6 +79,32 @@ You can add an [icon](https://blade-ui-kit.com/blade-icons?set=1#search) to a dr </x-filament::dropdown.list.item> ``` +### Changing the icon color of a dropdown item + +By default, the icon color uses the [same color as the item itself](#changing-the-color-of-a-dropdown-item). You can override it to be `danger`, `info`, `primary`, `success` or `warning` by using the `icon-color` attribute: + +```blade +<x-filament::dropdown.list.item icon="heroicon-m-pencil" icon-color="danger"> + Edit +</x-filament::dropdown.list.item> + +<x-filament::dropdown.list.item icon="heroicon-m-pencil" icon-color="info"> + Edit +</x-filament::dropdown.list.item> + +<x-filament::dropdown.list.item icon="heroicon-m-pencil" icon-color="primary"> + Edit +</x-filament::dropdown.list.item> + +<x-filament::dropdown.list.item icon="heroicon-m-pencil" icon-color="success"> + Edit +</x-filament::dropdown.list.item> + +<x-filament::dropdown.list.item icon="heroicon-m-pencil" icon-color="warning"> + Edit +</x-filament::dropdown.list.item> +``` + ## Adding an image to a dropdown item You can add a circular image to a dropdown item by using the `image` attribute: From 80cf5f5184fd1de23b45a4ebff19f6a9ab4d26d6 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 10:08:26 +0000 Subject: [PATCH 59/87] cs --- packages/actions/resources/lang/fr/export.php | 1 - packages/actions/src/Imports/Importer.php | 2 +- packages/panels/resources/lang/ro/pages/dashboard.php | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/actions/resources/lang/fr/export.php b/packages/actions/resources/lang/fr/export.php index 6b671323d6..89bb1c959e 100644 --- a/packages/actions/resources/lang/fr/export.php +++ b/packages/actions/resources/lang/fr/export.php @@ -1,6 +1,5 @@ <?php - return [ 'label' => 'Exporter :label', diff --git a/packages/actions/src/Imports/Importer.php b/packages/actions/src/Imports/Importer.php index 8f21b3c789..69c45852e5 100644 --- a/packages/actions/src/Imports/Importer.php +++ b/packages/actions/src/Imports/Importer.php @@ -80,7 +80,7 @@ abstract class Importer foreach ($this->getCachedColumns() as $column) { $columnName = $column->getName(); - + if (blank($this->columnMap[$columnName] ?? null)) { continue; } diff --git a/packages/panels/resources/lang/ro/pages/dashboard.php b/packages/panels/resources/lang/ro/pages/dashboard.php index 2534e8777b..ab7130495b 100644 --- a/packages/panels/resources/lang/ro/pages/dashboard.php +++ b/packages/panels/resources/lang/ro/pages/dashboard.php @@ -30,5 +30,4 @@ return [ ], - ]; From 0a8ecb2ea18e57a7f292b77dfc9724d94c3d18d1 Mon Sep 17 00:00:00 2001 From: Zep Fietje <hey@zepfietje.com> Date: Tue, 20 Feb 2024 22:01:11 +0100 Subject: [PATCH 60/87] Fix docs spelling --- packages/forms/docs/03-fields/12-repeater.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/forms/docs/03-fields/12-repeater.md b/packages/forms/docs/03-fields/12-repeater.md index 90d3a2a068..a3e3cd10f2 100644 --- a/packages/forms/docs/03-fields/12-repeater.md +++ b/packages/forms/docs/03-fields/12-repeater.md @@ -234,7 +234,7 @@ Repeater::make('qualifications') ### Reordering items in a relationship -By default, [reordering](#reordering-items) relationship repeater items is disabled. This is because your related model needs an `sort` column to store the order of related records. To enable reordering, you may use the `orderColumn()` method, passing in a name of the column on your related model to store the order in: +By default, [reordering](#reordering-items) relationship repeater items is disabled. This is because your related model needs a `sort` column to store the order of related records. To enable reordering, you may use the `orderColumn()` method, passing in a name of the column on your related model to store the order in: ```php use Filament\Forms\Components\Repeater; @@ -287,7 +287,7 @@ class OrderProduct extends Pivot { return $this->belongsTo(Order::class); } - + public function product(): BelongsTo { return $this->belongsTo(Product::class); @@ -634,7 +634,7 @@ Repeater::make('members') ->icon('heroicon-m-envelope') ->action(function (array $arguments, Repeater $component): void { $itemData = $component->getItemState($arguments['item']); - + Mail::to($itemData['email']) ->send( // ... From f33e1438400e23349dc098d2e16c2fdfa904dbd7 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 23:31:22 +0000 Subject: [PATCH 61/87] cs --- .../views/columns/image-column.blade.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/tables/resources/views/columns/image-column.blade.php b/packages/tables/resources/views/columns/image-column.blade.php index 3c1df7c846..c496839afa 100644 --- a/packages/tables/resources/views/columns/image-column.blade.php +++ b/packages/tables/resources/views/columns/image-column.blade.php @@ -10,15 +10,15 @@ $height = $getHeight() ?? ($isStacked ? '2rem' : '2.5rem'); $width = $getWidth() ?? (($isCircular || $isSquare) ? $height : null); - $countState = count($state); - $countLimitedState = count($limitedState); + $stateCount = count($state); + $limitedStateCount = count($limitedState); $defaultImageUrl = $getDefaultImageUrl(); - if ((! $countLimitedState) && filled($defaultImageUrl)) { + if ((! $limitedStateCount) && filled($defaultImageUrl)) { $limitedState = [null]; - $countLimitedState = 1; + $limitedStateCount = 1; } $ringClasses = \Illuminate\Support\Arr::toCssClasses([ @@ -33,7 +33,7 @@ }, ]); - $hasLimitedRemainingText = $hasLimitedRemainingText(); + $hasLimitedRemainingText = $hasLimitedRemainingText() && ($limitedStateCount < $stateCount); $isLimitedRemainingTextSeparate = $isLimitedRemainingTextSeparate(); $limitedRemainingTextSizeClasses = match ($getLimitedRemainingTextSize()) { @@ -55,7 +55,7 @@ ]) }} > - @if ($countLimitedState) + @if ($limitedStateCount) <div class="flex items-center gap-x-2.5"> <div @class([ @@ -93,7 +93,7 @@ /> @endforeach - @if ($hasLimitedRemainingText && ($countLimitedState < $countState) && (! $isLimitedRemainingTextSeparate) && $isCircular) + @if ($hasLimitedRemainingText && (! $isLimitedRemainingTextSeparate) && $isCircular) <div style=" @if ($height) height: {{ $height }}; @endif @@ -111,20 +111,20 @@ ]) > <span class="-ms-0.5"> - +{{ $countState - $countLimitedState }} + +{{ $stateCount - $limitedStateCount }} </span> </div> @endif </div> - @if ($hasLimitedRemainingText && ($countLimitedState < $countState) && ($isLimitedRemainingTextSeparate || (! $isCircular))) + @if ($hasLimitedRemainingText && ($isLimitedRemainingTextSeparate || (! $isCircular))) <div @class([ 'font-medium text-gray-500 dark:text-gray-400', $limitedRemainingTextSizeClasses, ]) > - +{{ $countState - $countLimitedState }} + +{{ $stateCount - $limitedStateCount }} </div> @endif </div> From 81920210f8ed72c1317033d6494fbdf6471cdccc Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 23:32:55 +0000 Subject: [PATCH 62/87] Update image-entry.blade.php --- .../views/components/image-entry.blade.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/infolists/resources/views/components/image-entry.blade.php b/packages/infolists/resources/views/components/image-entry.blade.php index cb9ffd5dca..30f3ba280b 100644 --- a/packages/infolists/resources/views/components/image-entry.blade.php +++ b/packages/infolists/resources/views/components/image-entry.blade.php @@ -11,10 +11,15 @@ $height = $getHeight() ?? ($isStacked ? '2.5rem' : '8rem'); $width = $getWidth() ?? (($isCircular || $isSquare) ? $height : null); + $stateCount = count($state); + $limitedStateCount = count($limitedState); + $defaultImageUrl = $getDefaultImageUrl(); - if ((! count($limitedState)) && filled($defaultImageUrl)) { + if ((! $limitedStateCount) && filled($defaultImageUrl)) { $limitedState = [null]; + + $limitedStateCount = 1; } $ringClasses = \Illuminate\Support\Arr::toCssClasses([ @@ -29,7 +34,7 @@ }, ]); - $hasLimitedRemainingText = $hasLimitedRemainingText(); + $hasLimitedRemainingText = $hasLimitedRemainingText() && ($limitedStateCount < $stateCount); $isLimitedRemainingTextSeparate = $isLimitedRemainingTextSeparate(); $limitedRemainingTextSizeClasses = match ($getLimitedRemainingTextSize()) { @@ -50,7 +55,7 @@ ]) }} > - @if (count($limitedState)) + @if ($limitedStateCount) <div @class([ 'flex flex-wrap', @@ -86,7 +91,7 @@ /> @endforeach - @if ($hasLimitedRemainingText && ($loop->iteration < count($limitedState)) && (! $isLimitedRemainingTextSeparate) && $isCircular) + @if ($hasLimitedRemainingText && (! $isLimitedRemainingTextSeparate) && $isCircular) <div style=" @if ($height) height: {{ $height }}; @endif @@ -104,20 +109,20 @@ ]) > <span class="-ms-0.5"> - +{{ count($state) - count($limitedState) }} + +{{ $stateCount - $limitedStateCount }} </span> </div> @endif </div> - @if ($hasLimitedRemainingText && ($loop->iteration < count($limitedState)) && ($isLimitedRemainingTextSeparate || (! $isCircular))) + @if ($hasLimitedRemainingText && ($isLimitedRemainingTextSeparate || (! $isCircular))) <div @class([ 'font-medium text-gray-500 dark:text-gray-400', $limitedRemainingTextSizeClasses, ]) > - +{{ count($state) - count($limitedState) }} + +{{ $stateCount - $limitedStateCount }} </div> @endif @elseif (($placeholder = $getPlaceholder()) !== null) From 6ccbb29c8ce464b0dc264658c59a5f1f6006ba23 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Tue, 20 Feb 2024 23:54:08 +0000 Subject: [PATCH 63/87] Update ColumnGroup.php --- packages/tables/src/Columns/ColumnGroup.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/tables/src/Columns/ColumnGroup.php b/packages/tables/src/Columns/ColumnGroup.php index 8ec8a93a7e..a9876cc896 100644 --- a/packages/tables/src/Columns/ColumnGroup.php +++ b/packages/tables/src/Columns/ColumnGroup.php @@ -78,7 +78,7 @@ class ColumnGroup extends Component } /** - * @return array<Column> + * @return array<string, Column> */ public function getColumns(): array { @@ -90,7 +90,7 @@ class ColumnGroup extends Component } /** - * @return array<Column> + * @return array<string, Column> */ public function getVisibleColumns(): array { From 63f1a1ef9a6bc2607205971af9a1da1259f71548 Mon Sep 17 00:00:00 2001 From: Saade <saade@outlook.com.br> Date: Wed, 21 Feb 2024 17:56:43 -0300 Subject: [PATCH 64/87] fix:`cache-components` command on windows --- packages/panels/src/Panel/Concerns/HasComponents.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/panels/src/Panel/Concerns/HasComponents.php b/packages/panels/src/Panel/Concerns/HasComponents.php index d76ad93626..cbfd832e72 100644 --- a/packages/panels/src/Panel/Concerns/HasComponents.php +++ b/packages/panels/src/Panel/Concerns/HasComponents.php @@ -671,6 +671,6 @@ trait HasComponents public function getComponentCachePath(): string { - return (config('filament.cache_path') ?? base_path('bootstrap/cache/filament')) . DIRECTORY_SEPARATOR . "panels/{$this->getId()}.php"; + return (config('filament.cache_path') ?? base_path('bootstrap/cache/filament')) . DIRECTORY_SEPARATOR . "panels" . DIRECTORY_SEPARATOR . "{$this->getId()}.php"; } } From e0614e399a07c510ed41da4e079ce6d2fc35f46d Mon Sep 17 00:00:00 2001 From: saade <saade@users.noreply.github.com> Date: Wed, 21 Feb 2024 21:03:18 +0000 Subject: [PATCH 65/87] chore: fix code style --- packages/panels/src/Panel/Concerns/HasComponents.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/panels/src/Panel/Concerns/HasComponents.php b/packages/panels/src/Panel/Concerns/HasComponents.php index cbfd832e72..69d2c77747 100644 --- a/packages/panels/src/Panel/Concerns/HasComponents.php +++ b/packages/panels/src/Panel/Concerns/HasComponents.php @@ -671,6 +671,6 @@ trait HasComponents public function getComponentCachePath(): string { - return (config('filament.cache_path') ?? base_path('bootstrap/cache/filament')) . DIRECTORY_SEPARATOR . "panels" . DIRECTORY_SEPARATOR . "{$this->getId()}.php"; + return (config('filament.cache_path') ?? base_path('bootstrap/cache/filament')) . DIRECTORY_SEPARATOR . 'panels' . DIRECTORY_SEPARATOR . "{$this->getId()}.php"; } } From 6eeffd74d34f0ad2c544578406ec321e03916a40 Mon Sep 17 00:00:00 2001 From: Adel Ali <3adeling@gmail.com> Date: Thu, 22 Feb 2024 11:31:01 +0300 Subject: [PATCH 66/87] Update .stubs.php replace `use Clousure;` to be after namespace --- packages/forms/.stubs.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/forms/.stubs.php b/packages/forms/.stubs.php index 6b5032dee5..3af0d92a4b 100644 --- a/packages/forms/.stubs.php +++ b/packages/forms/.stubs.php @@ -1,10 +1,9 @@ <?php -use Closure; - namespace Livewire\Features\SupportTesting { use Illuminate\Support\Collection; + use Closure; class Testable { public function fillForm(array $state = [], string $formName = 'form'): static {} From 48a5fc7cb300ef75eea0a46e278479e0b1028d08 Mon Sep 17 00:00:00 2001 From: wychoong <67364036+wychoong@users.noreply.github.com> Date: Thu, 22 Feb 2024 18:59:35 +0800 Subject: [PATCH 67/87] Fix: default theme mode not respected for pages before login --- packages/panels/resources/js/index.js | 6 +++++- .../panels/resources/views/components/layout/base.blade.php | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/panels/resources/js/index.js b/packages/panels/resources/js/index.js index 68ba9458d7..619729e70e 100644 --- a/packages/panels/resources/js/index.js +++ b/packages/panels/resources/js/index.js @@ -37,7 +37,11 @@ document.addEventListener('alpine:init', () => { }, }) - const theme = localStorage.getItem('theme') ?? 'system' + const theme = + localStorage.getItem('theme') ?? + getComputedStyle(document.documentElement).getPropertyValue( + '--default-theme-mode', + ) window.Alpine.store( 'theme', diff --git a/packages/panels/resources/views/components/layout/base.blade.php b/packages/panels/resources/views/components/layout/base.blade.php index 220f262d7f..a9a8aadfca 100644 --- a/packages/panels/resources/views/components/layout/base.blade.php +++ b/packages/panels/resources/views/components/layout/base.blade.php @@ -59,6 +59,7 @@ --font-family: '{!! filament()->getFontFamily() !!}'; --sidebar-width: {{ filament()->getSidebarWidth() }}; --collapsed-sidebar-width: {{ filament()->getCollapsedSidebarWidth() }}; + --default-theme-mode: {{ filament()->getDefaultThemeMode()->value }}; } </style> From 91bc4113a6a4b6f08e8eb98b1f57a3adbfb65f32 Mon Sep 17 00:00:00 2001 From: Rodrigo Fantuci <rfantuciq@gmail.com> Date: Thu, 22 Feb 2024 22:24:50 -0400 Subject: [PATCH 68/87] Fix docs link --- packages/forms/docs/04-layout/08-custom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/forms/docs/04-layout/08-custom.md b/packages/forms/docs/04-layout/08-custom.md index 5161b59029..2e5df2c491 100644 --- a/packages/forms/docs/04-layout/08-custom.md +++ b/packages/forms/docs/04-layout/08-custom.md @@ -26,7 +26,7 @@ This assumes that you have a `resources/views/filament/forms/components/wizard.b You may create your own custom component classes and views, which you can reuse across your project, and even release as a plugin to the community. -> If you're just creating a simple custom component to use once, you could instead use a [view component](#view) to render any custom Blade file. +> If you're just creating a simple custom component to use once, you could instead use a [view component](#view-components) to render any custom Blade file. To create a custom column class and view, you may use the following command: From acedf55c93270b94ad02c7f04eec056d8ddb2f2f Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 11:47:31 +0000 Subject: [PATCH 69/87] feature: Database transactions --- .../Concerns/CanUseDatabaseTransactions.php | 50 +++++++++++++++++++ .../src/Concerns/InteractsWithActions.php | 18 +++++++ packages/actions/src/CreateAction.php | 2 + packages/actions/src/EditAction.php | 2 + packages/actions/src/MountableAction.php | 9 ++-- .../src/Concerns/HasFormComponentActions.php | 18 +++++++ .../src/Concerns/InteractsWithInfolists.php | 18 +++++++ .../panels/src/Pages/Auth/EditProfile.php | 14 ++++++ packages/panels/src/Pages/Auth/Register.php | 7 ++- .../src/Pages/Tenancy/EditTenantProfile.php | 14 ++++++ .../src/Pages/Tenancy/RegisterTenant.php | 14 ++++++ .../src/Resources/Pages/CreateRecord.php | 14 ++++++ .../panels/src/Resources/Pages/EditRecord.php | 14 ++++++ .../src/Pages/SettingsPage.php | 14 ++++++ packages/support/src/Exceptions/Cancel.php | 13 +++++ packages/support/src/Exceptions/Halt.php | 13 +++++ packages/tables/src/Actions/CreateAction.php | 2 + packages/tables/src/Actions/EditAction.php | 2 + packages/tables/src/Concerns/HasActions.php | 18 +++++++ .../tables/src/Concerns/HasBulkActions.php | 18 +++++++ 20 files changed, 268 insertions(+), 6 deletions(-) create mode 100644 packages/actions/src/Concerns/CanUseDatabaseTransactions.php diff --git a/packages/actions/src/Concerns/CanUseDatabaseTransactions.php b/packages/actions/src/Concerns/CanUseDatabaseTransactions.php new file mode 100644 index 0000000000..4ea621ddf7 --- /dev/null +++ b/packages/actions/src/Concerns/CanUseDatabaseTransactions.php @@ -0,0 +1,50 @@ +<?php + +namespace Filament\Actions\Concerns; + +use Closure; +use Illuminate\Support\Facades\DB; + +trait CanUseDatabaseTransactions +{ + protected bool | Closure $hasDatabaseTransactions = false; + + public function databaseTransaction(bool | Closure $condition = true): static + { + $this->hasDatabaseTransactions = $condition; + + return $this; + } + + public function hasDatabaseTransactions(): bool + { + return (bool) $this->evaluate($this->hasDatabaseTransactions); + } + + public function beginDatabaseTransaction(): void + { + if (! $this->hasDatabaseTransactions()) { + return; + } + + DB::beginTransaction(); + } + + public function commitDatabaseTransaction(): void + { + if (! $this->hasDatabaseTransactions()) { + return; + } + + DB::commit(); + } + + public function rollBackDatabaseTransaction(): void + { + if (! $this->hasDatabaseTransactions()) { + return; + } + + DB::rollBack(); + } +} diff --git a/packages/actions/src/Concerns/InteractsWithActions.php b/packages/actions/src/Concerns/InteractsWithActions.php index 80c417fe02..4af3dc1746 100644 --- a/packages/actions/src/Concerns/InteractsWithActions.php +++ b/packages/actions/src/Concerns/InteractsWithActions.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Validation\ValidationException; use InvalidArgumentException; use Livewire\Attributes\Url; +use Throwable; use function Livewire\store; @@ -79,6 +80,8 @@ trait InteractsWithActions $originallyMountedActions = $this->mountedActions; try { + $action->beginDatabaseTransaction(); + if ($this->mountedActionHasForm()) { $action->callBeforeFormValidated(); @@ -96,10 +99,21 @@ trait InteractsWithActions $result = $action->callAfter() ?? $result; $this->afterActionCalled(); + + $action->commitDatabaseTransaction(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $action->rollBackDatabaseTransaction() : + $action->commitDatabaseTransaction(); + return null; } catch (Cancel $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $action->rollBackDatabaseTransaction() : + $action->commitDatabaseTransaction(); } catch (ValidationException $exception) { + $action->rollBackDatabaseTransaction(); + if (! $this->mountedActionShouldOpenModal()) { $action->resetArguments(); $action->resetFormData(); @@ -107,6 +121,10 @@ trait InteractsWithActions $this->unmountAction(); } + throw $exception; + } catch (Throwable $exception) { + $action->rollBackDatabaseTransaction(); + throw $exception; } diff --git a/packages/actions/src/CreateAction.php b/packages/actions/src/CreateAction.php index 7d1887dde0..d06b0de9ad 100644 --- a/packages/actions/src/CreateAction.php +++ b/packages/actions/src/CreateAction.php @@ -47,6 +47,8 @@ class CreateAction extends Action $this->record(null); + $this->databaseTransaction(); + $this->action(function (array $arguments, Form $form): void { $model = $this->getModel(); diff --git a/packages/actions/src/EditAction.php b/packages/actions/src/EditAction.php index 3b19cbd0a7..090ab208c4 100644 --- a/packages/actions/src/EditAction.php +++ b/packages/actions/src/EditAction.php @@ -47,6 +47,8 @@ class EditAction extends Action return $data; }); + $this->databaseTransaction(); + $this->action(function (): void { $this->process(function (array $data, HasActions $livewire, Model $record) { if ($translatableContentDriver = $livewire->makeFilamentTranslatableContentDriver()) { diff --git a/packages/actions/src/MountableAction.php b/packages/actions/src/MountableAction.php index 60ef7929f2..260378a452 100644 --- a/packages/actions/src/MountableAction.php +++ b/packages/actions/src/MountableAction.php @@ -15,6 +15,7 @@ abstract class MountableAction extends StaticAction implements HasLivewire use Concerns\CanOpenModal; use Concerns\CanRedirect; use Concerns\CanRequireConfirmation; + use Concerns\CanUseDatabaseTransactions; use Concerns\HasForm; use Concerns\HasInfolist; use Concerns\HasLifecycleHooks; @@ -39,14 +40,14 @@ abstract class MountableAction extends StaticAction implements HasLivewire return $this->evaluate($this->getActionFunction(), $parameters); } - public function cancel(): void + public function cancel(bool $shouldRollBackDatabaseTransaction = false): void { - throw new Cancel(); + throw (new Cancel())->rollBackDatabaseTransaction($shouldRollBackDatabaseTransaction); } - public function halt(): void + public function halt(bool $shouldRollBackDatabaseTransaction = false): void { - throw new Halt(); + throw (new Halt())->rollBackDatabaseTransaction($shouldRollBackDatabaseTransaction); } /** diff --git a/packages/forms/src/Concerns/HasFormComponentActions.php b/packages/forms/src/Concerns/HasFormComponentActions.php index 32f7aa951e..1e3af14fb4 100644 --- a/packages/forms/src/Concerns/HasFormComponentActions.php +++ b/packages/forms/src/Concerns/HasFormComponentActions.php @@ -9,6 +9,7 @@ use Filament\Forms\Form; use Filament\Support\Exceptions\Cancel; use Filament\Support\Exceptions\Halt; use Illuminate\Validation\ValidationException; +use Throwable; use function Livewire\store; @@ -59,6 +60,8 @@ trait HasFormComponentActions $result = null; try { + $action->beginDatabaseTransaction(); + if ($this->mountedFormComponentActionHasForm()) { $action->callBeforeFormValidated(); @@ -74,10 +77,21 @@ trait HasFormComponentActions ]); $result = $action->callAfter() ?? $result; + + $action->commitDatabaseTransaction(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $action->rollBackDatabaseTransaction() : + $action->commitDatabaseTransaction(); + return null; } catch (Cancel $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $action->rollBackDatabaseTransaction() : + $action->commitDatabaseTransaction(); } catch (ValidationException $exception) { + $action->rollBackDatabaseTransaction(); + if (! $this->mountedFormComponentActionShouldOpenModal()) { $action->resetArguments(); $action->resetFormData(); @@ -85,6 +99,10 @@ trait HasFormComponentActions $this->unmountFormComponentAction(); } + throw $exception; + } catch (Throwable $exception) { + $action->rollBackDatabaseTransaction(); + throw $exception; } diff --git a/packages/infolists/src/Concerns/InteractsWithInfolists.php b/packages/infolists/src/Concerns/InteractsWithInfolists.php index 2ffe64f70f..dda99d1f70 100644 --- a/packages/infolists/src/Concerns/InteractsWithInfolists.php +++ b/packages/infolists/src/Concerns/InteractsWithInfolists.php @@ -14,6 +14,7 @@ use Filament\Support\Exceptions\Cancel; use Filament\Support\Exceptions\Halt; use Filament\Tables\Contracts\HasTable; use Illuminate\Validation\ValidationException; +use Throwable; use function Livewire\store; @@ -103,6 +104,8 @@ trait InteractsWithInfolists $result = null; try { + $action->beginDatabaseTransaction(); + if ($this->mountedInfolistActionHasForm()) { $action->callBeforeFormValidated(); @@ -118,10 +121,21 @@ trait InteractsWithInfolists ]); $result = $action->callAfter() ?? $result; + + $action->commitDatabaseTransaction(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $action->rollBackDatabaseTransaction() : + $action->commitDatabaseTransaction(); + return null; } catch (Cancel $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $action->rollBackDatabaseTransaction() : + $action->commitDatabaseTransaction(); } catch (ValidationException $exception) { + $action->rollBackDatabaseTransaction(); + if (! $this->mountedInfolistActionShouldOpenModal()) { $action->resetArguments(); $action->resetFormData(); @@ -129,6 +143,10 @@ trait InteractsWithInfolists $this->unmountInfolistAction(); } + throw $exception; + } catch (Throwable $exception) { + $action->rollBackDatabaseTransaction(); + throw $exception; } diff --git a/packages/panels/src/Pages/Auth/EditProfile.php b/packages/panels/src/Pages/Auth/EditProfile.php index 283051cb5c..928e2bb730 100644 --- a/packages/panels/src/Pages/Auth/EditProfile.php +++ b/packages/panels/src/Pages/Auth/EditProfile.php @@ -21,9 +21,11 @@ use Filament\Support\Facades\FilamentView; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Route; use Illuminate\Validation\Rules\Password; +use Throwable; use function Filament\Support\is_app_url; @@ -143,6 +145,8 @@ class EditProfile extends Page public function save(): void { try { + DB::beginTransaction(); + $this->callHook('beforeValidate'); $data = $this->form->getState(); @@ -156,8 +160,18 @@ class EditProfile extends Page $this->handleRecordUpdate($this->getUser(), $data); $this->callHook('afterSave'); + + DB::commit(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + DB::rollBack() : + DB::commit(); + return; + } catch (Throwable $exception) { + DB::rollBack(); + + throw $exception; } if (request()->hasSession() && array_key_exists('password', $data)) { diff --git a/packages/panels/src/Pages/Auth/Register.php b/packages/panels/src/Pages/Auth/Register.php index e7d30b14ab..70a63c1c05 100644 --- a/packages/panels/src/Pages/Auth/Register.php +++ b/packages/panels/src/Pages/Auth/Register.php @@ -22,6 +22,7 @@ use Illuminate\Auth\SessionGuard; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; use Illuminate\Validation\Rules\Password; @@ -74,9 +75,11 @@ class Register extends SimplePage return null; } - $data = $this->form->getState(); + $user = DB::transaction(function () { + $data = $this->form->getState(); - $user = $this->getUserModel()::create($data); + return $this->getUserModel()::create($data); + }); event(new Registered($user)); diff --git a/packages/panels/src/Pages/Tenancy/EditTenantProfile.php b/packages/panels/src/Pages/Tenancy/EditTenantProfile.php index 5e52a770dc..907e8feda1 100644 --- a/packages/panels/src/Pages/Tenancy/EditTenantProfile.php +++ b/packages/panels/src/Pages/Tenancy/EditTenantProfile.php @@ -15,7 +15,9 @@ use Filament\Support\Facades\FilamentView; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\DB; use Livewire\Attributes\Locked; +use Throwable; use function Filament\authorize; use function Filament\Support\is_app_url; @@ -108,6 +110,8 @@ abstract class EditTenantProfile extends Page public function save(): void { try { + DB::beginTransaction(); + $this->callHook('beforeValidate'); $data = $this->form->getState(); @@ -121,8 +125,18 @@ abstract class EditTenantProfile extends Page $this->handleRecordUpdate($this->tenant, $data); $this->callHook('afterSave'); + + DB::commit(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + DB::rollBack() : + DB::commit(); + return; + } catch (Throwable $exception) { + DB::rollBack(); + + throw $exception; } $this->getSavedNotification()?->send(); diff --git a/packages/panels/src/Pages/Tenancy/RegisterTenant.php b/packages/panels/src/Pages/Tenancy/RegisterTenant.php index 185a9d04ff..fcae0c1fec 100644 --- a/packages/panels/src/Pages/Tenancy/RegisterTenant.php +++ b/packages/panels/src/Pages/Tenancy/RegisterTenant.php @@ -15,6 +15,8 @@ use Filament\Support\Facades\FilamentView; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\DB; +use Throwable; use function Filament\authorize; use function Filament\Support\is_app_url; @@ -70,6 +72,8 @@ abstract class RegisterTenant extends SimplePage public function register(): void { try { + DB::beginTransaction(); + $this->callHook('beforeValidate'); $data = $this->form->getState(); @@ -85,8 +89,18 @@ abstract class RegisterTenant extends SimplePage $this->form->model($this->tenant)->saveRelationships(); $this->callHook('afterRegister'); + + DB::commit(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + DB::rollBack() : + DB::commit(); + return; + } catch (Throwable $exception) { + DB::rollBack(); + + throw $exception; } if ($redirectUrl = $this->getRedirectUrl()) { diff --git a/packages/panels/src/Resources/Pages/CreateRecord.php b/packages/panels/src/Resources/Pages/CreateRecord.php index 7c7fa838f7..04d64d98a3 100644 --- a/packages/panels/src/Resources/Pages/CreateRecord.php +++ b/packages/panels/src/Resources/Pages/CreateRecord.php @@ -14,6 +14,8 @@ use Filament\Support\Facades\FilamentView; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasManyThrough; +use Illuminate\Support\Facades\DB; +use Throwable; use function Filament\Support\is_app_url; @@ -74,6 +76,8 @@ class CreateRecord extends Page $this->authorizeAccess(); try { + DB::beginTransaction(); + $this->callHook('beforeValidate'); $data = $this->form->getState(); @@ -89,8 +93,18 @@ class CreateRecord extends Page $this->form->model($this->getRecord())->saveRelationships(); $this->callHook('afterCreate'); + + DB::commit(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + DB::rollBack() : + DB::commit(); + return; + } catch (Throwable $exception) { + DB::rollBack(); + + throw $exception; } $this->rememberData(); diff --git a/packages/panels/src/Resources/Pages/EditRecord.php b/packages/panels/src/Resources/Pages/EditRecord.php index 59d433a003..22d1c3aa58 100644 --- a/packages/panels/src/Resources/Pages/EditRecord.php +++ b/packages/panels/src/Resources/Pages/EditRecord.php @@ -20,6 +20,8 @@ use Filament\Support\Facades\FilamentView; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Arr; +use Illuminate\Support\Facades\DB; +use Throwable; use function Filament\Support\is_app_url; @@ -130,6 +132,8 @@ class EditRecord extends Page $this->authorizeAccess(); try { + DB::beginTransaction(); + $this->callHook('beforeValidate'); $data = $this->form->getState(); @@ -143,8 +147,18 @@ class EditRecord extends Page $this->handleRecordUpdate($this->getRecord(), $data); $this->callHook('afterSave'); + + DB::commit(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + DB::rollBack() : + DB::commit(); + return; + } catch (Throwable $exception) { + DB::rollBack(); + + throw $exception; } $this->rememberData(); diff --git a/packages/spatie-laravel-settings-plugin/src/Pages/SettingsPage.php b/packages/spatie-laravel-settings-plugin/src/Pages/SettingsPage.php index 2f0fe97b6b..ebb20b802b 100644 --- a/packages/spatie-laravel-settings-plugin/src/Pages/SettingsPage.php +++ b/packages/spatie-laravel-settings-plugin/src/Pages/SettingsPage.php @@ -9,6 +9,8 @@ use Filament\Forms\Form; use Filament\Notifications\Notification; use Filament\Support\Exceptions\Halt; use Filament\Support\Facades\FilamentView; +use Illuminate\Support\Facades\DB; +use Throwable; use function Filament\Support\is_app_url; @@ -58,6 +60,8 @@ class SettingsPage extends Page public function save(): void { try { + DB::beginTransaction(); + $this->callHook('beforeValidate'); $data = $this->form->getState(); @@ -74,8 +78,18 @@ class SettingsPage extends Page $settings->save(); $this->callHook('afterSave'); + + DB::commit(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + DB::rollBack() : + DB::commit(); + return; + } catch (Throwable $exception) { + DB::rollBack(); + + throw $exception; } $this->getSavedNotification()?->send(); diff --git a/packages/support/src/Exceptions/Cancel.php b/packages/support/src/Exceptions/Cancel.php index e2c615e9c7..f90c62147c 100644 --- a/packages/support/src/Exceptions/Cancel.php +++ b/packages/support/src/Exceptions/Cancel.php @@ -6,4 +6,17 @@ use Exception; class Cancel extends Exception { + protected bool $shouldRollbackDatabaseTransaction = true; + + public function rollBackDatabaseTransaction(bool $condition = true): static + { + $this->shouldRollbackDatabaseTransaction = $condition; + + return $this; + } + + public function shouldRollbackDatabaseTransaction(): bool + { + return $this->shouldRollbackDatabaseTransaction; + } } diff --git a/packages/support/src/Exceptions/Halt.php b/packages/support/src/Exceptions/Halt.php index fbc4a8cef9..078a13351e 100644 --- a/packages/support/src/Exceptions/Halt.php +++ b/packages/support/src/Exceptions/Halt.php @@ -6,4 +6,17 @@ use Exception; class Halt extends Exception { + protected bool $shouldRollbackDatabaseTransaction = false; + + public function rollBackDatabaseTransaction(bool $condition = true): static + { + $this->shouldRollbackDatabaseTransaction = $condition; + + return $this; + } + + public function shouldRollbackDatabaseTransaction(): bool + { + return $this->shouldRollbackDatabaseTransaction; + } } diff --git a/packages/tables/src/Actions/CreateAction.php b/packages/tables/src/Actions/CreateAction.php index c1d8b8adb1..5571c79b29 100644 --- a/packages/tables/src/Actions/CreateAction.php +++ b/packages/tables/src/Actions/CreateAction.php @@ -42,6 +42,8 @@ class CreateAction extends Action $this->successNotificationTitle(__('filament-actions::create.single.notifications.created.title')); + $this->databaseTransaction(); + $this->action(function (array $arguments, Form $form, HasTable $livewire): void { $model = $this->getModel(); diff --git a/packages/tables/src/Actions/EditAction.php b/packages/tables/src/Actions/EditAction.php index 625e97f642..d781ebb9a5 100644 --- a/packages/tables/src/Actions/EditAction.php +++ b/packages/tables/src/Actions/EditAction.php @@ -49,6 +49,8 @@ class EditAction extends Action return $data; }); + $this->databaseTransaction(); + $this->action(function (): void { $this->process(function (array $data, Model $record, Table $table) { $relationship = $table->getRelationship(); diff --git a/packages/tables/src/Concerns/HasActions.php b/packages/tables/src/Concerns/HasActions.php index 0662ebc3fd..1d6efed9dc 100644 --- a/packages/tables/src/Concerns/HasActions.php +++ b/packages/tables/src/Concerns/HasActions.php @@ -11,6 +11,7 @@ use Filament\Tables\Actions\ActionGroup; use Illuminate\Database\Eloquent\Model; use Illuminate\Validation\ValidationException; use Livewire\Attributes\Url; +use Throwable; use function Livewire\store; @@ -93,6 +94,8 @@ trait HasActions $originallyMountedActions = $this->mountedTableActions; try { + $action->beginDatabaseTransaction(); + if ($this->mountedTableActionHasForm()) { $action->callBeforeFormValidated(); @@ -108,10 +111,21 @@ trait HasActions ]); $result = $action->callAfter() ?? $result; + + $action->commitDatabaseTransaction(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $action->rollBackDatabaseTransaction() : + $action->commitDatabaseTransaction(); + return null; } catch (Cancel $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $action->rollBackDatabaseTransaction() : + $action->commitDatabaseTransaction(); } catch (ValidationException $exception) { + $action->rollBackDatabaseTransaction(); + if (! $this->mountedTableActionShouldOpenModal()) { $action->resetArguments(); $action->resetFormData(); @@ -119,6 +133,10 @@ trait HasActions $this->unmountTableAction(); } + throw $exception; + } catch (Throwable $exception) { + $action->rollBackDatabaseTransaction(); + throw $exception; } diff --git a/packages/tables/src/Concerns/HasBulkActions.php b/packages/tables/src/Concerns/HasBulkActions.php index 5317980e9e..3094aacc40 100644 --- a/packages/tables/src/Concerns/HasBulkActions.php +++ b/packages/tables/src/Concerns/HasBulkActions.php @@ -14,6 +14,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Illuminate\Validation\ValidationException; +use Throwable; use function Livewire\store; @@ -64,6 +65,8 @@ trait HasBulkActions $originallyMountedAction = $this->mountedTableBulkAction; try { + $action->beginDatabaseTransaction(); + if ($this->mountedTableBulkActionHasForm()) { $action->callBeforeFormValidated(); @@ -79,10 +82,21 @@ trait HasBulkActions ]); $result = $action->callAfter() ?? $result; + + $action->commitDatabaseTransaction(); } catch (Halt $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $action->rollBackDatabaseTransaction() : + $action->commitDatabaseTransaction(); + return null; } catch (Cancel $exception) { + $exception->shouldRollbackDatabaseTransaction() ? + $action->rollBackDatabaseTransaction() : + $action->commitDatabaseTransaction(); } catch (ValidationException $exception) { + $action->rollBackDatabaseTransaction(); + if (! $this->mountedTableBulkActionShouldOpenModal()) { $action->resetArguments(); $action->resetFormData(); @@ -90,6 +104,10 @@ trait HasBulkActions $this->unmountTableBulkAction(); } + throw $exception; + } catch (Throwable $exception) { + $action->rollBackDatabaseTransaction(); + throw $exception; } From 5422732221d2581f32774f42c8b44d3e869f0387 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 11:49:18 +0000 Subject: [PATCH 70/87] Update CanReorderRecords.php --- .../tables/src/Concerns/CanReorderRecords.php | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/packages/tables/src/Concerns/CanReorderRecords.php b/packages/tables/src/Concerns/CanReorderRecords.php index f812293886..cc82a769dd 100644 --- a/packages/tables/src/Concerns/CanReorderRecords.php +++ b/packages/tables/src/Concerns/CanReorderRecords.php @@ -20,32 +20,34 @@ trait CanReorderRecords $orderColumn = (string) str($this->getTable()->getReorderColumn())->afterLast('.'); - if ( - (($relationship = $this->getTable()->getRelationship()) instanceof BelongsToMany) && - in_array($orderColumn, $relationship->getPivotColumns()) - ) { - foreach ($order as $index => $recordKey) { - $this->getTableRecord($recordKey)->{$relationship->getPivotAccessor()}->update([ - $orderColumn => $index + 1, - ]); + DB::transaction(function () use ($order, $orderColumn) { + if ( + (($relationship = $this->getTable()->getRelationship()) instanceof BelongsToMany) && + in_array($orderColumn, $relationship->getPivotColumns()) + ) { + foreach ($order as $index => $recordKey) { + $this->getTableRecord($recordKey)->{$relationship->getPivotAccessor()}->update([ + $orderColumn => $index + 1, + ]); + } + + return; } - return; - } + $model = app($this->getTable()->getModel()); + $modelKeyName = $model->getKeyName(); - $model = app($this->getTable()->getModel()); - $modelKeyName = $model->getKeyName(); - - $model - ->newModelQuery() - ->whereIn($modelKeyName, array_values($order)) - ->update([ - $orderColumn => DB::raw( - 'case ' . collect($order) - ->map(fn ($recordKey, int $recordIndex): string => 'when ' . $modelKeyName . ' = ' . DB::getPdo()->quote($recordKey) . ' then ' . ($recordIndex + 1)) - ->implode(' ') . ' end' - ), - ]); + $model + ->newModelQuery() + ->whereIn($modelKeyName, array_values($order)) + ->update([ + $orderColumn => DB::raw( + 'case ' . collect($order) + ->map(fn ($recordKey, int $recordIndex): string => 'when ' . $modelKeyName . ' = ' . DB::getPdo()->quote($recordKey) . ' then ' . ($recordIndex + 1)) + ->implode(' ') . ' end' + ), + ]); + }); } public function toggleTableReordering(): void From 355395b875f897e429505de8f7fc9d635fa67077 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 12:10:12 +0000 Subject: [PATCH 71/87] Update Cancel.php --- packages/support/src/Exceptions/Cancel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/support/src/Exceptions/Cancel.php b/packages/support/src/Exceptions/Cancel.php index f90c62147c..8fe366a086 100644 --- a/packages/support/src/Exceptions/Cancel.php +++ b/packages/support/src/Exceptions/Cancel.php @@ -6,7 +6,7 @@ use Exception; class Cancel extends Exception { - protected bool $shouldRollbackDatabaseTransaction = true; + protected bool $shouldRollbackDatabaseTransaction = false; public function rollBackDatabaseTransaction(bool $condition = true): static { From 5968ede9a9c839964cd575d4be8a62e3e882ee40 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 12:13:57 +0000 Subject: [PATCH 72/87] Bump min Laravel version --- packages/actions/composer.json | 6 +++--- packages/forms/composer.json | 14 ++++++------- packages/infolists/composer.json | 12 +++++------ packages/notifications/composer.json | 8 ++++---- packages/panels/composer.json | 20 +++++++++---------- .../composer.json | 4 ++-- .../composer.json | 2 +- .../composer.json | 6 +++--- .../spatie-laravel-tags-plugin/composer.json | 2 +- .../composer.json | 2 +- packages/support/composer.json | 6 +++--- packages/tables/composer.json | 12 +++++------ 12 files changed, 47 insertions(+), 47 deletions(-) diff --git a/packages/actions/composer.json b/packages/actions/composer.json index 49c37579b6..1d63bf645b 100644 --- a/packages/actions/composer.json +++ b/packages/actions/composer.json @@ -14,9 +14,9 @@ "filament/infolists": "self.version", "filament/notifications": "self.version", "filament/support": "self.version", - "illuminate/contracts": "^10.0", - "illuminate/database": "^10.0", - "illuminate/support": "^10.0", + "illuminate/contracts": "^10.45", + "illuminate/database": "^10.45", + "illuminate/support": "^10.45", "league/csv": "^9.14", "openspout/openspout": "^4.23", "spatie/laravel-package-tools": "^1.9" diff --git a/packages/forms/composer.json b/packages/forms/composer.json index aff3351362..c941db8cc5 100644 --- a/packages/forms/composer.json +++ b/packages/forms/composer.json @@ -12,13 +12,13 @@ "danharrin/date-format-converter": "^0.3", "filament/actions": "self.version", "filament/support": "self.version", - "illuminate/console": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/database": "^10.0", - "illuminate/filesystem": "^10.0", - "illuminate/support": "^10.0", - "illuminate/validation": "^10.0", - "illuminate/view": "^10.0", + "illuminate/console": "^10.45", + "illuminate/contracts": "^10.45", + "illuminate/database": "^10.45", + "illuminate/filesystem": "^10.45", + "illuminate/support": "^10.45", + "illuminate/validation": "^10.45", + "illuminate/view": "^10.45", "spatie/laravel-package-tools": "^1.9" }, "autoload": { diff --git a/packages/infolists/composer.json b/packages/infolists/composer.json index e7ebc5648e..e59e82ccde 100644 --- a/packages/infolists/composer.json +++ b/packages/infolists/composer.json @@ -11,12 +11,12 @@ "php": "^8.1", "filament/actions": "self.version", "filament/support": "self.version", - "illuminate/console": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/database": "^10.0", - "illuminate/filesystem": "^10.0", - "illuminate/support": "^10.0", - "illuminate/view": "^10.0", + "illuminate/console": "^10.45", + "illuminate/contracts": "^10.45", + "illuminate/database": "^10.45", + "illuminate/filesystem": "^10.45", + "illuminate/support": "^10.45", + "illuminate/view": "^10.45", "spatie/laravel-package-tools": "^1.9" }, "autoload": { diff --git a/packages/notifications/composer.json b/packages/notifications/composer.json index a002ed55eb..23582b14c2 100644 --- a/packages/notifications/composer.json +++ b/packages/notifications/composer.json @@ -11,10 +11,10 @@ "php": "^8.1", "filament/actions": "self.version", "filament/support": "self.version", - "illuminate/contracts": "^10.0", - "illuminate/filesystem": "^10.0", - "illuminate/notifications": "^10.0", - "illuminate/support": "^10.0", + "illuminate/contracts": "^10.45", + "illuminate/filesystem": "^10.45", + "illuminate/notifications": "^10.45", + "illuminate/support": "^10.45", "spatie/laravel-package-tools": "^1.9" }, "autoload": { diff --git a/packages/panels/composer.json b/packages/panels/composer.json index 6e0c6fe7b2..761c06d1e2 100644 --- a/packages/panels/composer.json +++ b/packages/panels/composer.json @@ -17,16 +17,16 @@ "filament/support": "self.version", "filament/tables": "self.version", "filament/widgets": "self.version", - "illuminate/auth": "^10.0", - "illuminate/console": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/cookie": "^10.0", - "illuminate/database": "^10.0", - "illuminate/http": "^10.0", - "illuminate/routing": "^10.0", - "illuminate/session": "^10.0", - "illuminate/support": "^10.0", - "illuminate/view": "^10.0", + "illuminate/auth": "^10.45", + "illuminate/console": "^10.45", + "illuminate/contracts": "^10.45", + "illuminate/cookie": "^10.45", + "illuminate/database": "^10.45", + "illuminate/http": "^10.45", + "illuminate/routing": "^10.45", + "illuminate/session": "^10.45", + "illuminate/support": "^10.45", + "illuminate/view": "^10.45", "spatie/laravel-package-tools": "^1.9" }, "autoload": { diff --git a/packages/spatie-laravel-google-fonts-plugin/composer.json b/packages/spatie-laravel-google-fonts-plugin/composer.json index 0799075e5f..eabbb16a0d 100644 --- a/packages/spatie-laravel-google-fonts-plugin/composer.json +++ b/packages/spatie-laravel-google-fonts-plugin/composer.json @@ -9,8 +9,8 @@ }, "require": { "php": "^8.1", - "illuminate/contracts": "^10.0", - "illuminate/support": "^10.0", + "illuminate/contracts": "^10.45", + "illuminate/support": "^10.45", "spatie/laravel-google-fonts": "^1.0" }, "autoload": { diff --git a/packages/spatie-laravel-media-library-plugin/composer.json b/packages/spatie-laravel-media-library-plugin/composer.json index f46fa45ae3..23085949d6 100644 --- a/packages/spatie-laravel-media-library-plugin/composer.json +++ b/packages/spatie-laravel-media-library-plugin/composer.json @@ -9,7 +9,7 @@ }, "require": { "php": "^8.1", - "illuminate/support": "^10.0", + "illuminate/support": "^10.45", "spatie/laravel-medialibrary": "^10.0|^11.0" }, "autoload": { diff --git a/packages/spatie-laravel-settings-plugin/composer.json b/packages/spatie-laravel-settings-plugin/composer.json index 97558fcb56..e775b0da13 100644 --- a/packages/spatie-laravel-settings-plugin/composer.json +++ b/packages/spatie-laravel-settings-plugin/composer.json @@ -10,9 +10,9 @@ "require": { "php": "^8.1", "filament/filament": "self.version", - "illuminate/console": "^10.0", - "illuminate/filesystem": "^10.0", - "illuminate/support": "^10.0", + "illuminate/console": "^10.45", + "illuminate/filesystem": "^10.45", + "illuminate/support": "^10.45", "spatie/laravel-settings": "^2.2|^3.0" }, "autoload": { diff --git a/packages/spatie-laravel-tags-plugin/composer.json b/packages/spatie-laravel-tags-plugin/composer.json index 045ddd7dfd..582b646932 100644 --- a/packages/spatie-laravel-tags-plugin/composer.json +++ b/packages/spatie-laravel-tags-plugin/composer.json @@ -9,7 +9,7 @@ }, "require": { "php": "^8.1", - "illuminate/database": "^10.0", + "illuminate/database": "^10.45", "spatie/laravel-tags": "^4.0" }, "autoload": { diff --git a/packages/spatie-laravel-translatable-plugin/composer.json b/packages/spatie-laravel-translatable-plugin/composer.json index 3981892d35..6b8d6d3e44 100644 --- a/packages/spatie-laravel-translatable-plugin/composer.json +++ b/packages/spatie-laravel-translatable-plugin/composer.json @@ -10,7 +10,7 @@ "require": { "php": "^8.1", "filament/support": "self.version", - "illuminate/support": "^10.0", + "illuminate/support": "^10.45", "spatie/laravel-translatable": "^6.0" }, "autoload": { diff --git a/packages/support/composer.json b/packages/support/composer.json index 762722fbb5..ea6097e0cd 100644 --- a/packages/support/composer.json +++ b/packages/support/composer.json @@ -12,9 +12,9 @@ "blade-ui-kit/blade-heroicons": "^2.2.1", "doctrine/dbal": "^3.2", "ext-intl": "*", - "illuminate/contracts": "^10.0", - "illuminate/support": "^10.0", - "illuminate/view": "^10.0", + "illuminate/contracts": "^10.45", + "illuminate/support": "^10.45", + "illuminate/view": "^10.45", "livewire/livewire": "^3.2.3", "ryangjchandler/blade-capture-directive": "^0.2|^0.3", "spatie/color": "^1.5", diff --git a/packages/tables/composer.json b/packages/tables/composer.json index 17d302ea5b..87ef08267e 100644 --- a/packages/tables/composer.json +++ b/packages/tables/composer.json @@ -12,12 +12,12 @@ "filament/actions": "self.version", "filament/forms": "self.version", "filament/support": "self.version", - "illuminate/console": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/database": "^10.0", - "illuminate/filesystem": "^10.0", - "illuminate/support": "^10.0", - "illuminate/view": "^10.0", + "illuminate/console": "^10.45", + "illuminate/contracts": "^10.45", + "illuminate/database": "^10.45", + "illuminate/filesystem": "^10.45", + "illuminate/support": "^10.45", + "illuminate/view": "^10.45", "kirschbaum-development/eloquent-power-joins": "^3.0", "spatie/laravel-package-tools": "^1.9" }, From 4fecd096120f4ef0227374b5737f72b795ce0380 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 12:56:09 +0000 Subject: [PATCH 73/87] fix: Laravel Number:: formatting --- .../actions/src/Concerns/CanExportRecords.php | 5 +- .../actions/src/Concerns/CanImportRecords.php | 7 +- packages/infolists/docs/03-entries/02-text.md | 51 +++++++++-- .../Components/Concerns/CanFormatState.php | 71 +++++++++------ .../components/pagination/index.blade.php | 6 +- packages/support/src/Enums/ArgumentValue.php | 8 ++ packages/support/src/helpers.php | 15 +-- packages/tables/docs/03-columns/02-text.md | 51 +++++++++-- packages/tables/docs/07-summaries.md | 52 ++++++++++- .../src/Columns/Concerns/CanFormatState.php | 71 +++++++++------ .../Summarizers/Concerns/CanFormatState.php | 91 ++++++++----------- .../Operators/EqualsOperator.php | 3 +- .../Operators/IsMaxOperator.php | 3 +- .../Operators/IsMinOperator.php | 3 +- 14 files changed, 300 insertions(+), 137 deletions(-) create mode 100644 packages/support/src/Enums/ArgumentValue.php diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index c5116d7bc9..376220b185 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -25,6 +25,7 @@ use Illuminate\Foundation\Bus\PendingChain; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Bus; +use Illuminate\Support\Number; use Illuminate\Support\Str; use Livewire\Component; @@ -127,7 +128,7 @@ trait CanExportRecords Notification::make() ->title(__('filament-actions::export.notifications.max_rows.title')) ->body(trans_choice('filament-actions::export.notifications.max_rows.body', $maxRows, [ - 'count' => format_number($maxRows), + 'count' => Number::format($maxRows), ])) ->danger() ->send(); @@ -239,7 +240,7 @@ trait CanExportRecords Notification::make() ->title($action->getSuccessNotificationTitle()) ->body(trans_choice('filament-actions::export.notifications.started.body', $export->total_rows, [ - 'count' => format_number($export->total_rows), + 'count' => Number::format($export->total_rows), ])) ->success() ->send(); diff --git a/packages/actions/src/Concerns/CanImportRecords.php b/packages/actions/src/Concerns/CanImportRecords.php index 12e8fc7931..bd045fe9ae 100644 --- a/packages/actions/src/Concerns/CanImportRecords.php +++ b/packages/actions/src/Concerns/CanImportRecords.php @@ -26,6 +26,7 @@ use Illuminate\Filesystem\AwsS3V3Adapter; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Number; use League\Csv\Info; use League\Csv\Reader as CsvReader; use League\Csv\Statement; @@ -181,7 +182,7 @@ trait CanImportRecords Notification::make() ->title(__('filament-actions::import.notifications.max_rows.title')) ->body(trans_choice('filament-actions::import.notifications.max_rows.body', $maxRows, [ - 'count' => format_number($maxRows), + 'count' => Number::format($maxRows), ])) ->danger() ->send(); @@ -271,7 +272,7 @@ trait CanImportRecords fn (Notification $notification) => $notification->actions([ NotificationAction::make('downloadFailedRowsCsv') ->label(trans_choice('filament-actions::import.notifications.completed.actions.download_failed_rows_csv.label', $failedRowsCount, [ - 'count' => format_number($failedRowsCount), + 'count' => Number::format($failedRowsCount), ])) ->color('danger') ->url(route('filament.imports.failed-rows.download', ['import' => $import], absolute: false), shouldOpenInNewTab: true) @@ -285,7 +286,7 @@ trait CanImportRecords Notification::make() ->title($action->getSuccessNotificationTitle()) ->body(trans_choice('filament-actions::import.notifications.started.body', $import->total_rows, [ - 'count' => format_number($import->total_rows), + 'count' => Number::format($import->total_rows), ])) ->success() ->send(); diff --git a/packages/infolists/docs/03-entries/02-text.md b/packages/infolists/docs/03-entries/02-text.md index 669aad78fe..1e2a3228fc 100644 --- a/packages/infolists/docs/03-entries/02-text.md +++ b/packages/infolists/docs/03-entries/02-text.md @@ -58,17 +58,39 @@ TextEntry::make('created_at') ## Number formatting -The `numeric()` method allows you to format an entry as a number, using PHP's `number_format()`: +The `numeric()` method allows you to format an entry as a number: ```php use Filament\Infolists\Components\TextEntry; TextEntry::make('stock') - ->numeric( - decimalPlaces: 0, - decimalSeparator: '.', - thousandsSeparator: ',', - ) + ->numeric() +``` + +If you would like to customize the number of decimal places used to format the number with, you can use the `decimalPlaces` argument: + +```php +use Filament\Infolists\Components\TextEntry; + +TextEntry::make('stock') + ->numeric(decimalPlaces: 0) +``` + +By default, your app's locale will be used to format the number suitably. If you would like to customize the locale used, you can pass it to the `locale` argument: + +```php +use Filament\Infolists\Components\TextEntry; + +TextEntry::make('stock') + ->numeric(locale: 'nl') +``` + +Alternatively, you can set the default locale used across your app using the `Number::useLocale()` method in the `boot()` method of a service provider: + +```php +use Illuminate\Support\Number; + +Number::useLocale('nl'); ``` ## Currency formatting @@ -91,6 +113,23 @@ TextEntry::make('price') ->money('EUR', divideBy: 100) ``` +By default, your app's locale will be used to format the money suitably. If you would like to customize the locale used, you can pass it to the `locale` argument: + +```php +use Filament\Infolists\Components\TextEntry; + +TextEntry::make('price') + ->money(currency: 'EUR', locale: 'nl') +``` + +Alternatively, you can set the default locale used across your app using the `Number::useLocale()` method in the `boot()` method of a service provider: + +```php +use Illuminate\Support\Number; + +Number::useLocale('nl'); +``` + ## Limiting text length You may `limit()` the length of the entry's value: diff --git a/packages/infolists/src/Components/Concerns/CanFormatState.php b/packages/infolists/src/Components/Concerns/CanFormatState.php index c0e5ffbe38..8f9ed0a9e3 100644 --- a/packages/infolists/src/Components/Concerns/CanFormatState.php +++ b/packages/infolists/src/Components/Concerns/CanFormatState.php @@ -6,8 +6,11 @@ use Closure; use Filament\Infolists\Components\TextEntry; use Filament\Infolists\Infolist; use Filament\Support\Contracts\HasLabel as LabelInterface; +use Filament\Support\Enums\ArgumentValue; +use Filament\Tables\Table; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Carbon; +use Illuminate\Support\Number; use Illuminate\Support\Str; use function Filament\Support\format_money; @@ -99,28 +102,11 @@ trait CanFormatState return $this; } - public function money(string | Closure | null $currency = null, int $divideBy = 0): static + public function money(string | Closure | null $currency = null, int $divideBy = 0, string | Closure | null $locale = null): static { $this->isMoney = true; - $this->formatStateUsing(static function (TextEntry $component, $state) use ($currency, $divideBy): ?string { - if (blank($state)) { - return null; - } - - $currency = $component->evaluate($currency) ?? Infolist::$defaultCurrency; - - return format_money($state, $currency, $divideBy); - }); - - return $this; - } - - public function numeric(int | Closure | null $decimalPlaces = null, string | Closure | null $decimalSeparator = '.', string | Closure | null $thousandsSeparator = ','): static - { - $this->isNumeric = true; - - $this->formatStateUsing(static function (TextEntry $component, $state) use ($decimalPlaces, $decimalSeparator, $thousandsSeparator): ?string { + $this->formatStateUsing(static function (TextEntry $component, $state) use ($currency, $divideBy, $locale): ?string { if (blank($state)) { return null; } @@ -129,16 +115,47 @@ trait CanFormatState return $state; } - if ($decimalPlaces === null) { - return format_number($state); + $currency = $component->evaluate($currency) ?? Table::$defaultCurrency; + + if ($divideBy) { + $state /= $divideBy; } - return number_format( - $state, - $component->evaluate($decimalPlaces), - $component->evaluate($decimalSeparator), - $component->evaluate($thousandsSeparator), - ); + return Number::currency($state, $currency, $component->evaluate($locale)); + }); + + return $this; + } + + public function numeric(int | Closure | null $decimalPlaces = null, string | Closure | null | ArgumentValue $decimalSeparator = ArgumentValue::Default, string | Closure | null | ArgumentValue $thousandsSeparator = ArgumentValue::Default, int | Closure | null $maxDecimalPlaces = null, string | Closure | null $locale = null): static + { + $this->isNumeric = true; + + $this->formatStateUsing(static function (TextEntry $component, $state) use ($decimalPlaces, $decimalSeparator, $locale, $maxDecimalPlaces, $thousandsSeparator): ?string { + if (blank($state)) { + return null; + } + + if (! is_numeric($state)) { + return $state; + } + + $decimalSeparator = $component->evaluate($decimalSeparator); + $thousandsSeparator = $component->evaluate($thousandsSeparator); + + if ( + ($decimalSeparator !== ArgumentValue::Default) || + ($thousandsSeparator !== ArgumentValue::Default) + ) { + return number_format( + $state, + $component->evaluate($decimalPlaces), + $decimalSeparator === ArgumentValue::Default ? '.' : $decimalSeparator, + $thousandsSeparator === ArgumentValue::Default ? ',' : $thousandsSeparator, + ); + } + + return Number::format($state, $decimalPlaces, $maxDecimalPlaces, locale: $component->evaluate($loale)); }); return $this; diff --git a/packages/support/resources/views/components/pagination/index.blade.php b/packages/support/resources/views/components/pagination/index.blade.php index 106be9704a..4768d5be62 100644 --- a/packages/support/resources/views/components/pagination/index.blade.php +++ b/packages/support/resources/views/components/pagination/index.blade.php @@ -51,9 +51,9 @@ 'filament::components/pagination.overview', $paginator->total(), [ - 'first' => \Filament\Support\format_number($paginator->firstItem() ?? 0), - 'last' => \Filament\Support\format_number($paginator->lastItem() ?? 0), - 'total' => \Filament\Support\format_number($paginator->total()), + 'first' => \Illuminate\Support\Number::format($paginator->firstItem() ?? 0), + 'last' => \Illuminate\Support\Number::format($paginator->lastItem() ?? 0), + 'total' => \Illuminate\Support\Number::format($paginator->total()), ], ) }} diff --git a/packages/support/src/Enums/ArgumentValue.php b/packages/support/src/Enums/ArgumentValue.php new file mode 100644 index 0000000000..c7e900123a --- /dev/null +++ b/packages/support/src/Enums/ArgumentValue.php @@ -0,0 +1,8 @@ +<?php + +namespace Filament\Support\Enums; + +enum ArgumentValue +{ + case Default; +} diff --git a/packages/support/src/helpers.php b/packages/support/src/helpers.php index 62ecdf5f03..67f90d4f49 100644 --- a/packages/support/src/helpers.php +++ b/packages/support/src/helpers.php @@ -8,30 +8,33 @@ use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Connection; use Illuminate\Database\Query\Expression; use Illuminate\Support\HtmlString; +use Illuminate\Support\Number; use Illuminate\Support\Str; use Illuminate\Translation\MessageSelector; use Illuminate\View\ComponentAttributeBag; use NumberFormatter; if (! function_exists('Filament\Support\format_money')) { + /** + * @deprecated Use `Illuminate\Support\Number::currency()` instead. + */ function format_money(float | int $money, string $currency, int $divideBy = 0): string { - $formatter = new NumberFormatter(app()->getLocale(), NumberFormatter::CURRENCY); - if ($divideBy) { $money /= $divideBy; } - return $formatter->formatCurrency($money, $currency); + return Number::currency($money, $currency); } } if (! function_exists('Filament\Support\format_number')) { + /** + * @deprecated Use `Illuminate\Support\Number::format()` instead. + */ function format_number(float | int $number): string { - $formatter = new NumberFormatter(app()->getLocale(), NumberFormatter::DECIMAL); - - return $formatter->format($number); + return Number::format($number); } } diff --git a/packages/tables/docs/03-columns/02-text.md b/packages/tables/docs/03-columns/02-text.md index 11f319a96b..816b7a2610 100644 --- a/packages/tables/docs/03-columns/02-text.md +++ b/packages/tables/docs/03-columns/02-text.md @@ -84,17 +84,39 @@ TextColumn::make('created_at') ## Number formatting -The `numeric()` method allows you to format a column as a number, using PHP's `number_format()`: +The `numeric()` method allows you to format an entry as a number: ```php use Filament\Tables\Columns\TextColumn; TextColumn::make('stock') - ->numeric( - decimalPlaces: 0, - decimalSeparator: '.', - thousandsSeparator: ',', - ) + ->numeric() +``` + +If you would like to customize the number of decimal places used to format the number with, you can use the `decimalPlaces` argument: + +```php +use Filament\Tables\Columns\TextColumn; + +TextColumn::make('stock') + ->numeric(decimalPlaces: 0) +``` + +By default, your app's locale will be used to format the number suitably. If you would like to customize the locale used, you can pass it to the `locale` argument: + +```php +use Filament\Tables\Columns\TextColumn; + +TextColumn::make('stock') + ->numeric(locale: 'nl') +``` + +Alternatively, you can set the default locale used across your app using the `Number::useLocale()` method in the `boot()` method of a service provider: + +```php +use Illuminate\Support\Number; + +Number::useLocale('nl'); ``` ## Currency formatting @@ -117,6 +139,23 @@ TextColumn::make('price') ->money('EUR', divideBy: 100) ``` +By default, your app's locale will be used to format the money suitably. If you would like to customize the locale used, you can pass it to the `locale` argument: + +```php +use Filament\Tables\Columns\TextColumn; + +TextColumn::make('price') + ->money('EUR', locale: 'nl') +``` + +Alternatively, you can set the default locale used across your app using the `Number::useLocale()` method in the `boot()` method of a service provider: + +```php +use Illuminate\Support\Number; + +Number::useLocale('nl'); +``` + ## Limiting text length You may `limit()` the length of the cell's value: diff --git a/packages/tables/docs/07-summaries.md b/packages/tables/docs/07-summaries.md index 061be9d05b..66041651e5 100644 --- a/packages/tables/docs/07-summaries.md +++ b/packages/tables/docs/07-summaries.md @@ -221,7 +221,17 @@ In this example, the table will calculate how many posts are published. ### Number formatting -The `numeric()` method allows you to format a summary as a number, using PHP's `number_format()`: +The `numeric()` method allows you to format an entry as a number: + +```php +use Filament\Tables\Columns\Summarizers\Average; +use Filament\Tables\Columns\TextColumn; + +TextColumn::make('rating') + ->summarize(Average::make()->numeric()) +``` + +If you would like to customize the number of decimal places used to format the number with, you can use the `decimalPlaces` argument: ```php use Filament\Tables\Columns\Summarizers\Average; @@ -230,11 +240,29 @@ use Filament\Tables\Columns\TextColumn; TextColumn::make('rating') ->summarize(Average::make()->numeric( decimalPlaces: 0, - decimalSeparator: '.', - thousandsSeparator: ',', )) ``` +By default, your app's locale will be used to format the number suitably. If you would like to customize the locale used, you can pass it to the `locale` argument: + +```php +use Filament\Tables\Columns\Summarizers\Average; +use Filament\Tables\Columns\TextColumn; + +TextColumn::make('rating') + ->summarize(Average::make()->numeric( + locale: 'nl', + )) +``` + +Alternatively, you can set the default locale used across your app using the `Number::useLocale()` method in the `boot()` method of a service provider: + +```php +use Illuminate\Support\Number; + +Number::useLocale('nl'); +``` + ### Currency formatting The `money()` method allows you to easily format monetary values, in any currency: @@ -257,6 +285,24 @@ TextColumn::make('price') ->summarize(Sum::make()->money('EUR', divideBy: 100)) ``` +By default, your app's locale will be used to format the money suitably. If you would like to customize the locale used, you can pass it to the `locale` argument: + +```php +use Filament\Tables\Columns\Summarizers\Average; +use Filament\Tables\Columns\TextColumn; + +TextColumn::make('price') + ->summarize(Sum::make()->money(currency: 'EUR', locale: 'nl')) +``` + +Alternatively, you can set the default locale used across your app using the `Number::useLocale()` method in the `boot()` method of a service provider: + +```php +use Illuminate\Support\Number; + +Number::useLocale('nl'); +``` + ### Limiting text length You may `limit()` the length of the summary's value: diff --git a/packages/tables/src/Columns/Concerns/CanFormatState.php b/packages/tables/src/Columns/Concerns/CanFormatState.php index c1eb759e53..e8505baadc 100644 --- a/packages/tables/src/Columns/Concerns/CanFormatState.php +++ b/packages/tables/src/Columns/Concerns/CanFormatState.php @@ -3,11 +3,14 @@ namespace Filament\Tables\Columns\Concerns; use Closure; +use Filament\Infolists\Components\TextEntry; use Filament\Support\Contracts\HasLabel as LabelInterface; +use Filament\Support\Enums\ArgumentValue; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Carbon; +use Illuminate\Support\Number; use Illuminate\Support\Str; use function Filament\Support\format_money; @@ -99,28 +102,11 @@ trait CanFormatState return $this; } - public function money(string | Closure | null $currency = null, int $divideBy = 0): static + public function money(string | Closure | null $currency = null, int $divideBy = 0, string | Closure | null $locale = null): static { $this->isMoney = true; - $this->formatStateUsing(static function (TextColumn $column, $state) use ($currency, $divideBy): ?string { - if (blank($state)) { - return null; - } - - $currency = $column->evaluate($currency) ?? Table::$defaultCurrency; - - return format_money($state, $currency, $divideBy); - }); - - return $this; - } - - public function numeric(int | Closure | null $decimalPlaces = null, string | Closure | null $decimalSeparator = '.', string | Closure | null $thousandsSeparator = ','): static - { - $this->isNumeric = true; - - $this->formatStateUsing(static function (TextColumn $column, $state) use ($decimalPlaces, $decimalSeparator, $thousandsSeparator): ?string { + $this->formatStateUsing(static function (TextColumn $column, $state) use ($currency, $divideBy, $locale): ?string { if (blank($state)) { return null; } @@ -129,16 +115,47 @@ trait CanFormatState return $state; } - if ($decimalPlaces === null) { - return format_number($state); + $currency = $column->evaluate($currency) ?? Table::$defaultCurrency; + + if ($divideBy) { + $state /= $divideBy; } - return number_format( - $state, - $column->evaluate($decimalPlaces), - $column->evaluate($decimalSeparator), - $column->evaluate($thousandsSeparator), - ); + return Number::currency($state, $currency, $column->evaluate($locale)); + }); + + return $this; + } + + public function numeric(int | Closure | null $decimalPlaces = null, string | Closure | null | ArgumentValue $decimalSeparator = ArgumentValue::Default, string | Closure | null | ArgumentValue $thousandsSeparator = ArgumentValue::Default, int | Closure | null $maxDecimalPlaces = null, string | Closure | null $locale = null): static + { + $this->isNumeric = true; + + $this->formatStateUsing(static function (TextColumn $column, $state) use ($decimalPlaces, $decimalSeparator, $locale, $maxDecimalPlaces, $thousandsSeparator): ?string { + if (blank($state)) { + return null; + } + + if (! is_numeric($state)) { + return $state; + } + + $decimalSeparator = $column->evaluate($decimalSeparator); + $thousandsSeparator = $column->evaluate($thousandsSeparator); + + if ( + ($decimalSeparator !== ArgumentValue::Default) || + ($thousandsSeparator !== ArgumentValue::Default) + ) { + return number_format( + $state, + $column->evaluate($decimalPlaces), + $decimalSeparator === ArgumentValue::Default ? '.' : $decimalSeparator, + $thousandsSeparator === ArgumentValue::Default ? ',' : $thousandsSeparator, + ); + } + + return Number::format($state, $decimalPlaces, $maxDecimalPlaces, locale: $column->evaluate($locale)); }); return $this; diff --git a/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php b/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php index 3a1440362f..0abb7d79f4 100644 --- a/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php +++ b/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php @@ -3,9 +3,12 @@ namespace Filament\Tables\Columns\Summarizers\Concerns; use Closure; +use Filament\Infolists\Components\TextEntry; +use Filament\Support\Enums\ArgumentValue; use Filament\Tables\Columns\Summarizers\Summarizer; use Filament\Tables\Table; use Illuminate\Support\Arr; +use Illuminate\Support\Number; use Illuminate\Support\Str; use function Filament\Support\format_money; @@ -26,83 +29,69 @@ trait CanFormatState public function limit(int $length = 100, ?string $end = '...'): static { - $this->formatStateUsing(static function ($state) use ($end, $length) { - $isArrayState = is_array($state); - - $state = array_map(function ($state) use ($end, $length) { - if (blank($state)) { - return null; - } - - return Str::limit(strval($state), $length, $end ?? ''); - }, Arr::wrap($state)); - - if (! $isArrayState) { - return Arr::first($state); + $this->formatStateUsing(static function ($state) use ($end, $length): ?string { + if (blank($state)) { + return null; } - return $state; + return Str::limit(strval($state), $length, $end ?? ''); }); return $this; } - public function money(string | Closure | null $currency = null, int $divideBy = 0): static + public function money(string | Closure | null $currency = null, int $divideBy = 0, string | Closure | null $locale = null): static { - $this->formatStateUsing(static function ($state, Summarizer $summarizer) use ($currency, $divideBy) { - $isArrayState = is_array($state); - - $state = array_map(function ($state) use ($currency, $divideBy, $summarizer) { - if (blank($state)) { - return null; - } - - $currency = $summarizer->evaluate($currency) ?? Table::$defaultCurrency; - - return format_money($state, $currency, $divideBy); - }, Arr::wrap($state)); - - if (! $isArrayState) { - return Arr::first($state); + $this->formatStateUsing(static function ($state, Summarizer $summarizer) use ($currency, $divideBy, $locale): ?string { + if (blank($state)) { + return null; } - return $state; + if (! is_numeric($state)) { + return $state; + } + + $currency = $summarizer->evaluate($currency) ?? Table::$defaultCurrency; + + if ($divideBy) { + $state /= $divideBy; + } + + return Number::currency($state, $currency, $summarizer->evaluate($locale)); }); return $this; } - public function numeric(int | Closure | null $decimalPlaces = null, string | Closure | null $decimalSeparator = '.', string | Closure | null $thousandsSeparator = ','): static + public function numeric(int | Closure | null $decimalPlaces = null, string | Closure | null | ArgumentValue $decimalSeparator = ArgumentValue::Default, string | Closure | null | ArgumentValue $thousandsSeparator = ArgumentValue::Default, int | Closure | null $maxDecimalPlaces = null, string | Closure | null $locale = null): static { - $this->formatStateUsing(static function ($state, Summarizer $summarizer) use ($decimalPlaces, $decimalSeparator, $thousandsSeparator) { - $isArrayState = is_array($state); + $this->isNumeric = true; - $state = array_map(function ($state) use ($decimalPlaces, $decimalSeparator, $summarizer, $thousandsSeparator) { - if (blank($state)) { - return null; - } + $this->formatStateUsing(static function ($state, Summarizer $summarizer) use ($decimalPlaces, $decimalSeparator, $locale, $maxDecimalPlaces, $thousandsSeparator): ?string { + if (blank($state)) { + return null; + } - if (! is_numeric($state)) { - return $state; - } + if (! is_numeric($state)) { + return $state; + } - if ($decimalPlaces === null) { - return format_number($state); - } + $decimalSeparator = $summarizer->evaluate($decimalSeparator); + $thousandsSeparator = $summarizer->evaluate($thousandsSeparator); + if ( + ($decimalSeparator !== ArgumentValue::Default) || + ($thousandsSeparator !== ArgumentValue::Default) + ) { return number_format( $state, $summarizer->evaluate($decimalPlaces), - $summarizer->evaluate($decimalSeparator), - $summarizer->evaluate($thousandsSeparator), + $decimalSeparator === ArgumentValue::Default ? '.' : $decimalSeparator, + $thousandsSeparator === ArgumentValue::Default ? ',' : $thousandsSeparator, ); - }, Arr::wrap($state)); - - if (! $isArrayState) { - return Arr::first($state); } - return $state; + return Number::format($state, $decimalPlaces, $maxDecimalPlaces, locale: $summarizer->evaluate($locale)); }); return $this; diff --git a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/EqualsOperator.php b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/EqualsOperator.php index 987d718045..3fc09255fa 100644 --- a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/EqualsOperator.php +++ b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/EqualsOperator.php @@ -7,6 +7,7 @@ use Filament\Forms\Components\TextInput; use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Number; use function Filament\Support\format_number; class EqualsOperator extends Operator @@ -35,7 +36,7 @@ class EqualsOperator extends Operator 'filament-tables::filters/query-builder.operators.number.equals.summary.direct', [ 'attribute' => $this->getAttributeLabel(), - 'number' => format_number($this->getSettings()['number']), + 'number' => Number::format($this->getSettings()['number']), ], ); } diff --git a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMaxOperator.php b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMaxOperator.php index 46804cb691..7bfc5c8123 100644 --- a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMaxOperator.php +++ b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMaxOperator.php @@ -7,6 +7,7 @@ use Filament\Forms\Components\TextInput; use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Number; use function Filament\Support\format_number; class IsMaxOperator extends Operator @@ -35,7 +36,7 @@ class IsMaxOperator extends Operator 'filament-tables::filters/query-builder.operators.number.is_max.summary.direct', [ 'attribute' => $this->getAttributeLabel(), - 'number' => format_number($this->getSettings()['number']), + 'number' => Number::format($this->getSettings()['number']), ], ); } diff --git a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMinOperator.php b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMinOperator.php index ed3a1584da..6fdbfd8b1d 100644 --- a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMinOperator.php +++ b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMinOperator.php @@ -7,6 +7,7 @@ use Filament\Forms\Components\TextInput; use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Number; use function Filament\Support\format_number; class IsMinOperator extends Operator @@ -35,7 +36,7 @@ class IsMinOperator extends Operator 'filament-tables::filters/query-builder.operators.number.is_min.summary.direct', [ 'attribute' => $this->getAttributeLabel(), - 'number' => format_number($this->getSettings()['number']), + 'number' => Number::format($this->getSettings()['number']), ], ); } From e5e04c021a8523e39094c38ad33b980bce841551 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 12:58:50 +0000 Subject: [PATCH 74/87] cs --- packages/actions/src/Concerns/CanExportRecords.php | 2 -- packages/actions/src/Concerns/CanImportRecords.php | 2 -- .../infolists/src/Components/Concerns/CanFormatState.php | 7 ++----- packages/support/src/helpers.php | 1 - packages/tables/src/Columns/Concerns/CanFormatState.php | 6 +----- .../src/Columns/Summarizers/Concerns/CanFormatState.php | 7 +------ .../NumberConstraint/Operators/EqualsOperator.php | 2 -- .../NumberConstraint/Operators/IsMaxOperator.php | 2 -- .../NumberConstraint/Operators/IsMinOperator.php | 2 -- 9 files changed, 4 insertions(+), 27 deletions(-) diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index 376220b185..ea56877d1e 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -29,8 +29,6 @@ use Illuminate\Support\Number; use Illuminate\Support\Str; use Livewire\Component; -use function Filament\Support\format_number; - trait CanExportRecords { /** diff --git a/packages/actions/src/Concerns/CanImportRecords.php b/packages/actions/src/Concerns/CanImportRecords.php index bd045fe9ae..0897000f71 100644 --- a/packages/actions/src/Concerns/CanImportRecords.php +++ b/packages/actions/src/Concerns/CanImportRecords.php @@ -35,8 +35,6 @@ use Livewire\Features\SupportFileUploads\TemporaryUploadedFile; use SplTempFileObject; use Symfony\Component\HttpFoundation\StreamedResponse; -use function Filament\Support\format_number; - trait CanImportRecords { /** diff --git a/packages/infolists/src/Components/Concerns/CanFormatState.php b/packages/infolists/src/Components/Concerns/CanFormatState.php index 8f9ed0a9e3..b639778c0d 100644 --- a/packages/infolists/src/Components/Concerns/CanFormatState.php +++ b/packages/infolists/src/Components/Concerns/CanFormatState.php @@ -13,9 +13,6 @@ use Illuminate\Support\Carbon; use Illuminate\Support\Number; use Illuminate\Support\Str; -use function Filament\Support\format_money; -use function Filament\Support\format_number; - trait CanFormatState { protected ?Closure $formatStateUsing = null; @@ -131,7 +128,7 @@ trait CanFormatState { $this->isNumeric = true; - $this->formatStateUsing(static function (TextEntry $component, $state) use ($decimalPlaces, $decimalSeparator, $locale, $maxDecimalPlaces, $thousandsSeparator): ?string { + $this->formatStateUsing(static function (TextEntry $component, $state) use ($decimalPlaces, $decimalSeparator, $maxDecimalPlaces, $thousandsSeparator): ?string { if (blank($state)) { return null; } @@ -150,7 +147,7 @@ trait CanFormatState return number_format( $state, $component->evaluate($decimalPlaces), - $decimalSeparator === ArgumentValue::Default ? '.' : $decimalSeparator, + $decimalSeparator === ArgumentValue::Default ? '.' : $decimalSeparator, $thousandsSeparator === ArgumentValue::Default ? ',' : $thousandsSeparator, ); } diff --git a/packages/support/src/helpers.php b/packages/support/src/helpers.php index 67f90d4f49..01c64c6ae5 100644 --- a/packages/support/src/helpers.php +++ b/packages/support/src/helpers.php @@ -12,7 +12,6 @@ use Illuminate\Support\Number; use Illuminate\Support\Str; use Illuminate\Translation\MessageSelector; use Illuminate\View\ComponentAttributeBag; -use NumberFormatter; if (! function_exists('Filament\Support\format_money')) { /** diff --git a/packages/tables/src/Columns/Concerns/CanFormatState.php b/packages/tables/src/Columns/Concerns/CanFormatState.php index e8505baadc..5a76d5bb15 100644 --- a/packages/tables/src/Columns/Concerns/CanFormatState.php +++ b/packages/tables/src/Columns/Concerns/CanFormatState.php @@ -3,7 +3,6 @@ namespace Filament\Tables\Columns\Concerns; use Closure; -use Filament\Infolists\Components\TextEntry; use Filament\Support\Contracts\HasLabel as LabelInterface; use Filament\Support\Enums\ArgumentValue; use Filament\Tables\Columns\TextColumn; @@ -13,9 +12,6 @@ use Illuminate\Support\Carbon; use Illuminate\Support\Number; use Illuminate\Support\Str; -use function Filament\Support\format_money; -use function Filament\Support\format_number; - trait CanFormatState { protected ?Closure $formatStateUsing = null; @@ -150,7 +146,7 @@ trait CanFormatState return number_format( $state, $column->evaluate($decimalPlaces), - $decimalSeparator === ArgumentValue::Default ? '.' : $decimalSeparator, + $decimalSeparator === ArgumentValue::Default ? '.' : $decimalSeparator, $thousandsSeparator === ArgumentValue::Default ? ',' : $thousandsSeparator, ); } diff --git a/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php b/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php index 0abb7d79f4..50522e9eb0 100644 --- a/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php +++ b/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php @@ -3,17 +3,12 @@ namespace Filament\Tables\Columns\Summarizers\Concerns; use Closure; -use Filament\Infolists\Components\TextEntry; use Filament\Support\Enums\ArgumentValue; use Filament\Tables\Columns\Summarizers\Summarizer; use Filament\Tables\Table; -use Illuminate\Support\Arr; use Illuminate\Support\Number; use Illuminate\Support\Str; -use function Filament\Support\format_money; -use function Filament\Support\format_number; - trait CanFormatState { protected ?Closure $formatStateUsing = null; @@ -86,7 +81,7 @@ trait CanFormatState return number_format( $state, $summarizer->evaluate($decimalPlaces), - $decimalSeparator === ArgumentValue::Default ? '.' : $decimalSeparator, + $decimalSeparator === ArgumentValue::Default ? '.' : $decimalSeparator, $thousandsSeparator === ArgumentValue::Default ? ',' : $thousandsSeparator, ); } diff --git a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/EqualsOperator.php b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/EqualsOperator.php index 3fc09255fa..471f823caa 100644 --- a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/EqualsOperator.php +++ b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/EqualsOperator.php @@ -6,9 +6,7 @@ use Filament\Forms\Components\Component; use Filament\Forms\Components\TextInput; use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator; use Illuminate\Database\Eloquent\Builder; - use Illuminate\Support\Number; -use function Filament\Support\format_number; class EqualsOperator extends Operator { diff --git a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMaxOperator.php b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMaxOperator.php index 7bfc5c8123..cf8c4ad494 100644 --- a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMaxOperator.php +++ b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMaxOperator.php @@ -6,9 +6,7 @@ use Filament\Forms\Components\Component; use Filament\Forms\Components\TextInput; use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator; use Illuminate\Database\Eloquent\Builder; - use Illuminate\Support\Number; -use function Filament\Support\format_number; class IsMaxOperator extends Operator { diff --git a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMinOperator.php b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMinOperator.php index 6fdbfd8b1d..dffb0cca75 100644 --- a/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMinOperator.php +++ b/packages/tables/src/Filters/QueryBuilder/Constraints/NumberConstraint/Operators/IsMinOperator.php @@ -6,9 +6,7 @@ use Filament\Forms\Components\Component; use Filament\Forms\Components\TextInput; use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator; use Illuminate\Database\Eloquent\Builder; - use Illuminate\Support\Number; -use function Filament\Support\format_number; class IsMinOperator extends Operator { From 9c83b6945163529e5dfcc980d7f21e97e085942c Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 13:02:21 +0000 Subject: [PATCH 75/87] fix --- packages/infolists/src/Components/Concerns/CanFormatState.php | 4 ++-- .../src/Columns/Summarizers/Concerns/CanFormatState.php | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/infolists/src/Components/Concerns/CanFormatState.php b/packages/infolists/src/Components/Concerns/CanFormatState.php index b639778c0d..8bee46d012 100644 --- a/packages/infolists/src/Components/Concerns/CanFormatState.php +++ b/packages/infolists/src/Components/Concerns/CanFormatState.php @@ -128,7 +128,7 @@ trait CanFormatState { $this->isNumeric = true; - $this->formatStateUsing(static function (TextEntry $component, $state) use ($decimalPlaces, $decimalSeparator, $maxDecimalPlaces, $thousandsSeparator): ?string { + $this->formatStateUsing(static function (TextEntry $component, $state) use ($decimalPlaces, $decimalSeparator, $locale, $maxDecimalPlaces, $thousandsSeparator): ?string { if (blank($state)) { return null; } @@ -152,7 +152,7 @@ trait CanFormatState ); } - return Number::format($state, $decimalPlaces, $maxDecimalPlaces, locale: $component->evaluate($loale)); + return Number::format($state, $decimalPlaces, $maxDecimalPlaces, $component->evaluate($locale)); }); return $this; diff --git a/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php b/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php index 50522e9eb0..91934e7bb7 100644 --- a/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php +++ b/packages/tables/src/Columns/Summarizers/Concerns/CanFormatState.php @@ -60,8 +60,6 @@ trait CanFormatState public function numeric(int | Closure | null $decimalPlaces = null, string | Closure | null | ArgumentValue $decimalSeparator = ArgumentValue::Default, string | Closure | null | ArgumentValue $thousandsSeparator = ArgumentValue::Default, int | Closure | null $maxDecimalPlaces = null, string | Closure | null $locale = null): static { - $this->isNumeric = true; - $this->formatStateUsing(static function ($state, Summarizer $summarizer) use ($decimalPlaces, $decimalSeparator, $locale, $maxDecimalPlaces, $thousandsSeparator): ?string { if (blank($state)) { return null; From a4b8a798e3cf44768ac12ebaef8a52551d9e0254 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 13:34:00 +0000 Subject: [PATCH 76/87] refactor --- packages/forms/docs/03-fields/03-select.md | 2 +- .../forms/src/Components/CheckboxList.php | 12 +++++-- .../Concerns/HasPivotAttributes.php | 31 ------------------- .../src/Components/Concerns/HasPivotData.php | 31 +++++++++++++++++++ packages/forms/src/Components/Select.php | 12 +++++-- 5 files changed, 52 insertions(+), 36 deletions(-) delete mode 100644 packages/forms/src/Components/Concerns/HasPivotAttributes.php create mode 100644 packages/forms/src/Components/Concerns/HasPivotData.php diff --git a/packages/forms/docs/03-fields/03-select.md b/packages/forms/docs/03-fields/03-select.md index 4bef10b888..bba9e8cb1b 100644 --- a/packages/forms/docs/03-fields/03-select.md +++ b/packages/forms/docs/03-fields/03-select.md @@ -186,7 +186,7 @@ use Filament\Forms\Components\Select; Select::make('technologies') ->relationship(titleAttribute: 'name') - ->pivotAttributes([ + ->pivotData([ 'is_primary' => true, ]) ``` diff --git a/packages/forms/src/Components/CheckboxList.php b/packages/forms/src/Components/CheckboxList.php index deda4ff8a7..fc9576fb8b 100644 --- a/packages/forms/src/Components/CheckboxList.php +++ b/packages/forms/src/Components/CheckboxList.php @@ -24,7 +24,7 @@ class CheckboxList extends Field implements Contracts\CanDisableOptions, Contrac use Concerns\HasGridDirection; use Concerns\HasNestedRecursiveValidationRules; use Concerns\HasOptions; - use Concerns\HasPivotAttributes; + use Concerns\HasPivotData; /** * @var view-string @@ -186,7 +186,15 @@ class CheckboxList extends Field implements Contracts\CanDisableOptions, Contrac }); $this->saveRelationshipsUsing(static function (CheckboxList $component, ?array $state) { - $component->getRelationship()->syncWithPivotValues($state ?? [], $component->getPivotAttributes()); + $pivotData = $component->getPivotData(); + + if ($pivotData === []) { + $component->getRelationship()->sync($state ?? []); + + return; + } + + $component->getRelationship()->syncWithPivotValues($state ?? [], $pivotData); }); $this->dehydrated(false); diff --git a/packages/forms/src/Components/Concerns/HasPivotAttributes.php b/packages/forms/src/Components/Concerns/HasPivotAttributes.php deleted file mode 100644 index bba59853c2..0000000000 --- a/packages/forms/src/Components/Concerns/HasPivotAttributes.php +++ /dev/null @@ -1,31 +0,0 @@ -<?php - -namespace Filament\Forms\Components\Concerns; - -use Closure; - -trait HasPivotAttributes -{ - /** - * @var array<array<mixed> | Closure> - */ - protected array | Closure $pivotAttributes = []; - - /** - * @param array<mixed> | Closure $attributes - */ - public function pivotAttributes(array | Closure $attributes): static - { - $this->pivotAttributes = $attributes; - - return $this; - } - - /** - * @return array<mixed> - */ - public function getPivotAttributes(): ?array - { - return $this->evaluate($this->pivotAttributes); - } -} diff --git a/packages/forms/src/Components/Concerns/HasPivotData.php b/packages/forms/src/Components/Concerns/HasPivotData.php new file mode 100644 index 0000000000..ea4b817171 --- /dev/null +++ b/packages/forms/src/Components/Concerns/HasPivotData.php @@ -0,0 +1,31 @@ +<?php + +namespace Filament\Forms\Components\Concerns; + +use Closure; + +trait HasPivotData +{ + /** + * @var array<string, mixed> | Closure + */ + protected array | Closure $pivotData = []; + + /** + * @param array<string, mixed> | Closure $data + */ + public function pivotData(array | Closure $data): static + { + $this->pivotData = $data; + + return $this; + } + + /** + * @return array<string, mixed> + */ + public function getPivotData(): array + { + return $this->evaluate($this->pivotData) ?? []; + } +} diff --git a/packages/forms/src/Components/Select.php b/packages/forms/src/Components/Select.php index 193be941d0..ebed92312e 100644 --- a/packages/forms/src/Components/Select.php +++ b/packages/forms/src/Components/Select.php @@ -46,7 +46,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has use Concerns\HasLoadingMessage; use Concerns\HasNestedRecursiveValidationRules; use Concerns\HasOptions; - use Concerns\HasPivotAttributes; + use Concerns\HasPivotData; use Concerns\HasPlaceholder; use HasExtraAlpineAttributes; @@ -964,7 +964,15 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has return; } - $relationship->syncWithPivotValues($state ?? [], $component->getPivotAttributes()); + $pivotData = $component->getPivotData(); + + if ($pivotData === []) { + $relationship->sync($state ?? []); + + return; + } + + $relationship->syncWithPivotValues($state ?? [], $pivotData); }); $this->createOptionUsing(static function (Select $component, array $data, Form $form) { From 4deb638f698445f6781008efa92655c32e10872a Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 13:37:40 +0000 Subject: [PATCH 77/87] docs --- packages/forms/docs/03-fields/03-select.md | 28 ++++++++++--------- .../forms/docs/03-fields/06-checkbox-list.md | 26 +++++++++-------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/packages/forms/docs/03-fields/03-select.md b/packages/forms/docs/03-fields/03-select.md index bba9e8cb1b..1da5a36f40 100644 --- a/packages/forms/docs/03-fields/03-select.md +++ b/packages/forms/docs/03-fields/03-select.md @@ -179,19 +179,6 @@ Select::make('technologies') ->relationship(titleAttribute: 'name') ``` -If you're using a `BelongsToMany` relationship and your pivot table has additional columns, you can use the `pivotAttributes()` method to specify the pivot attributes that should be saved: - -```php -use Filament\Forms\Components\Select; - -Select::make('technologies') - ->relationship(titleAttribute: 'name') - ->pivotData([ - 'is_primary' => true, - ]) -``` - - ### Searching relationship options across multiple columns By default, if the select is also searchable, Filament will return search results for the relationship based on the title column of the relationship. If you'd like to search across multiple columns, you can pass an array of columns to the `searchable()` method: @@ -277,6 +264,21 @@ Select::make('author_id') ->searchable(['first_name', 'last_name']) ``` +### Saving pivot data to the relationship + +If you're using a `multiple()` relationship and your pivot table has additional columns, you can use the `pivotData()` method to specify the data that should be saved in them: + +```php +use Filament\Forms\Components\Select; + +Select::make('primaryTechnologies') + ->relationship(name: 'technologies', titleAttribute: 'name') + ->multiple() + ->pivotData([ + 'is_primary' => true, + ]) +``` + ### Creating a new option in a modal You may define a custom form that can be used to create a new record and attach it to the `BelongsTo` relationship: diff --git a/packages/forms/docs/03-fields/06-checkbox-list.md b/packages/forms/docs/03-fields/06-checkbox-list.md index e21e827204..c6155c4983 100644 --- a/packages/forms/docs/03-fields/06-checkbox-list.md +++ b/packages/forms/docs/03-fields/06-checkbox-list.md @@ -196,18 +196,6 @@ CheckboxList::make('technologies') ->relationship(titleAttribute: 'name') ``` -If you're using a `BelongsToMany` relationship and your pivot table has additional columns, you can use the `pivotAttributes()` method to specify the pivot attributes that should be saved: - -```php -use Filament\Forms\Components\Select; - -CheckboxList::make('technologies') - ->relationship(titleAttribute: 'name') - ->pivotAttributes([ - 'is_primary' => true, - ]) -``` - ### Customizing the relationship query You may customize the database query that retrieves options using the `modifyOptionsQueryUsing` parameter of the `relationship()` method: @@ -252,6 +240,20 @@ CheckboxList::make('authors') ->getOptionLabelFromRecordUsing(fn (Model $record) => "{$record->first_name} {$record->last_name}") ``` +### Saving pivot data to the relationship + +If your pivot table has additional columns, you can use the `pivotData()` method to specify the data that should be saved in them: + +```php +use Filament\Forms\Components\CheckboxList; + +CheckboxList::make('primaryTechnologies') + ->relationship(name: 'technologies', titleAttribute: 'name') + ->pivotData([ + 'is_primary' => true, + ]) +``` + ## Setting a custom no search results message When you're using a searchable checkbox list, you may want to display a custom message when no search results are found. You can do this using the `noSearchResultsMessage()` method: From 3aea0244f467284f8fcb3922f4c701d71d93d926 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 13:39:34 +0000 Subject: [PATCH 78/87] Update composer.lock --- composer.lock | 154 +++++++++++++++++++++++++------------------------- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/composer.lock b/composer.lock index 6ea2ccb7e5..6c2ce0286d 100644 --- a/composer.lock +++ b/composer.lock @@ -129,16 +129,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.299.1", + "version": "3.300.3", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "a0f87b8e8bfb9afd0ffd702fcda556b465eee457" + "reference": "a1202d1a82593fc2cdad54d627e54c518a984738" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a0f87b8e8bfb9afd0ffd702fcda556b465eee457", - "reference": "a0f87b8e8bfb9afd0ffd702fcda556b465eee457", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a1202d1a82593fc2cdad54d627e54c518a984738", + "reference": "a1202d1a82593fc2cdad54d627e54c518a984738", "shasum": "" }, "require": { @@ -218,9 +218,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.299.1" + "source": "https://github.com/aws/aws-sdk-php/tree/3.300.3" }, - "time": "2024-02-16T19:08:34+00:00" + "time": "2024-02-22T19:20:21+00:00" }, { "name": "blade-ui-kit/blade-heroicons", @@ -374,16 +374,16 @@ }, { "name": "brianium/paratest", - "version": "v7.4.1", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "b2830e330011d59a799c0002e118f5b4bbdb9604" + "reference": "64fcfd0e28a6b8078a19dbf9127be2ee645b92ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/b2830e330011d59a799c0002e118f5b4bbdb9604", - "reference": "b2830e330011d59a799c0002e118f5b4bbdb9604", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/64fcfd0e28a6b8078a19dbf9127be2ee645b92ec", + "reference": "64fcfd0e28a6b8078a19dbf9127be2ee645b92ec", "shasum": "" }, "require": { @@ -391,13 +391,13 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-simplexml": "*", - "fidry/cpu-core-counter": "^1.0.0", + "fidry/cpu-core-counter": "^1.1.0", "jean85/pretty-package-versions": "^2.0.5", "php": "~8.2.0 || ~8.3.0", "phpunit/php-code-coverage": "^10.1.11 || ^11.0.0", "phpunit/php-file-iterator": "^4.1.0 || ^5.0.0", "phpunit/php-timer": "^6.0.0 || ^7.0.0", - "phpunit/phpunit": "^10.5.9 || ^11.0.2", + "phpunit/phpunit": "^10.5.9 || ^11.0.3", "sebastian/environment": "^6.0.1 || ^7.0.0", "symfony/console": "^6.4.3 || ^7.0.3", "symfony/process": "^6.4.3 || ^7.0.3" @@ -406,11 +406,11 @@ "doctrine/coding-standard": "^12.0.0", "ext-pcov": "*", "ext-posix": "*", - "phpstan/phpstan": "^1.10.57", + "phpstan/phpstan": "^1.10.58", "phpstan/phpstan-deprecation-rules": "^1.1.4", "phpstan/phpstan-phpunit": "^1.3.15", "phpstan/phpstan-strict-rules": "^1.5.2", - "squizlabs/php_codesniffer": "^3.8.1", + "squizlabs/php_codesniffer": "^3.9.0", "symfony/filesystem": "^6.4.3 || ^7.0.3" }, "bin": [ @@ -452,7 +452,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.4.1" + "source": "https://github.com/paratestphp/paratest/tree/v7.4.3" }, "funding": [ { @@ -464,7 +464,7 @@ "type": "paypal" } ], - "time": "2024-02-06T13:50:28+00:00" + "time": "2024-02-20T07:24:02+00:00" }, { "name": "brick/math", @@ -1570,15 +1570,15 @@ "dist": { "type": "path", "url": "packages/support", - "reference": "70668ccdd8bce1e3df337ed3e483150a70207728" + "reference": "099ac9c8ddf7d2d6fdb9ccd8ed7d43782645bd4f" }, "require": { "blade-ui-kit/blade-heroicons": "^2.2.1", "doctrine/dbal": "^3.2", "ext-intl": "*", - "illuminate/contracts": "^10.0", - "illuminate/support": "^10.0", - "illuminate/view": "^10.0", + "illuminate/contracts": "^10.45", + "illuminate/support": "^10.45", + "illuminate/view": "^10.45", "livewire/livewire": "^3.2.3", "php": "^8.1", "ryangjchandler/blade-capture-directive": "^0.2|^0.3", @@ -2593,16 +2593,16 @@ }, { "name": "laravel/framework", - "version": "v10.44.0", + "version": "v10.45.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "1199dbe361787bbe9648131a79f53921b4148cf6" + "reference": "dcf5d1d722b84ad38a5e053289130b6962f830bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/1199dbe361787bbe9648131a79f53921b4148cf6", - "reference": "1199dbe361787bbe9648131a79f53921b4148cf6", + "url": "https://api.github.com/repos/laravel/framework/zipball/dcf5d1d722b84ad38a5e053289130b6962f830bd", + "reference": "dcf5d1d722b84ad38a5e053289130b6962f830bd", "shasum": "" }, "require": { @@ -2795,20 +2795,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-02-13T16:01:16+00:00" + "time": "2024-02-21T14:07:36+00:00" }, { "name": "laravel/pint", - "version": "v1.13.11", + "version": "v1.14.0", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "60a163c3e7e3346a1dec96d3e6f02e6465452552" + "reference": "6b127276e3f263f7bb17d5077e9e0269e61b2a0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/60a163c3e7e3346a1dec96d3e6f02e6465452552", - "reference": "60a163c3e7e3346a1dec96d3e6f02e6465452552", + "url": "https://api.github.com/repos/laravel/pint/zipball/6b127276e3f263f7bb17d5077e9e0269e61b2a0e", + "reference": "6b127276e3f263f7bb17d5077e9e0269e61b2a0e", "shasum": "" }, "require": { @@ -2861,7 +2861,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2024-02-13T17:20:13+00:00" + "time": "2024-02-20T17:38:05+00:00" }, { "name": "laravel/prompts", @@ -3236,16 +3236,16 @@ }, { "name": "league/csv", - "version": "9.14.0", + "version": "9.15.0", "source": { "type": "git", "url": "https://github.com/thephpleague/csv.git", - "reference": "34bf0df7340b60824b9449b5c526fcc3325070d5" + "reference": "fa7e2441c0bc9b2360f4314fd6c954f7ff40d435" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/csv/zipball/34bf0df7340b60824b9449b5c526fcc3325070d5", - "reference": "34bf0df7340b60824b9449b5c526fcc3325070d5", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/fa7e2441c0bc9b2360f4314fd6c954f7ff40d435", + "reference": "fa7e2441c0bc9b2360f4314fd6c954f7ff40d435", "shasum": "" }, "require": { @@ -3260,12 +3260,12 @@ "ext-xdebug": "*", "friendsofphp/php-cs-fixer": "^v3.22.0", "phpbench/phpbench": "^1.2.15", - "phpstan/phpstan": "^1.10.50", + "phpstan/phpstan": "^1.10.57", "phpstan/phpstan-deprecation-rules": "^1.1.4", "phpstan/phpstan-phpunit": "^1.3.15", "phpstan/phpstan-strict-rules": "^1.5.2", - "phpunit/phpunit": "^10.5.3", - "symfony/var-dumper": "^6.4.0" + "phpunit/phpunit": "^10.5.9", + "symfony/var-dumper": "^6.4.2" }, "suggest": { "ext-dom": "Required to use the XMLConverter and the HTMLConverter classes", @@ -3321,7 +3321,7 @@ "type": "github" } ], - "time": "2023-12-29T07:34:53+00:00" + "time": "2024-02-20T20:00:00+00:00" }, { "name": "league/flysystem", @@ -3770,16 +3770,16 @@ }, { "name": "livewire/livewire", - "version": "v3.4.4", + "version": "v3.4.6", "source": { "type": "git", "url": "https://github.com/livewire/livewire.git", - "reference": "c0489d4a76382f6dcf6e2702112f86aa089d0c8d" + "reference": "7e7d638183b34fb61621455891869f5abfd55a82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/livewire/livewire/zipball/c0489d4a76382f6dcf6e2702112f86aa089d0c8d", - "reference": "c0489d4a76382f6dcf6e2702112f86aa089d0c8d", + "url": "https://api.github.com/repos/livewire/livewire/zipball/7e7d638183b34fb61621455891869f5abfd55a82", + "reference": "7e7d638183b34fb61621455891869f5abfd55a82", "shasum": "" }, "require": { @@ -3833,7 +3833,7 @@ "description": "A front-end framework for Laravel.", "support": { "issues": "https://github.com/livewire/livewire/issues", - "source": "https://github.com/livewire/livewire/tree/v3.4.4" + "source": "https://github.com/livewire/livewire/tree/v3.4.6" }, "funding": [ { @@ -3841,7 +3841,7 @@ "type": "github" } ], - "time": "2024-01-28T19:07:11+00:00" + "time": "2024-02-20T14:04:25+00:00" }, { "name": "maennchen/zipstream-php", @@ -4645,16 +4645,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.0.0", + "version": "v5.0.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc" + "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4a21235f7e56e713259a6f76bf4b5ea08502b9dc", - "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/2218c2252c874a4624ab2f613d86ac32d227bc69", + "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69", "shasum": "" }, "require": { @@ -4697,9 +4697,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.1" }, - "time": "2024-01-07T17:17:35+00:00" + "time": "2024-02-21T19:24:10+00:00" }, { "name": "nunomaduro/collision", @@ -5180,16 +5180,16 @@ }, { "name": "orchestra/testbench-core", - "version": "v8.21.1", + "version": "v8.22.1", "source": { "type": "git", "url": "https://github.com/orchestral/testbench-core.git", - "reference": "c6bf49a1b7ef4afe58e5bda676158c4de41f9a81" + "reference": "b0006c092694828f4b0fa409a369b798e5e26f8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/c6bf49a1b7ef4afe58e5bda676158c4de41f9a81", - "reference": "c6bf49a1b7ef4afe58e5bda676158c4de41f9a81", + "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/b0006c092694828f4b0fa409a369b798e5e26f8d", + "reference": "b0006c092694828f4b0fa409a369b798e5e26f8d", "shasum": "" }, "require": { @@ -5268,7 +5268,7 @@ "issues": "https://github.com/orchestral/testbench/issues", "source": "https://github.com/orchestral/testbench-core" }, - "time": "2024-01-22T01:45:47+00:00" + "time": "2024-02-21T23:33:22+00:00" }, { "name": "orchestra/workbench", @@ -5886,21 +5886,21 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.8.0", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc" + "reference": "153ae662783729388a584b4361f2545e4d841e3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fad452781b3d774e3337b0c0b245dd8e5a4455fc", - "reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", + "reference": "153ae662783729388a584b4361f2545e4d841e3c", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", - "php": "^7.4 || ^8.0", + "php": "^7.3 || ^8.0", "phpdocumentor/reflection-common": "^2.0", "phpstan/phpdoc-parser": "^1.13" }, @@ -5938,9 +5938,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" }, - "time": "2024-01-11T11:49:22+00:00" + "time": "2024-02-23T11:10:43+00:00" }, { "name": "phpmyadmin/sql-parser", @@ -8930,16 +8930,16 @@ }, { "name": "spatie/laravel-medialibrary", - "version": "11.4.1", + "version": "11.4.4", "source": { "type": "git", "url": "https://github.com/spatie/laravel-medialibrary.git", - "reference": "d94b110c2ee9a0602ae1be9bf59e91ae8dab28cf" + "reference": "bb29cacfe209856db304adc6c5ba8c05ff7a8802" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/d94b110c2ee9a0602ae1be9bf59e91ae8dab28cf", - "reference": "d94b110c2ee9a0602ae1be9bf59e91ae8dab28cf", + "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/bb29cacfe209856db304adc6c5ba8c05ff7a8802", + "reference": "bb29cacfe209856db304adc6c5ba8c05ff7a8802", "shasum": "" }, "require": { @@ -9022,7 +9022,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-medialibrary/issues", - "source": "https://github.com/spatie/laravel-medialibrary/tree/11.4.1" + "source": "https://github.com/spatie/laravel-medialibrary/tree/11.4.4" }, "funding": [ { @@ -9034,7 +9034,7 @@ "type": "github" } ], - "time": "2024-02-17T12:22:37+00:00" + "time": "2024-02-22T09:39:31+00:00" }, { "name": "spatie/laravel-package-tools", @@ -9183,20 +9183,20 @@ }, { "name": "spatie/laravel-tags", - "version": "4.5.2", + "version": "4.6.0", "source": { "type": "git", "url": "https://github.com/spatie/laravel-tags.git", - "reference": "627587878731650c52d79e2132cfd1410a18d428" + "reference": "ddcc82e1149c4720c0eaa02d171f50a1cdd1cb46" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-tags/zipball/627587878731650c52d79e2132cfd1410a18d428", - "reference": "627587878731650c52d79e2132cfd1410a18d428", + "url": "https://api.github.com/repos/spatie/laravel-tags/zipball/ddcc82e1149c4720c0eaa02d171f50a1cdd1cb46", + "reference": "ddcc82e1149c4720c0eaa02d171f50a1cdd1cb46", "shasum": "" }, "require": { - "laravel/framework": "^8.67|^9.0|^10.0", + "laravel/framework": "^8.67|^9.0|^10.0|^11.0", "nesbot/carbon": "^2.63", "php": "^8.0", "spatie/eloquent-sortable": "^3.10|^4.0", @@ -9204,8 +9204,8 @@ "spatie/laravel-translatable": "^4.6|^5.0|^6.0" }, "require-dev": { - "orchestra/testbench": "^6.13|^7.0|^8.0", - "pestphp/pest": "^1.22", + "orchestra/testbench": "^6.13|^7.0|^8.0|^9.0", + "pestphp/pest": "^1.22|^2.0", "phpunit/phpunit": "^9.5.2" }, "type": "library", @@ -9241,7 +9241,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-tags/issues", - "source": "https://github.com/spatie/laravel-tags/tree/4.5.2" + "source": "https://github.com/spatie/laravel-tags/tree/4.6.0" }, "funding": [ { @@ -9249,7 +9249,7 @@ "type": "github" } ], - "time": "2024-01-19T22:10:13+00:00" + "time": "2024-02-21T12:13:18+00:00" }, { "name": "spatie/laravel-translatable", From 81314008759d57c779360b5967bef3d42cafd2e8 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 13:51:15 +0000 Subject: [PATCH 79/87] Revert "Update 12-repeater.md" This reverts commit 2058210b4b83d22c16af133d2f4260bda6fe57dd. --- packages/forms/docs/03-fields/12-repeater.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/forms/docs/03-fields/12-repeater.md b/packages/forms/docs/03-fields/12-repeater.md index d83ea88f17..90d3a2a068 100644 --- a/packages/forms/docs/03-fields/12-repeater.md +++ b/packages/forms/docs/03-fields/12-repeater.md @@ -219,22 +219,6 @@ Repeater::make('qualifications') ]) ``` -When using a Select field depending on a relationship nested within the Repeater schema, it may be necesary to use `saveRelationshipsUsing(null)` if you experience an `Call to undefined method Illuminate\Database\Eloquent\Relations\HasOne::associate()` exception. - -```php -use Filament\Forms\Components\Repeater; -use Filament\Forms\Components\Select; - -Repeater::make('specimens') - ->relationship('specimens') - ->schema([ - Select::make('specimen_container_id') - ->relationship('specimen_container') - ->saveRelationshipsUsing(null), - // ... - ]) -``` - When using `disabled()` with `relationship()`, ensure that `disabled()` is called before `relationship()`. This ensures that the `dehydrated()` call from within `relationship()` is not overridden by the call from `disabled()`: ```php From c392b86daeedbfc18cc693ec7243d20c58ed7b4b Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 13:54:30 +0000 Subject: [PATCH 80/87] Update Select.php --- packages/forms/src/Components/Select.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/forms/src/Components/Select.php b/packages/forms/src/Components/Select.php index cc52608006..95f76b592b 100644 --- a/packages/forms/src/Components/Select.php +++ b/packages/forms/src/Components/Select.php @@ -18,6 +18,8 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Database\Eloquent\Relations\HasManyThrough; +use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasOneOrMany; use Illuminate\Database\Eloquent\Relations\HasOneThrough; use Illuminate\Database\Eloquent\Relations\Relation; @@ -842,7 +844,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has } if ( - ($relationship instanceof HasOneThrough) || + ($relationship instanceof HasManyThrough) || ($relationship instanceof \Znck\Eloquent\Relations\BelongsToThrough) ) { $relatedModel = $relationship->getResults(); @@ -965,7 +967,11 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has $this->saveRelationshipsUsing(static function (Select $component, Model $record, $state) { $relationship = $component->getRelationship(); - if ($relationship instanceof \Znck\Eloquent\Relations\BelongsToThrough) { + if ( + ($relationship instanceof HasOneOrMany) || + ($relationship instanceof HasManyThrough) || + ($relationship instanceof \Znck\Eloquent\Relations\BelongsToThrough) + ) { return; } @@ -1076,7 +1082,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has return parent::getLabel(); } - public function getRelationship(): BelongsTo | BelongsToMany | HasOneOrMany | HasOneThrough | \Znck\Eloquent\Relations\BelongsToThrough | null + public function getRelationship(): BelongsTo | BelongsToMany | HasOneOrMany | HasManyThrough | \Znck\Eloquent\Relations\BelongsToThrough | null { if (blank($this->getRelationshipName())) { return null; @@ -1201,7 +1207,7 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has return $relationship->getQualifiedRelatedKeyName(); } - if ($relationship instanceof HasOneThrough) { + if ($relationship instanceof HasManyThrough) { return $relationship->getQualifiedForeignKeyName(); } From 7010f542eb814dbfb941f9ea5f7648d95a686bbd Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 13:54:43 +0000 Subject: [PATCH 81/87] Update Select.php --- packages/forms/src/Components/Select.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/forms/src/Components/Select.php b/packages/forms/src/Components/Select.php index 02fa235f98..6a8d618620 100644 --- a/packages/forms/src/Components/Select.php +++ b/packages/forms/src/Components/Select.php @@ -19,9 +19,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasManyThrough; -use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasOneOrMany; -use Illuminate\Database\Eloquent\Relations\HasOneThrough; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Arr; use Illuminate\Support\Str; From ad4df89e7463763c96ae7405110b39653e281c02 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 18:29:41 +0000 Subject: [PATCH 82/87] Update helpers.php --- packages/support/src/helpers.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/support/src/helpers.php b/packages/support/src/helpers.php index 988cb2c2c7..14d4785e5f 100644 --- a/packages/support/src/helpers.php +++ b/packages/support/src/helpers.php @@ -11,6 +11,7 @@ use Illuminate\Support\HtmlString; use Illuminate\Support\Str; use Illuminate\Translation\MessageSelector; use Illuminate\View\ComponentAttributeBag; +use Illuminate\View\ComponentSlot; use NumberFormatter; if (! function_exists('Filament\Support\format_money')) { @@ -118,6 +119,10 @@ if (! function_exists('Filament\Support\is_slot_empty')) { return true; } + if (! $slot instanceof ComponentSlot) { + $slot = new ComponentSlot($slot->toHtml()); + } + return $slot->hasActualContent(); } } From 62418045527573b2910b85f9bb1c41caa889b60c Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 19:25:34 +0000 Subject: [PATCH 83/87] Update helpers.php --- packages/support/src/helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/support/src/helpers.php b/packages/support/src/helpers.php index 0fd1b2a521..9512062bd5 100644 --- a/packages/support/src/helpers.php +++ b/packages/support/src/helpers.php @@ -125,7 +125,7 @@ if (! function_exists('Filament\Support\is_slot_empty')) { $slot = new ComponentSlot($slot->toHtml()); } - return $slot->hasActualContent(); + return ! $slot->hasActualContent(); } } From a89100e1e3d79a7260852fac0ba6b91382eea582 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 19:26:45 +0000 Subject: [PATCH 84/87] compile --- docs-assets/app/public/js/filament/filament/app.js | 2 +- packages/panels/dist/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs-assets/app/public/js/filament/filament/app.js b/docs-assets/app/public/js/filament/filament/app.js index 6edaa63227..1ea8686be2 100644 --- a/docs-assets/app/public/js/filament/filament/app.js +++ b/docs-assets/app/public/js/filament/filament/app.js @@ -1 +1 @@ -(()=>{var Z=Object.create,L=Object.defineProperty,ee=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty,re=Object.getOwnPropertyNames,ne=Object.getOwnPropertyDescriptor,ae=o=>L(o,"__esModule",{value:!0}),ie=(o,n)=>()=>(n||(n={exports:{}},o(n.exports,n)),n.exports),se=(o,n,p)=>{if(n&&typeof n=="object"||typeof n=="function")for(let d of re(n))!te.call(o,d)&&d!=="default"&&L(o,d,{get:()=>n[d],enumerable:!(p=ne(n,d))||p.enumerable});return o},oe=o=>se(ae(L(o!=null?Z(ee(o)):{},"default",o&&o.__esModule&&"default"in o?{get:()=>o.default,enumerable:!0}:{value:o,enumerable:!0})),o),fe=ie((o,n)=>{(function(p,d,P){if(!p)return;for(var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},y={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},g={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},q={option:"alt",command:"meta",return:"enter",escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},S,w=1;w<20;++w)h[111+w]="f"+w;for(w=0;w<=9;++w)h[w+96]=w.toString();function O(e,t,a){if(e.addEventListener){e.addEventListener(t,a,!1);return}e.attachEvent("on"+t,a)}function T(e){if(e.type=="keypress"){var t=String.fromCharCode(e.which);return e.shiftKey||(t=t.toLowerCase()),t}return h[e.which]?h[e.which]:y[e.which]?y[e.which]:String.fromCharCode(e.which).toLowerCase()}function $(e,t){return e.sort().join(",")===t.sort().join(",")}function B(e){var t=[];return e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.ctrlKey&&t.push("ctrl"),e.metaKey&&t.push("meta"),t}function V(e){if(e.preventDefault){e.preventDefault();return}e.returnValue=!1}function H(e){if(e.stopPropagation){e.stopPropagation();return}e.cancelBubble=!0}function C(e){return e=="shift"||e=="ctrl"||e=="alt"||e=="meta"}function J(){if(!S){S={};for(var e in h)e>95&&e<112||h.hasOwnProperty(e)&&(S[h[e]]=e)}return S}function U(e,t,a){return a||(a=J()[e]?"keydown":"keypress"),a=="keypress"&&t.length&&(a="keydown"),a}function X(e){return e==="+"?["+"]:(e=e.replace(/\+{2}/g,"+plus"),e.split("+"))}function I(e,t){var a,c,b,M=[];for(a=X(e),b=0;b<a.length;++b)c=a[b],q[c]&&(c=q[c]),t&&t!="keypress"&&g[c]&&(c=g[c],M.push("shift")),C(c)&&M.push(c);return t=U(c,M,t),{key:c,modifiers:M,action:t}}function D(e,t){return e===null||e===d?!1:e===t?!0:D(e.parentNode,t)}function v(e){var t=this;if(e=e||d,!(t instanceof v))return new v(e);t.target=e,t._callbacks={},t._directMap={};var a={},c,b=!1,M=!1,E=!1;function K(r){r=r||{};var s=!1,l;for(l in a){if(r[l]){s=!0;continue}a[l]=0}s||(E=!1)}function j(r,s,l,i,u,m){var f,_,A=[],k=l.type;if(!t._callbacks[r])return[];for(k=="keyup"&&C(r)&&(s=[r]),f=0;f<t._callbacks[r].length;++f)if(_=t._callbacks[r][f],!(!i&&_.seq&&a[_.seq]!=_.level)&&k==_.action&&(k=="keypress"&&!l.metaKey&&!l.ctrlKey||$(s,_.modifiers))){var Q=!i&&_.combo==u,W=i&&_.seq==i&&_.level==m;(Q||W)&&t._callbacks[r].splice(f,1),A.push(_)}return A}function x(r,s,l,i){t.stopCallback(s,s.target||s.srcElement,l,i)||r(s,l)===!1&&(V(s),H(s))}t._handleKey=function(r,s,l){var i=j(r,s,l),u,m={},f=0,_=!1;for(u=0;u<i.length;++u)i[u].seq&&(f=Math.max(f,i[u].level));for(u=0;u<i.length;++u){if(i[u].seq){if(i[u].level!=f)continue;_=!0,m[i[u].seq]=1,x(i[u].callback,l,i[u].combo,i[u].seq);continue}_||x(i[u].callback,l,i[u].combo)}var A=l.type=="keypress"&&M;l.type==E&&!C(r)&&!A&&K(m),M=_&&l.type=="keydown"};function G(r){typeof r.which!="number"&&(r.which=r.keyCode);var s=T(r);if(s){if(r.type=="keyup"&&b===s){b=!1;return}t.handleKey(s,B(r),r)}}function Y(){clearTimeout(c),c=setTimeout(K,1e3)}function z(r,s,l,i){a[r]=0;function u(k){return function(){E=k,++a[r],Y()}}function m(k){x(l,k,r),i!=="keyup"&&(b=T(k)),setTimeout(K,10)}for(var f=0;f<s.length;++f){var _=f+1===s.length,A=_?m:u(i||I(s[f+1]).action);N(s[f],A,i,r,f)}}function N(r,s,l,i,u){t._directMap[r+":"+l]=s,r=r.replace(/\s+/g," ");var m=r.split(" "),f;if(m.length>1){z(r,m,s,l);return}f=I(r,l),t._callbacks[f.key]=t._callbacks[f.key]||[],j(f.key,f.modifiers,{type:f.action},i,r,u),t._callbacks[f.key][i?"unshift":"push"]({callback:s,modifiers:f.modifiers,action:f.action,seq:i,level:u,combo:r})}t._bindMultiple=function(r,s,l){for(var i=0;i<r.length;++i)N(r[i],s,l)},O(e,"keypress",G),O(e,"keydown",G),O(e,"keyup",G)}v.prototype.bind=function(e,t,a){var c=this;return e=e instanceof Array?e:[e],c._bindMultiple.call(c,e,t,a),c},v.prototype.unbind=function(e,t){var a=this;return a.bind.call(a,e,function(){},t)},v.prototype.trigger=function(e,t){var a=this;return a._directMap[e+":"+t]&&a._directMap[e+":"+t]({},e),a},v.prototype.reset=function(){var e=this;return e._callbacks={},e._directMap={},e},v.prototype.stopCallback=function(e,t){var a=this;if((" "+t.className+" ").indexOf(" mousetrap ")>-1||D(t,a.target))return!1;if("composedPath"in e&&typeof e.composedPath=="function"){var c=e.composedPath()[0];c!==e.target&&(t=c)}return t.tagName=="INPUT"||t.tagName=="SELECT"||t.tagName=="TEXTAREA"||t.isContentEditable},v.prototype.handleKey=function(){var e=this;return e._handleKey.apply(e,arguments)},v.addKeycodes=function(e){for(var t in e)e.hasOwnProperty(t)&&(h[t]=e[t]);S=null},v.init=function(){var e=v(d);for(var t in e)t.charAt(0)!=="_"&&(v[t]=function(a){return function(){return e[a].apply(e,arguments)}}(t))},v.init(),p.Mousetrap=v,typeof n<"u"&&n.exports&&(n.exports=v),typeof define=="function"&&define.amd&&define(function(){return v})})(typeof window<"u"?window:null,typeof window<"u"?document:null)}),R=oe(fe());(function(o){if(o){var n={},p=o.prototype.stopCallback;o.prototype.stopCallback=function(d,P,h,y){var g=this;return g.paused?!0:n[h]||n[y]?!1:p.call(g,d,P,h)},o.prototype.bindGlobal=function(d,P,h){var y=this;if(y.bind(d,P,h),d instanceof Array){for(var g=0;g<d.length;g++)n[d[g]]=!0;return}n[d]=!0},o.init()}})(typeof Mousetrap<"u"?Mousetrap:void 0);var le=o=>{o.directive("mousetrap",(n,{modifiers:p,expression:d},{evaluate:P})=>{let h=()=>d?P(d):n.click();p=p.map(y=>y.replace("-","+")),p.includes("global")&&(p=p.filter(y=>y!=="global"),R.default.bindGlobal(p,y=>{y.preventDefault(),h()})),R.default.bind(p,y=>{y.preventDefault(),h()})})},F=le;document.addEventListener("alpine:init",()=>{window.Alpine.plugin(F),window.Alpine.store("sidebar",{isOpen:window.Alpine.$persist(!0).as("isOpen"),collapsedGroups:window.Alpine.$persist(null).as("collapsedGroups"),groupIsCollapsed:function(n){return this.collapsedGroups.includes(n)},collapseGroup:function(n){this.collapsedGroups.includes(n)||(this.collapsedGroups=this.collapsedGroups.concat(n))},toggleCollapsedGroup:function(n){this.collapsedGroups=this.collapsedGroups.includes(n)?this.collapsedGroups.filter(p=>p!==n):this.collapsedGroups.concat(n)},close:function(){this.isOpen=!1},open:function(){this.isOpen=!0}});let o=localStorage.getItem("theme")??"system";window.Alpine.store("theme",o==="dark"||o==="system"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),window.addEventListener("theme-changed",n=>{let p=n.detail;localStorage.setItem("theme",p),p==="system"&&(p=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),window.Alpine.store("theme",p)}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",n=>{localStorage.getItem("theme")==="system"&&window.Alpine.store("theme",n.matches?"dark":"light")}),window.Alpine.effect(()=>{window.Alpine.store("theme")==="dark"?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")})});})(); +(()=>{var Z=Object.create,L=Object.defineProperty,ee=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty,re=Object.getOwnPropertyNames,ne=Object.getOwnPropertyDescriptor,ae=s=>L(s,"__esModule",{value:!0}),ie=(s,n)=>()=>(n||(n={exports:{}},s(n.exports,n)),n.exports),oe=(s,n,p)=>{if(n&&typeof n=="object"||typeof n=="function")for(let d of re(n))!te.call(s,d)&&d!=="default"&&L(s,d,{get:()=>n[d],enumerable:!(p=ne(n,d))||p.enumerable});return s},se=s=>oe(ae(L(s!=null?Z(ee(s)):{},"default",s&&s.__esModule&&"default"in s?{get:()=>s.default,enumerable:!0}:{value:s,enumerable:!0})),s),fe=ie((s,n)=>{(function(p,d,M){if(!p)return;for(var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},y={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},g={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},q={option:"alt",command:"meta",return:"enter",escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},S,w=1;w<20;++w)h[111+w]="f"+w;for(w=0;w<=9;++w)h[w+96]=w.toString();function C(e,t,a){if(e.addEventListener){e.addEventListener(t,a,!1);return}e.attachEvent("on"+t,a)}function T(e){if(e.type=="keypress"){var t=String.fromCharCode(e.which);return e.shiftKey||(t=t.toLowerCase()),t}return h[e.which]?h[e.which]:y[e.which]?y[e.which]:String.fromCharCode(e.which).toLowerCase()}function V(e,t){return e.sort().join(",")===t.sort().join(",")}function $(e){var t=[];return e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.ctrlKey&&t.push("ctrl"),e.metaKey&&t.push("meta"),t}function B(e){if(e.preventDefault){e.preventDefault();return}e.returnValue=!1}function H(e){if(e.stopPropagation){e.stopPropagation();return}e.cancelBubble=!0}function O(e){return e=="shift"||e=="ctrl"||e=="alt"||e=="meta"}function J(){if(!S){S={};for(var e in h)e>95&&e<112||h.hasOwnProperty(e)&&(S[h[e]]=e)}return S}function U(e,t,a){return a||(a=J()[e]?"keydown":"keypress"),a=="keypress"&&t.length&&(a="keydown"),a}function X(e){return e==="+"?["+"]:(e=e.replace(/\+{2}/g,"+plus"),e.split("+"))}function I(e,t){var a,c,b,P=[];for(a=X(e),b=0;b<a.length;++b)c=a[b],q[c]&&(c=q[c]),t&&t!="keypress"&&g[c]&&(c=g[c],P.push("shift")),O(c)&&P.push(c);return t=U(c,P,t),{key:c,modifiers:P,action:t}}function D(e,t){return e===null||e===d?!1:e===t?!0:D(e.parentNode,t)}function v(e){var t=this;if(e=e||d,!(t instanceof v))return new v(e);t.target=e,t._callbacks={},t._directMap={};var a={},c,b=!1,P=!1,E=!1;function K(r){r=r||{};var o=!1,l;for(l in a){if(r[l]){o=!0;continue}a[l]=0}o||(E=!1)}function j(r,o,l,i,u,m){var f,_,A=[],k=l.type;if(!t._callbacks[r])return[];for(k=="keyup"&&O(r)&&(o=[r]),f=0;f<t._callbacks[r].length;++f)if(_=t._callbacks[r][f],!(!i&&_.seq&&a[_.seq]!=_.level)&&k==_.action&&(k=="keypress"&&!l.metaKey&&!l.ctrlKey||V(o,_.modifiers))){var Q=!i&&_.combo==u,W=i&&_.seq==i&&_.level==m;(Q||W)&&t._callbacks[r].splice(f,1),A.push(_)}return A}function x(r,o,l,i){t.stopCallback(o,o.target||o.srcElement,l,i)||r(o,l)===!1&&(B(o),H(o))}t._handleKey=function(r,o,l){var i=j(r,o,l),u,m={},f=0,_=!1;for(u=0;u<i.length;++u)i[u].seq&&(f=Math.max(f,i[u].level));for(u=0;u<i.length;++u){if(i[u].seq){if(i[u].level!=f)continue;_=!0,m[i[u].seq]=1,x(i[u].callback,l,i[u].combo,i[u].seq);continue}_||x(i[u].callback,l,i[u].combo)}var A=l.type=="keypress"&&P;l.type==E&&!O(r)&&!A&&K(m),P=_&&l.type=="keydown"};function G(r){typeof r.which!="number"&&(r.which=r.keyCode);var o=T(r);if(o){if(r.type=="keyup"&&b===o){b=!1;return}t.handleKey(o,$(r),r)}}function Y(){clearTimeout(c),c=setTimeout(K,1e3)}function z(r,o,l,i){a[r]=0;function u(k){return function(){E=k,++a[r],Y()}}function m(k){x(l,k,r),i!=="keyup"&&(b=T(k)),setTimeout(K,10)}for(var f=0;f<o.length;++f){var _=f+1===o.length,A=_?m:u(i||I(o[f+1]).action);N(o[f],A,i,r,f)}}function N(r,o,l,i,u){t._directMap[r+":"+l]=o,r=r.replace(/\s+/g," ");var m=r.split(" "),f;if(m.length>1){z(r,m,o,l);return}f=I(r,l),t._callbacks[f.key]=t._callbacks[f.key]||[],j(f.key,f.modifiers,{type:f.action},i,r,u),t._callbacks[f.key][i?"unshift":"push"]({callback:o,modifiers:f.modifiers,action:f.action,seq:i,level:u,combo:r})}t._bindMultiple=function(r,o,l){for(var i=0;i<r.length;++i)N(r[i],o,l)},C(e,"keypress",G),C(e,"keydown",G),C(e,"keyup",G)}v.prototype.bind=function(e,t,a){var c=this;return e=e instanceof Array?e:[e],c._bindMultiple.call(c,e,t,a),c},v.prototype.unbind=function(e,t){var a=this;return a.bind.call(a,e,function(){},t)},v.prototype.trigger=function(e,t){var a=this;return a._directMap[e+":"+t]&&a._directMap[e+":"+t]({},e),a},v.prototype.reset=function(){var e=this;return e._callbacks={},e._directMap={},e},v.prototype.stopCallback=function(e,t){var a=this;if((" "+t.className+" ").indexOf(" mousetrap ")>-1||D(t,a.target))return!1;if("composedPath"in e&&typeof e.composedPath=="function"){var c=e.composedPath()[0];c!==e.target&&(t=c)}return t.tagName=="INPUT"||t.tagName=="SELECT"||t.tagName=="TEXTAREA"||t.isContentEditable},v.prototype.handleKey=function(){var e=this;return e._handleKey.apply(e,arguments)},v.addKeycodes=function(e){for(var t in e)e.hasOwnProperty(t)&&(h[t]=e[t]);S=null},v.init=function(){var e=v(d);for(var t in e)t.charAt(0)!=="_"&&(v[t]=function(a){return function(){return e[a].apply(e,arguments)}}(t))},v.init(),p.Mousetrap=v,typeof n<"u"&&n.exports&&(n.exports=v),typeof define=="function"&&define.amd&&define(function(){return v})})(typeof window<"u"?window:null,typeof window<"u"?document:null)}),R=se(fe());(function(s){if(s){var n={},p=s.prototype.stopCallback;s.prototype.stopCallback=function(d,M,h,y){var g=this;return g.paused?!0:n[h]||n[y]?!1:p.call(g,d,M,h)},s.prototype.bindGlobal=function(d,M,h){var y=this;if(y.bind(d,M,h),d instanceof Array){for(var g=0;g<d.length;g++)n[d[g]]=!0;return}n[d]=!0},s.init()}})(typeof Mousetrap<"u"?Mousetrap:void 0);var le=s=>{s.directive("mousetrap",(n,{modifiers:p,expression:d},{evaluate:M})=>{let h=()=>d?M(d):n.click();p=p.map(y=>y.replace("-","+")),p.includes("global")&&(p=p.filter(y=>y!=="global"),R.default.bindGlobal(p,y=>{y.preventDefault(),h()})),R.default.bind(p,y=>{y.preventDefault(),h()})})},F=le;document.addEventListener("alpine:init",()=>{window.Alpine.plugin(F),window.Alpine.store("sidebar",{isOpen:window.Alpine.$persist(!0).as("isOpen"),collapsedGroups:window.Alpine.$persist(null).as("collapsedGroups"),groupIsCollapsed:function(n){return this.collapsedGroups.includes(n)},collapseGroup:function(n){this.collapsedGroups.includes(n)||(this.collapsedGroups=this.collapsedGroups.concat(n))},toggleCollapsedGroup:function(n){this.collapsedGroups=this.collapsedGroups.includes(n)?this.collapsedGroups.filter(p=>p!==n):this.collapsedGroups.concat(n)},close:function(){this.isOpen=!1},open:function(){this.isOpen=!0}});let s=localStorage.getItem("theme")??getComputedStyle(document.documentElement).getPropertyValue("--default-theme-mode");window.Alpine.store("theme",s==="dark"||s==="system"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),window.addEventListener("theme-changed",n=>{let p=n.detail;localStorage.setItem("theme",p),p==="system"&&(p=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),window.Alpine.store("theme",p)}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",n=>{localStorage.getItem("theme")==="system"&&window.Alpine.store("theme",n.matches?"dark":"light")}),window.Alpine.effect(()=>{window.Alpine.store("theme")==="dark"?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")})});})(); diff --git a/packages/panels/dist/index.js b/packages/panels/dist/index.js index 6edaa63227..1ea8686be2 100644 --- a/packages/panels/dist/index.js +++ b/packages/panels/dist/index.js @@ -1 +1 @@ -(()=>{var Z=Object.create,L=Object.defineProperty,ee=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty,re=Object.getOwnPropertyNames,ne=Object.getOwnPropertyDescriptor,ae=o=>L(o,"__esModule",{value:!0}),ie=(o,n)=>()=>(n||(n={exports:{}},o(n.exports,n)),n.exports),se=(o,n,p)=>{if(n&&typeof n=="object"||typeof n=="function")for(let d of re(n))!te.call(o,d)&&d!=="default"&&L(o,d,{get:()=>n[d],enumerable:!(p=ne(n,d))||p.enumerable});return o},oe=o=>se(ae(L(o!=null?Z(ee(o)):{},"default",o&&o.__esModule&&"default"in o?{get:()=>o.default,enumerable:!0}:{value:o,enumerable:!0})),o),fe=ie((o,n)=>{(function(p,d,P){if(!p)return;for(var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},y={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},g={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},q={option:"alt",command:"meta",return:"enter",escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},S,w=1;w<20;++w)h[111+w]="f"+w;for(w=0;w<=9;++w)h[w+96]=w.toString();function O(e,t,a){if(e.addEventListener){e.addEventListener(t,a,!1);return}e.attachEvent("on"+t,a)}function T(e){if(e.type=="keypress"){var t=String.fromCharCode(e.which);return e.shiftKey||(t=t.toLowerCase()),t}return h[e.which]?h[e.which]:y[e.which]?y[e.which]:String.fromCharCode(e.which).toLowerCase()}function $(e,t){return e.sort().join(",")===t.sort().join(",")}function B(e){var t=[];return e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.ctrlKey&&t.push("ctrl"),e.metaKey&&t.push("meta"),t}function V(e){if(e.preventDefault){e.preventDefault();return}e.returnValue=!1}function H(e){if(e.stopPropagation){e.stopPropagation();return}e.cancelBubble=!0}function C(e){return e=="shift"||e=="ctrl"||e=="alt"||e=="meta"}function J(){if(!S){S={};for(var e in h)e>95&&e<112||h.hasOwnProperty(e)&&(S[h[e]]=e)}return S}function U(e,t,a){return a||(a=J()[e]?"keydown":"keypress"),a=="keypress"&&t.length&&(a="keydown"),a}function X(e){return e==="+"?["+"]:(e=e.replace(/\+{2}/g,"+plus"),e.split("+"))}function I(e,t){var a,c,b,M=[];for(a=X(e),b=0;b<a.length;++b)c=a[b],q[c]&&(c=q[c]),t&&t!="keypress"&&g[c]&&(c=g[c],M.push("shift")),C(c)&&M.push(c);return t=U(c,M,t),{key:c,modifiers:M,action:t}}function D(e,t){return e===null||e===d?!1:e===t?!0:D(e.parentNode,t)}function v(e){var t=this;if(e=e||d,!(t instanceof v))return new v(e);t.target=e,t._callbacks={},t._directMap={};var a={},c,b=!1,M=!1,E=!1;function K(r){r=r||{};var s=!1,l;for(l in a){if(r[l]){s=!0;continue}a[l]=0}s||(E=!1)}function j(r,s,l,i,u,m){var f,_,A=[],k=l.type;if(!t._callbacks[r])return[];for(k=="keyup"&&C(r)&&(s=[r]),f=0;f<t._callbacks[r].length;++f)if(_=t._callbacks[r][f],!(!i&&_.seq&&a[_.seq]!=_.level)&&k==_.action&&(k=="keypress"&&!l.metaKey&&!l.ctrlKey||$(s,_.modifiers))){var Q=!i&&_.combo==u,W=i&&_.seq==i&&_.level==m;(Q||W)&&t._callbacks[r].splice(f,1),A.push(_)}return A}function x(r,s,l,i){t.stopCallback(s,s.target||s.srcElement,l,i)||r(s,l)===!1&&(V(s),H(s))}t._handleKey=function(r,s,l){var i=j(r,s,l),u,m={},f=0,_=!1;for(u=0;u<i.length;++u)i[u].seq&&(f=Math.max(f,i[u].level));for(u=0;u<i.length;++u){if(i[u].seq){if(i[u].level!=f)continue;_=!0,m[i[u].seq]=1,x(i[u].callback,l,i[u].combo,i[u].seq);continue}_||x(i[u].callback,l,i[u].combo)}var A=l.type=="keypress"&&M;l.type==E&&!C(r)&&!A&&K(m),M=_&&l.type=="keydown"};function G(r){typeof r.which!="number"&&(r.which=r.keyCode);var s=T(r);if(s){if(r.type=="keyup"&&b===s){b=!1;return}t.handleKey(s,B(r),r)}}function Y(){clearTimeout(c),c=setTimeout(K,1e3)}function z(r,s,l,i){a[r]=0;function u(k){return function(){E=k,++a[r],Y()}}function m(k){x(l,k,r),i!=="keyup"&&(b=T(k)),setTimeout(K,10)}for(var f=0;f<s.length;++f){var _=f+1===s.length,A=_?m:u(i||I(s[f+1]).action);N(s[f],A,i,r,f)}}function N(r,s,l,i,u){t._directMap[r+":"+l]=s,r=r.replace(/\s+/g," ");var m=r.split(" "),f;if(m.length>1){z(r,m,s,l);return}f=I(r,l),t._callbacks[f.key]=t._callbacks[f.key]||[],j(f.key,f.modifiers,{type:f.action},i,r,u),t._callbacks[f.key][i?"unshift":"push"]({callback:s,modifiers:f.modifiers,action:f.action,seq:i,level:u,combo:r})}t._bindMultiple=function(r,s,l){for(var i=0;i<r.length;++i)N(r[i],s,l)},O(e,"keypress",G),O(e,"keydown",G),O(e,"keyup",G)}v.prototype.bind=function(e,t,a){var c=this;return e=e instanceof Array?e:[e],c._bindMultiple.call(c,e,t,a),c},v.prototype.unbind=function(e,t){var a=this;return a.bind.call(a,e,function(){},t)},v.prototype.trigger=function(e,t){var a=this;return a._directMap[e+":"+t]&&a._directMap[e+":"+t]({},e),a},v.prototype.reset=function(){var e=this;return e._callbacks={},e._directMap={},e},v.prototype.stopCallback=function(e,t){var a=this;if((" "+t.className+" ").indexOf(" mousetrap ")>-1||D(t,a.target))return!1;if("composedPath"in e&&typeof e.composedPath=="function"){var c=e.composedPath()[0];c!==e.target&&(t=c)}return t.tagName=="INPUT"||t.tagName=="SELECT"||t.tagName=="TEXTAREA"||t.isContentEditable},v.prototype.handleKey=function(){var e=this;return e._handleKey.apply(e,arguments)},v.addKeycodes=function(e){for(var t in e)e.hasOwnProperty(t)&&(h[t]=e[t]);S=null},v.init=function(){var e=v(d);for(var t in e)t.charAt(0)!=="_"&&(v[t]=function(a){return function(){return e[a].apply(e,arguments)}}(t))},v.init(),p.Mousetrap=v,typeof n<"u"&&n.exports&&(n.exports=v),typeof define=="function"&&define.amd&&define(function(){return v})})(typeof window<"u"?window:null,typeof window<"u"?document:null)}),R=oe(fe());(function(o){if(o){var n={},p=o.prototype.stopCallback;o.prototype.stopCallback=function(d,P,h,y){var g=this;return g.paused?!0:n[h]||n[y]?!1:p.call(g,d,P,h)},o.prototype.bindGlobal=function(d,P,h){var y=this;if(y.bind(d,P,h),d instanceof Array){for(var g=0;g<d.length;g++)n[d[g]]=!0;return}n[d]=!0},o.init()}})(typeof Mousetrap<"u"?Mousetrap:void 0);var le=o=>{o.directive("mousetrap",(n,{modifiers:p,expression:d},{evaluate:P})=>{let h=()=>d?P(d):n.click();p=p.map(y=>y.replace("-","+")),p.includes("global")&&(p=p.filter(y=>y!=="global"),R.default.bindGlobal(p,y=>{y.preventDefault(),h()})),R.default.bind(p,y=>{y.preventDefault(),h()})})},F=le;document.addEventListener("alpine:init",()=>{window.Alpine.plugin(F),window.Alpine.store("sidebar",{isOpen:window.Alpine.$persist(!0).as("isOpen"),collapsedGroups:window.Alpine.$persist(null).as("collapsedGroups"),groupIsCollapsed:function(n){return this.collapsedGroups.includes(n)},collapseGroup:function(n){this.collapsedGroups.includes(n)||(this.collapsedGroups=this.collapsedGroups.concat(n))},toggleCollapsedGroup:function(n){this.collapsedGroups=this.collapsedGroups.includes(n)?this.collapsedGroups.filter(p=>p!==n):this.collapsedGroups.concat(n)},close:function(){this.isOpen=!1},open:function(){this.isOpen=!0}});let o=localStorage.getItem("theme")??"system";window.Alpine.store("theme",o==="dark"||o==="system"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),window.addEventListener("theme-changed",n=>{let p=n.detail;localStorage.setItem("theme",p),p==="system"&&(p=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),window.Alpine.store("theme",p)}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",n=>{localStorage.getItem("theme")==="system"&&window.Alpine.store("theme",n.matches?"dark":"light")}),window.Alpine.effect(()=>{window.Alpine.store("theme")==="dark"?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")})});})(); +(()=>{var Z=Object.create,L=Object.defineProperty,ee=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty,re=Object.getOwnPropertyNames,ne=Object.getOwnPropertyDescriptor,ae=s=>L(s,"__esModule",{value:!0}),ie=(s,n)=>()=>(n||(n={exports:{}},s(n.exports,n)),n.exports),oe=(s,n,p)=>{if(n&&typeof n=="object"||typeof n=="function")for(let d of re(n))!te.call(s,d)&&d!=="default"&&L(s,d,{get:()=>n[d],enumerable:!(p=ne(n,d))||p.enumerable});return s},se=s=>oe(ae(L(s!=null?Z(ee(s)):{},"default",s&&s.__esModule&&"default"in s?{get:()=>s.default,enumerable:!0}:{value:s,enumerable:!0})),s),fe=ie((s,n)=>{(function(p,d,M){if(!p)return;for(var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},y={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},g={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},q={option:"alt",command:"meta",return:"enter",escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},S,w=1;w<20;++w)h[111+w]="f"+w;for(w=0;w<=9;++w)h[w+96]=w.toString();function C(e,t,a){if(e.addEventListener){e.addEventListener(t,a,!1);return}e.attachEvent("on"+t,a)}function T(e){if(e.type=="keypress"){var t=String.fromCharCode(e.which);return e.shiftKey||(t=t.toLowerCase()),t}return h[e.which]?h[e.which]:y[e.which]?y[e.which]:String.fromCharCode(e.which).toLowerCase()}function V(e,t){return e.sort().join(",")===t.sort().join(",")}function $(e){var t=[];return e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.ctrlKey&&t.push("ctrl"),e.metaKey&&t.push("meta"),t}function B(e){if(e.preventDefault){e.preventDefault();return}e.returnValue=!1}function H(e){if(e.stopPropagation){e.stopPropagation();return}e.cancelBubble=!0}function O(e){return e=="shift"||e=="ctrl"||e=="alt"||e=="meta"}function J(){if(!S){S={};for(var e in h)e>95&&e<112||h.hasOwnProperty(e)&&(S[h[e]]=e)}return S}function U(e,t,a){return a||(a=J()[e]?"keydown":"keypress"),a=="keypress"&&t.length&&(a="keydown"),a}function X(e){return e==="+"?["+"]:(e=e.replace(/\+{2}/g,"+plus"),e.split("+"))}function I(e,t){var a,c,b,P=[];for(a=X(e),b=0;b<a.length;++b)c=a[b],q[c]&&(c=q[c]),t&&t!="keypress"&&g[c]&&(c=g[c],P.push("shift")),O(c)&&P.push(c);return t=U(c,P,t),{key:c,modifiers:P,action:t}}function D(e,t){return e===null||e===d?!1:e===t?!0:D(e.parentNode,t)}function v(e){var t=this;if(e=e||d,!(t instanceof v))return new v(e);t.target=e,t._callbacks={},t._directMap={};var a={},c,b=!1,P=!1,E=!1;function K(r){r=r||{};var o=!1,l;for(l in a){if(r[l]){o=!0;continue}a[l]=0}o||(E=!1)}function j(r,o,l,i,u,m){var f,_,A=[],k=l.type;if(!t._callbacks[r])return[];for(k=="keyup"&&O(r)&&(o=[r]),f=0;f<t._callbacks[r].length;++f)if(_=t._callbacks[r][f],!(!i&&_.seq&&a[_.seq]!=_.level)&&k==_.action&&(k=="keypress"&&!l.metaKey&&!l.ctrlKey||V(o,_.modifiers))){var Q=!i&&_.combo==u,W=i&&_.seq==i&&_.level==m;(Q||W)&&t._callbacks[r].splice(f,1),A.push(_)}return A}function x(r,o,l,i){t.stopCallback(o,o.target||o.srcElement,l,i)||r(o,l)===!1&&(B(o),H(o))}t._handleKey=function(r,o,l){var i=j(r,o,l),u,m={},f=0,_=!1;for(u=0;u<i.length;++u)i[u].seq&&(f=Math.max(f,i[u].level));for(u=0;u<i.length;++u){if(i[u].seq){if(i[u].level!=f)continue;_=!0,m[i[u].seq]=1,x(i[u].callback,l,i[u].combo,i[u].seq);continue}_||x(i[u].callback,l,i[u].combo)}var A=l.type=="keypress"&&P;l.type==E&&!O(r)&&!A&&K(m),P=_&&l.type=="keydown"};function G(r){typeof r.which!="number"&&(r.which=r.keyCode);var o=T(r);if(o){if(r.type=="keyup"&&b===o){b=!1;return}t.handleKey(o,$(r),r)}}function Y(){clearTimeout(c),c=setTimeout(K,1e3)}function z(r,o,l,i){a[r]=0;function u(k){return function(){E=k,++a[r],Y()}}function m(k){x(l,k,r),i!=="keyup"&&(b=T(k)),setTimeout(K,10)}for(var f=0;f<o.length;++f){var _=f+1===o.length,A=_?m:u(i||I(o[f+1]).action);N(o[f],A,i,r,f)}}function N(r,o,l,i,u){t._directMap[r+":"+l]=o,r=r.replace(/\s+/g," ");var m=r.split(" "),f;if(m.length>1){z(r,m,o,l);return}f=I(r,l),t._callbacks[f.key]=t._callbacks[f.key]||[],j(f.key,f.modifiers,{type:f.action},i,r,u),t._callbacks[f.key][i?"unshift":"push"]({callback:o,modifiers:f.modifiers,action:f.action,seq:i,level:u,combo:r})}t._bindMultiple=function(r,o,l){for(var i=0;i<r.length;++i)N(r[i],o,l)},C(e,"keypress",G),C(e,"keydown",G),C(e,"keyup",G)}v.prototype.bind=function(e,t,a){var c=this;return e=e instanceof Array?e:[e],c._bindMultiple.call(c,e,t,a),c},v.prototype.unbind=function(e,t){var a=this;return a.bind.call(a,e,function(){},t)},v.prototype.trigger=function(e,t){var a=this;return a._directMap[e+":"+t]&&a._directMap[e+":"+t]({},e),a},v.prototype.reset=function(){var e=this;return e._callbacks={},e._directMap={},e},v.prototype.stopCallback=function(e,t){var a=this;if((" "+t.className+" ").indexOf(" mousetrap ")>-1||D(t,a.target))return!1;if("composedPath"in e&&typeof e.composedPath=="function"){var c=e.composedPath()[0];c!==e.target&&(t=c)}return t.tagName=="INPUT"||t.tagName=="SELECT"||t.tagName=="TEXTAREA"||t.isContentEditable},v.prototype.handleKey=function(){var e=this;return e._handleKey.apply(e,arguments)},v.addKeycodes=function(e){for(var t in e)e.hasOwnProperty(t)&&(h[t]=e[t]);S=null},v.init=function(){var e=v(d);for(var t in e)t.charAt(0)!=="_"&&(v[t]=function(a){return function(){return e[a].apply(e,arguments)}}(t))},v.init(),p.Mousetrap=v,typeof n<"u"&&n.exports&&(n.exports=v),typeof define=="function"&&define.amd&&define(function(){return v})})(typeof window<"u"?window:null,typeof window<"u"?document:null)}),R=se(fe());(function(s){if(s){var n={},p=s.prototype.stopCallback;s.prototype.stopCallback=function(d,M,h,y){var g=this;return g.paused?!0:n[h]||n[y]?!1:p.call(g,d,M,h)},s.prototype.bindGlobal=function(d,M,h){var y=this;if(y.bind(d,M,h),d instanceof Array){for(var g=0;g<d.length;g++)n[d[g]]=!0;return}n[d]=!0},s.init()}})(typeof Mousetrap<"u"?Mousetrap:void 0);var le=s=>{s.directive("mousetrap",(n,{modifiers:p,expression:d},{evaluate:M})=>{let h=()=>d?M(d):n.click();p=p.map(y=>y.replace("-","+")),p.includes("global")&&(p=p.filter(y=>y!=="global"),R.default.bindGlobal(p,y=>{y.preventDefault(),h()})),R.default.bind(p,y=>{y.preventDefault(),h()})})},F=le;document.addEventListener("alpine:init",()=>{window.Alpine.plugin(F),window.Alpine.store("sidebar",{isOpen:window.Alpine.$persist(!0).as("isOpen"),collapsedGroups:window.Alpine.$persist(null).as("collapsedGroups"),groupIsCollapsed:function(n){return this.collapsedGroups.includes(n)},collapseGroup:function(n){this.collapsedGroups.includes(n)||(this.collapsedGroups=this.collapsedGroups.concat(n))},toggleCollapsedGroup:function(n){this.collapsedGroups=this.collapsedGroups.includes(n)?this.collapsedGroups.filter(p=>p!==n):this.collapsedGroups.concat(n)},close:function(){this.isOpen=!1},open:function(){this.isOpen=!0}});let s=localStorage.getItem("theme")??getComputedStyle(document.documentElement).getPropertyValue("--default-theme-mode");window.Alpine.store("theme",s==="dark"||s==="system"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),window.addEventListener("theme-changed",n=>{let p=n.detail;localStorage.setItem("theme",p),p==="system"&&(p=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),window.Alpine.store("theme",p)}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",n=>{localStorage.getItem("theme")==="system"&&window.Alpine.store("theme",n.matches?"dark":"light")}),window.Alpine.effect(()=>{window.Alpine.store("theme")==="dark"?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")})});})(); From 045d1c7f43a5cef057ec2cdd99b1372bbc6f8873 Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 19:28:47 +0000 Subject: [PATCH 85/87] fix: Nested Spatie relationships --- .../SpatieMediaLibraryImageEntry.php | 69 ++++++++------ .../Columns/SpatieMediaLibraryImageColumn.php | 91 +++++++++++-------- .../Infolists/Components/SpatieTagsEntry.php | 43 +++++---- .../src/Tables/Columns/SpatieTagsColumn.php | 47 ++++++---- 4 files changed, 153 insertions(+), 97 deletions(-) diff --git a/packages/spatie-laravel-media-library-plugin/src/Infolists/Components/SpatieMediaLibraryImageEntry.php b/packages/spatie-laravel-media-library-plugin/src/Infolists/Components/SpatieMediaLibraryImageEntry.php index b305bd1d28..b20ab2ad9a 100644 --- a/packages/spatie-laravel-media-library-plugin/src/Infolists/Components/SpatieMediaLibraryImageEntry.php +++ b/packages/spatie-laravel-media-library-plugin/src/Infolists/Components/SpatieMediaLibraryImageEntry.php @@ -3,6 +3,7 @@ namespace Filament\Infolists\Components; use Closure; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Arr; use Spatie\MediaLibrary\MediaCollections\Models\Media; use Throwable; @@ -46,34 +47,38 @@ class SpatieMediaLibraryImageEntry extends ImageEntry } if ($this->hasRelationship($record)) { - $record = $record->getRelationValue($this->getRelationshipName()); + $record = $this->getRelationshipResults($record); } - if (! $record) { - return null; - } + $records = Arr::wrap($record); - /** @var ?Media $media */ - $media = $record->media->first(fn (Media $media): bool => $media->uuid === $state); + foreach ($records as $record) { + /** @var Model $record */ - if (! $media) { - return null; - } + /** @var ?Media $media */ + $media = $record->getRelationValue('media')->first(fn (Media $media): bool => $media->uuid === $state); - $conversion = $this->getConversion(); - - if ($this->getVisibility() === 'private') { - try { - return $media->getTemporaryUrl( - now()->addMinutes(5), - $conversion ?? '', - ); - } catch (Throwable $exception) { - // This driver does not support creating temporary URLs. + if (! $media) { + continue; } + + $conversion = $this->getConversion(); + + if ($this->getVisibility() === 'private') { + try { + return $media->getTemporaryUrl( + now()->addMinutes(5), + $conversion ?? '', + ); + } catch (Throwable $exception) { + // This driver does not support creating temporary URLs. + } + } + + return $media->getAvailableUrl(Arr::wrap($conversion)); } - return $media->getAvailableUrl(Arr::wrap($conversion)); + return null; } /** @@ -86,13 +91,25 @@ class SpatieMediaLibraryImageEntry extends ImageEntry $record = $this->getRecord(); if ($this->hasRelationship($record)) { - $record = $record->getRelationValue($this->getRelationshipName()); + $record = $this->getRelationshipResults($record); } - return $record?->getRelationValue('media') - ->filter(fn (Media $media): bool => blank($collection) || ($media->getAttributeValue('collection_name') === $collection)) - ->sortBy('order_column') - ->map(fn (Media $media): string => $media->uuid) - ->all() ?? []; + $records = Arr::wrap($record); + + $state = []; + + foreach ($records as $record) { + /** @var Model $record */ + $state = [ + ...$state, + ...$record->getRelationValue('media') + ->filter(fn (Media $media): bool => blank($collection) || ($media->getAttributeValue('collection_name') === $collection)) + ->sortBy('order_column') + ->pluck('uuid') + ->all(), + ]; + } + + return array_unique($state); } } diff --git a/packages/spatie-laravel-media-library-plugin/src/Tables/Columns/SpatieMediaLibraryImageColumn.php b/packages/spatie-laravel-media-library-plugin/src/Tables/Columns/SpatieMediaLibraryImageColumn.php index c109e7e6a2..59b9a9e011 100644 --- a/packages/spatie-laravel-media-library-plugin/src/Tables/Columns/SpatieMediaLibraryImageColumn.php +++ b/packages/spatie-laravel-media-library-plugin/src/Tables/Columns/SpatieMediaLibraryImageColumn.php @@ -4,6 +4,7 @@ namespace Filament\Tables\Columns; use Closure; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Arr; use Spatie\MediaLibrary\MediaCollections\Models\Media; @@ -44,34 +45,38 @@ class SpatieMediaLibraryImageColumn extends ImageColumn $record = $this->getRecord(); if ($this->hasRelationship($record)) { - $record = $record->getRelationValue($this->getRelationshipName()); + $record = $this->getRelationshipResults($record); } - if (! $record) { - return null; - } + $records = Arr::wrap($record); - /** @var ?Media $media */ - $media = $record->media->first(fn (Media $media): bool => $media->uuid === $state); + foreach ($records as $record) { + /** @var Model $record */ - if (! $media) { - return null; - } + /** @var ?Media $media */ + $media = $record->getRelationValue('media')->first(fn (Media $media): bool => $media->uuid === $state); - $conversion = $this->getConversion(); - - if ($this->getVisibility() === 'private') { - try { - return $media->getTemporaryUrl( - now()->addMinutes(5), - $conversion ?? '', - ); - } catch (Throwable $exception) { - // This driver does not support creating temporary URLs. + if (! $media) { + continue; } + + $conversion = $this->getConversion(); + + if ($this->getVisibility() === 'private') { + try { + return $media->getTemporaryUrl( + now()->addMinutes(5), + $conversion ?? '', + ); + } catch (Throwable $exception) { + // This driver does not support creating temporary URLs. + } + } + + return $media->getAvailableUrl(Arr::wrap($conversion)); } - return $media->getAvailableUrl(Arr::wrap($conversion)); + return null; } /** @@ -79,19 +84,28 @@ class SpatieMediaLibraryImageColumn extends ImageColumn */ public function getState(): array { - $collection = $this->getCollection(); - $record = $this->getRecord(); if ($this->hasRelationship($record)) { - $record = $record->getRelationValue($this->getRelationshipName()); + $record = $this->getRelationshipResults($record); } - return $record?->getRelationValue('media') - ->filter(fn (Media $media): bool => blank($collection) || ($media->getAttributeValue('collection_name') === $collection)) - ->sortBy('order_column') - ->map(fn (Media $media): string => $media->uuid) - ->all() ?? []; + $records = Arr::wrap($record); + + $state = []; + + foreach ($records as $record) { + /** @var Model $record */ + $state = [ + ...$state, + ...$record->getRelationValue('media') + ->sortBy('order_column') + ->pluck('uuid') + ->all(), + ]; + } + + return array_unique($state); } public function applyEagerLoading(Builder | Relation $query): Builder | Relation @@ -100,18 +114,23 @@ class SpatieMediaLibraryImageColumn extends ImageColumn return $query; } + /** @phpstan-ignore-next-line */ + $modifyMediaQuery = fn (Builder | Relation $query) => $query + ->ordered() + ->when( + $this->getCollection(), + fn (Builder | Relation $query, string $collection) => $query->where( + 'collection_name', + $collection, + ), + ); + if ($this->hasRelationship($query->getModel())) { return $query->with([ - "{$this->getRelationshipName()}.media" => fn (Builder | Relation $query) => $query->when( - $this->getCollection(), - fn (Builder | Relation $query, string $collection) => $query->where( - 'collection_name', - $collection, - ), - ), + "{$this->getRelationshipName()}.media" => $modifyMediaQuery, ]); } - return $query->with(['media']); + return $query->with(['media' => $modifyMediaQuery]); } } diff --git a/packages/spatie-laravel-tags-plugin/src/Infolists/Components/SpatieTagsEntry.php b/packages/spatie-laravel-tags-plugin/src/Infolists/Components/SpatieTagsEntry.php index 82b40d6e52..276bd7e1de 100644 --- a/packages/spatie-laravel-tags-plugin/src/Infolists/Components/SpatieTagsEntry.php +++ b/packages/spatie-laravel-tags-plugin/src/Infolists/Components/SpatieTagsEntry.php @@ -5,6 +5,8 @@ namespace Filament\Infolists\Components; use Closure; use Filament\SpatieLaravelTagsPlugin\Types\AllTagTypes; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Arr; class SpatieTagsEntry extends TextEntry { @@ -37,27 +39,34 @@ class SpatieTagsEntry extends TextEntry } if ($this->hasRelationship($record)) { - $record = $record->getRelationValue($this->getRelationshipName()); + $record = $this->getRelationshipResults($record); } - if (! $record) { - return []; + $records = Arr::wrap($record); + + $state = []; + + foreach ($records as $record) { + /** @var Model $record */ + if (! (method_exists($record, 'tags') && method_exists($record, 'tagsWithType'))) { + continue; + } + + $type = $this->getType(); + + if ($this->isAnyTagTypeAllowed()) { + $tags = $record->getRelationValue('tags'); + } else { + $tags = $record->tagsWithType($type); + } + + $state = [ + ...$state, + ...$tags->pluck('name')->all(), + ]; } - if (! (method_exists($record, 'tags') && method_exists($record, 'tagsWithType'))) { - return []; - } - - $type = $this->getType(); - - if ($this->isAnyTagTypeAllowed()) { - /** @phpstan-ignore-next-line */ - $tags = $record->tags; - } else { - $tags = $record->tagsWithType($type); - } - - return $tags->pluck('name')->all(); + return array_unique($state); } public function type(string | Closure | AllTagTypes | null $type): static diff --git a/packages/spatie-laravel-tags-plugin/src/Tables/Columns/SpatieTagsColumn.php b/packages/spatie-laravel-tags-plugin/src/Tables/Columns/SpatieTagsColumn.php index 74b88f915d..23d2885fc9 100644 --- a/packages/spatie-laravel-tags-plugin/src/Tables/Columns/SpatieTagsColumn.php +++ b/packages/spatie-laravel-tags-plugin/src/Tables/Columns/SpatieTagsColumn.php @@ -5,10 +5,12 @@ namespace Filament\Tables\Columns; use Closure; use Filament\SpatieLaravelTagsPlugin\Types\AllTagTypes; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Relation; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; -class SpatieTagsColumn extends TagsColumn +class SpatieTagsColumn extends TextColumn { protected string | Closure | AllTagTypes | null $type; @@ -17,6 +19,8 @@ class SpatieTagsColumn extends TagsColumn parent::setUp(); $this->type(new AllTagTypes()); + + $this->badge(); } /** @@ -33,27 +37,34 @@ class SpatieTagsColumn extends TagsColumn $record = $this->getRecord(); if ($this->hasRelationship($record)) { - $record = $record->getRelationValue($this->getRelationshipName()); + $record = $this->getRelationshipResults($record); } - if (! $record) { - return []; + $records = Arr::wrap($record); + + $state = []; + + foreach ($records as $record) { + /** @var Model $record */ + if (! (method_exists($record, 'tags') && method_exists($record, 'tagsWithType'))) { + continue; + } + + $type = $this->getType(); + + if ($this->isAnyTagTypeAllowed()) { + $tags = $record->getRelationValue('tags'); + } else { + $tags = $record->tagsWithType($type); + } + + $state = [ + ...$state, + ...$tags->pluck('name')->all(), + ]; } - if (! (method_exists($record, 'tags') && method_exists($record, 'tagsWithType'))) { - return []; - } - - $type = $this->getType(); - - if ($this->isAnyTagTypeAllowed()) { - /** @phpstan-ignore-next-line */ - $tags = $record->tags; - } else { - $tags = $record->tagsWithType($type); - } - - return $tags->pluck('name')->all(); + return array_unique($state); } public function type(string | Closure | AllTagTypes | null $type): static From 38d492d46a93ce2fb13e1e5ecef93eba503ff41f Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 19:37:27 +0000 Subject: [PATCH 86/87] clean --- .../docs/07-prebuilt-actions/08-import.md | 25 +++++++++---------- packages/actions/src/Imports/ImportColumn.php | 15 ++++++++--- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/actions/docs/07-prebuilt-actions/08-import.md b/packages/actions/docs/07-prebuilt-actions/08-import.md index e0ca79f8b7..4290a2622b 100644 --- a/packages/actions/docs/07-prebuilt-actions/08-import.md +++ b/packages/actions/docs/07-prebuilt-actions/08-import.md @@ -104,19 +104,6 @@ ImportColumn::make('sku') ->label('SKU') ``` -## Adding helper text below the import column - -Sometimes, you may wish to provide extra information for the import column before validation. - -The `helperText()` method is used to add helper text: - -```php -use Filament\Forms\Components\TextInput; - -ImportColumn::make('skus') - ->helperText('A comma-separated list of SKUs.') -``` - ### Requiring an importer column to be mapped to a CSV column You can call the `requiredMapping()` method to make a column required to be mapped to a column in the CSV. Columns that are required in the database should be required to be mapped: @@ -333,6 +320,18 @@ ImportColumn::make('sku') }) ``` +### Adding helper text below the import column + +Sometimes, you may wish to provide extra information for the user before validation. You can do this by adding `helperText()` to a column, which gets displayed below the mapping select: + +```php +use Filament\Forms\Components\TextInput; + +ImportColumn::make('skus') + ->array(',') + ->helperText('A comma-separated list of SKUs.') +``` + ## Updating existing records when importing When generating an importer class, you will see this `resolveRecord()` method: diff --git a/packages/actions/src/Imports/ImportColumn.php b/packages/actions/src/Imports/ImportColumn.php index 175f4491c0..bb2c795a86 100644 --- a/packages/actions/src/Imports/ImportColumn.php +++ b/packages/actions/src/Imports/ImportColumn.php @@ -3,9 +3,9 @@ namespace Filament\Actions\Imports; use Closure; -use Filament\Forms\Components\Concerns\HasHelperText; use Filament\Forms\Components\Select; use Filament\Support\Components\Component; +use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\Relation; @@ -14,8 +14,6 @@ use Illuminate\Support\Str; class ImportColumn extends Component { - use HasHelperText; - protected string $name; protected string | Closure | null $label = null; @@ -73,6 +71,8 @@ class ImportColumn extends Component protected string $evaluationIdentifier = 'column'; + protected string | Htmlable | Closure | null $helperText = null; + final public function __construct(string $name) { $this->name($name); @@ -92,7 +92,7 @@ class ImportColumn extends Component ->label($this->getLabel()) ->placeholder(__('filament-actions::import.modal.form.columns.placeholder')) ->required($this->isMappingRequired()) - ->helperText($this->getHelperText()); + ->helperText($this->helperText); } public function name(string $name): static @@ -138,6 +138,13 @@ class ImportColumn extends Component return $this; } + public function helperText(string | Htmlable | Closure | null $text): static + { + $this->helperText = $text; + + return $this; + } + public function integer(bool | Closure $condition = true): static { $this->numeric($condition, decimalPlaces: 0); From 72e9b8cebf4c4fc8aebd667b5335d1984a8b1c7f Mon Sep 17 00:00:00 2001 From: Dan Harrin <git@danharrin.com> Date: Fri, 23 Feb 2024 19:41:47 +0000 Subject: [PATCH 87/87] wip --- packages/tables/src/Columns/Summarizers/Average.php | 5 +++-- packages/tables/src/Columns/Summarizers/Count.php | 5 +++-- packages/tables/src/Columns/Summarizers/Sum.php | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/tables/src/Columns/Summarizers/Average.php b/packages/tables/src/Columns/Summarizers/Average.php index c84c60872f..82a3002099 100644 --- a/packages/tables/src/Columns/Summarizers/Average.php +++ b/packages/tables/src/Columns/Summarizers/Average.php @@ -40,9 +40,10 @@ class Average extends Summarizer return $this->selectedState[$this->getSelectAlias()]; } - public function selectAlias(string $alias): static + public function selectAlias(?string $alias): static { - $this->selectAlias = $alias; + $this->selectAlias = $alias; + return $this; } diff --git a/packages/tables/src/Columns/Summarizers/Count.php b/packages/tables/src/Columns/Summarizers/Count.php index d6640f48e9..b210ee6e91 100644 --- a/packages/tables/src/Columns/Summarizers/Count.php +++ b/packages/tables/src/Columns/Summarizers/Count.php @@ -75,9 +75,10 @@ class Count extends Summarizer return $this->selectedState[$this->getSelectAlias()]; } - public function selectAlias(string $alias): static + public function selectAlias(?string $alias): static { - $this->selectAlias = $alias; + $this->selectAlias = $alias; + return $this; } diff --git a/packages/tables/src/Columns/Summarizers/Sum.php b/packages/tables/src/Columns/Summarizers/Sum.php index 16569af230..f5069952f7 100644 --- a/packages/tables/src/Columns/Summarizers/Sum.php +++ b/packages/tables/src/Columns/Summarizers/Sum.php @@ -40,9 +40,10 @@ class Sum extends Summarizer return $this->selectedState[$this->getSelectAlias()]; } - public function selectAlias(string $alias): static + public function selectAlias(?string $alias): static { - $this->selectAlias = $alias; + $this->selectAlias = $alias; + return $this; }