diff --git a/CHANGELOG.md b/CHANGELOG.md index 83393a033..b133e9023 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to `laravel-livewire-tables` will be documented in this file ## [Unreleased] +## [2.10.0] - 2023-01-16 + +### Added + +- Added support for MorphOne relationships - https://github.com/rappasoft/laravel-livewire-tables/pull/844 +- Added MultiSelectDropdownFilter - https://github.com/rappasoft/laravel-livewire-tables/pull/1011 +- FilterSlideDown - Ability to set Default to Open or Closed - https://github.com/rappasoft/laravel-livewire-tables/pull/1017 + +### Changed + +- Updated EN translations - https://github.com/rappasoft/laravel-livewire-tables/pull/999 +- Updated ES translations - https://github.com/rappasoft/laravel-livewire-tables/pull/1000 +- Bulk Actions Simple Pagination fix & typo in toolbar.blade.php - https://github.com/rappasoft/laravel-livewire-tables/pull/1015 + ## [2.9.0] - 2022-12-21 ### Added @@ -705,7 +719,9 @@ Ground Up Rebuild - Initial release -[Unreleased]: https://github.com/rappasoft/laravel-livewire-tables/compare/v2.8.0...development +[Unreleased]: https://github.com/rappasoft/laravel-livewire-tables/compare/v2.10.0...development +[2.10.0]: https://github.com/rappasoft/laravel-livewire-tables/compare/v2.9.0...v2.10.0 +[2.9.0]: https://github.com/rappasoft/laravel-livewire-tables/compare/v2.8.0...v2.9.0 [2.8.0]: https://github.com/rappasoft/laravel-livewire-tables/compare/v2.7.0...v2.8.0 [2.7.0]: https://github.com/rappasoft/laravel-livewire-tables/compare/v2.6.0...v2.7.0 [2.6.0]: https://github.com/rappasoft/laravel-livewire-tables/compare/v2.5.0...v2.6.0 diff --git a/docs/columns/relationships.md b/docs/columns/relationships.md index caa86f870..cb11ac3e7 100644 --- a/docs/columns/relationships.md +++ b/docs/columns/relationships.md @@ -3,7 +3,7 @@ title: Relationships weight: 2 --- -Out of the box the columns support `hasOne` and `belongsTo` relationships for display, sorting, and searching. The component will automatically join the necessary tables. +Out of the box the columns support `hasOne`, `belongsTo`, and `MorphOne` relationships for display, sorting, and searching. The component will automatically join the necessary tables. To call these relationships, just use the relationship dot-notation string as the field name: diff --git a/docs/filters/applying-filters.md b/docs/filters/applying-filters.md index 000927067..3a756204c 100644 --- a/docs/filters/applying-filters.md +++ b/docs/filters/applying-filters.md @@ -47,7 +47,7 @@ You may wish to apply default filters i.e. current month on accessing the view i ```php public function mount() { - $this->setFilter('created_after', date('Y-m-d', strtotime('now -1 month')); + $this->setFilter('created_after', date('Y-m-d', strtotime('now -1 month'))); } ``` diff --git a/docs/filters/available-methods.md b/docs/filters/available-methods.md index decb758b8..f5f7344cc 100644 --- a/docs/filters/available-methods.md +++ b/docs/filters/available-methods.md @@ -158,6 +158,31 @@ public function configure(): void } ``` +### setFilterSlideDownDefaultStatusEnabled + +Set the filter slide down to visible by default + +```php +public function configure(): void +{ + // Shorthand for $this->setFilterSlideDownDefaultStatus(true) + $this->setFilterSlideDownDefaultStatusEnabled(); +} +``` + +### setFilterSlideDownDefaultStatusDisabled + +Set the filter slide down to collapsed by default + +```php +public function configure(): void +{ + // Shorthand for $this->setFilterSlideDownDefaultStatus(false) + $this->setFilterSlideDownDefaultStatusDisabled(); +} +``` + + ---- ## Filter Methods diff --git a/docs/filters/creating-filters.md b/docs/filters/creating-filters.md index 0310ce9fa..1a0b2fd81 100644 --- a/docs/filters/creating-filters.md +++ b/docs/filters/creating-filters.md @@ -61,10 +61,15 @@ public function filters(): array 25 => 'Type Y', 26 => 'Type Z', ], - ]), + ]) + ->setFirstOption('All Tags'), ]; } ``` +To set a defualt "All" option at the start of the dropdown, you can do so by utilising the +``` +->SetFirstOption('NAME') +``` ## Multi-select Filters @@ -89,6 +94,30 @@ public function filters(): array } ``` +## Multi-select dropdown Filters + +Multi-select dropdown filters are a simple dropdown list. The user can select multiple options from the list. There is also an 'All' option that will select all values + +```php +use Rappasoft\LaravelLivewireTables\Views\Filters\SelectFilter; + +public function filters(): array +{ + return [ + SelectFilter::make('Tags') + ->options( + Tag::query() + ->orderBy('name') + ->get() + ->keyBy('id') + ->map(fn($tag) => $tag->name) + ->toArray() + ) + ->setFirstOption('All Tags'), + ]; +} +``` + ## Date Filters Date filters are HTML date elements. diff --git a/resources/lang/en.json b/resources/lang/en.json index 5026af455..19cc757c7 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -1,5 +1,6 @@ { "All": "All", + "All Columns": "All Columns", "Applied Filters": "Applied Filters", "Applied Sorting": "Applied Sorting", "Bulk Actions": "Bulk Actions", diff --git a/resources/lang/es.json b/resources/lang/es.json index 43e1fc5f7..6e4cfd8a4 100644 --- a/resources/lang/es.json +++ b/resources/lang/es.json @@ -1,5 +1,6 @@ { "All": "Todo", + "All Columns": "Todas las columnas", "Applied Filters": "Filtros Aplicados", "Applied Sorting": "Ordenamineto Aplicado", "Bulk Actions": "Acciones Masivas", diff --git a/resources/views/components/table/tr/bulk-actions.blade.php b/resources/views/components/table/tr/bulk-actions.blade.php index 744fd3cca..cea9f187c 100644 --- a/resources/views/components/table/tr/bulk-actions.blade.php +++ b/resources/views/components/table/tr/bulk-actions.blade.php @@ -8,6 +8,7 @@ $colspan = $component->getColspanCount(); $selected = $component->getSelectedCount(); $selectAll = $component->selectAllIsEnabled(); + $simplePagination = ($component->paginationMethod == "simple") ? true : false; @endphp @if ($theme === 'tailwind') @@ -20,7 +21,7 @@ class="bg-indigo-50 dark:bg-gray-900 dark:text-white"
@lang('You are currently selecting all') - {{ number_format($rows->total()) }} + @if(!$simplePagination) {{ number_format($rows->total()) }} @endif @lang('rows'). @@ -39,7 +40,7 @@ class="ml-1 text-blue-600 underline text-gray-700 text-sm leading-5 font-medium @lang('You have selected') {{ $selected }} @lang('rows, do you want to select all') - {{ number_format($rows->total()) }}? + @if(!$simplePagination) {{ number_format($rows->total()) }} @endif
diff --git a/resources/views/components/wrapper.blade.php b/resources/views/components/wrapper.blade.php index d9886135a..fdfe063fd 100644 --- a/resources/views/components/wrapper.blade.php +++ b/resources/views/components/wrapper.blade.php @@ -13,7 +13,7 @@ @endif @if ($component->isFilterLayoutSlideDown()) - x-data="{ filtersOpen: false }" + wire:ignore.self x-data="{ filtersOpen: $wire.filterSlideDownDefaultVisible }" @endif > @include('livewire-tables::includes.debug') diff --git a/src/Traits/Configuration/FilterConfiguration.php b/src/Traits/Configuration/FilterConfiguration.php index 270f3499e..5819e316f 100644 --- a/src/Traits/Configuration/FilterConfiguration.php +++ b/src/Traits/Configuration/FilterConfiguration.php @@ -137,4 +137,36 @@ public function setFilterLayoutSlideDown(): self return $this; } + + /** + * @param bool $status + * + * @return $this + */ + public function setFilterSlideDownDefaultStatus(bool $status): self + { + $this->filterSlideDownDefaultVisible = $status; + + return $this; + } + + /** + * @return $this + */ + public function setFilterSlideDownDefaultStatusDisabled(): self + { + $this->setFilterSlideDownDefaultStatus(false); + + return $this; + } + + /** + * @return $this + */ + public function setFilterSlideDownDefaultStatusEnabled(): self + { + $this->setFilterSlideDownDefaultStatus(true); + + return $this; + } } diff --git a/src/Traits/Helpers/FilterHelpers.php b/src/Traits/Helpers/FilterHelpers.php index 2dacd61dc..899a9c678 100644 --- a/src/Traits/Helpers/FilterHelpers.php +++ b/src/Traits/Helpers/FilterHelpers.php @@ -4,6 +4,7 @@ use Illuminate\Support\Collection; use Rappasoft\LaravelLivewireTables\Views\Filter; +use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectDropdownFilter; use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter; trait FilterHelpers @@ -38,6 +39,21 @@ public function filtersVisibilityIsDisabled(): bool return $this->getFiltersVisibilityStatus() === false; } + public function getFilterSlideDownDefaultStatus(): bool + { + return $this->filterSlideDownDefaultVisible; + } + + public function filtersSlideDownIsDefaultVisible(): bool + { + return $this->getFilterSlideDownDefaultStatus() === true; + } + + public function filtersSlideDownIsDefaultHidden(): bool + { + return $this->getFilterSlideDownDefaultStatus() === false; + } + public function getFilterPillsStatus(): bool { return $this->filterPillsStatus; @@ -91,7 +107,7 @@ public function selectAllFilterOptions(string $filterKey): void { $filter = $this->getFilterByKey($filterKey); - if (! $filter instanceof MultiSelectFilter) { + if (! $filter instanceof MultiSelectFilter && ! $filter instanceof MultiSelectDropdownFilter) { return; } @@ -175,7 +191,7 @@ public function resetFilter($filter): void if (! $filter instanceof Filter) { $filter = $this->getFilterByKey($filter); } - + $this->setFilter($filter->getKey(), $filter->getDefaultValue()); } diff --git a/src/Traits/WithData.php b/src/Traits/WithData.php index 2b5bcb4bd..d68625fdb 100644 --- a/src/Traits/WithData.php +++ b/src/Traits/WithData.php @@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasOne; +use Illuminate\Database\Eloquent\Relations\MorphOne; use Rappasoft\LaravelLivewireTables\Views\Column; trait WithData @@ -77,6 +78,7 @@ protected function joinRelation(Column $column): Builder $model = $lastQuery->getRelation($relationPart); switch (true) { + case $model instanceof MorphOne: case $model instanceof HasOne: $table = $model->getRelated()->getTable(); $foreign = $model->getQualifiedForeignKeyName(); @@ -139,7 +141,7 @@ protected function getTableForColumn(Column $column): ?string foreach ($column->getRelations() as $relationPart) { $model = $lastQuery->getRelation($relationPart); - if ($model instanceof HasOne || $model instanceof BelongsTo) { + if ($model instanceof HasOne || $model instanceof BelongsTo || $model instanceof MorphOne) { $table = $model->getRelated()->getTable(); } diff --git a/src/Traits/WithFilters.php b/src/Traits/WithFilters.php index 61d368995..6c56dd3ad 100644 --- a/src/Traits/WithFilters.php +++ b/src/Traits/WithFilters.php @@ -14,6 +14,7 @@ trait WithFilters public bool $filtersStatus = true; public bool $filtersVisibilityStatus = true; public bool $filterPillsStatus = true; + public bool $filterSlideDownDefaultVisible = false; public string $filterLayout = 'popover'; public function filters(): array diff --git a/src/Views/Filters/MultiSelectDropdownFilter.php b/src/Views/Filters/MultiSelectDropdownFilter.php new file mode 100644 index 000000000..707057814 --- /dev/null +++ b/src/Views/Filters/MultiSelectDropdownFilter.php @@ -0,0 +1,99 @@ +options = $options; + + return $this; + } + + public function getOptions(): array + { + return $this->options; + } + + public function setFirstOption(string $firstOption): MultiSelectDropdownFilter + { + $this->firstOption = $firstOption; + + return $this; + } + + public function getFirstOption(): string + { + return $this->firstOption; + } + + public function getKeys(): array + { + return collect($this->getOptions()) + ->keys() + ->map(fn ($value) => (string)$value) + ->filter(fn ($value) => strlen($value)) + ->values() + ->toArray(); + } + + public function validate($value) + { + if (is_array($value)) { + foreach ($value as $index => $val) { + // Remove the bad value + if (! in_array($val, $this->getKeys())) { + unset($value[$index]); + } + } + } + + return $value; + } + + public function getDefaultValue() + { + return []; + } + + public function getFilterPillValue($value): ?string + { + $values = []; + + foreach ($value as $item) { + $found = $this->getCustomFilterPillValue($item) ?? $this->getOptions()[$item] ?? null; + + if ($found) { + $values[] = $found; + } + } + + return implode(', ', $values); + } + + public function isEmpty($value): bool + { + if (! is_array($value)) { + return true; + } elseif (in_array("all", $value)) { + return true; + } + + return false; + } + + public function render(DataTableComponent $component) + { + return view('livewire-tables::components.tools.filters.multi-select-dropdown', [ + 'component' => $component, + 'filter' => $this, + ]); + } +} diff --git a/tests/Http/Livewire/PetsTable.php b/tests/Http/Livewire/PetsTable.php index c03b277f7..0abb8038d 100644 --- a/tests/Http/Livewire/PetsTable.php +++ b/tests/Http/Livewire/PetsTable.php @@ -6,7 +6,9 @@ use Rappasoft\LaravelLivewireTables\DataTableComponent; use Rappasoft\LaravelLivewireTables\Tests\Models\Breed; use Rappasoft\LaravelLivewireTables\Tests\Models\Pet; +use Rappasoft\LaravelLivewireTables\Tests\Models\Species; use Rappasoft\LaravelLivewireTables\Views\Column; +use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectDropdownFilter; use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter; class PetsTable extends DataTableComponent @@ -56,6 +58,18 @@ public function filters(): array ->filter(function (Builder $builder, array $values) { return $builder->whereIn('breed_id', $values); }), + MultiSelectDropdownFilter::make('Species') + ->options( + Species::query() + ->orderBy('name') + ->get() + ->keyBy('id') + ->map(fn ($species) => $species->name) + ->toArray() + ) + ->filter(function (Builder $builder, array $values) { + return $builder->whereIn('species_id', $values); + }), ]; } } diff --git a/tests/Traits/Configuration/FilterConfigurationTest.php b/tests/Traits/Configuration/FilterConfigurationTest.php index 76eb1203d..47431c5e0 100644 --- a/tests/Traits/Configuration/FilterConfigurationTest.php +++ b/tests/Traits/Configuration/FilterConfigurationTest.php @@ -100,4 +100,26 @@ public function filters_layout_can_be_set(): void $this->basicTable->setFilterLayout('popover'); } + + /** @test */ + public function filters_layout_popover_default_can_be_set(): void + { + $this->assertFalse($this->basicTable->filterSlideDownDefaultVisible); + + $this->basicTable->setFilterSlideDownDefaultStatusEnabled(); + + $this->assertTrue($this->basicTable->filterSlideDownDefaultVisible); + + $this->basicTable->setFilterSlideDownDefaultStatusDisabled(); + + $this->assertFalse($this->basicTable->filterSlideDownDefaultVisible); + + $this->basicTable->setFilterSlideDownDefaultStatus(true); + + $this->assertTrue($this->basicTable->filterSlideDownDefaultVisible); + + $this->basicTable->setFilterSlideDownDefaultStatus(false); + + $this->assertFalse($this->basicTable->filterSlideDownDefaultVisible); + } } diff --git a/tests/Traits/Helpers/FilterHelpersTest.php b/tests/Traits/Helpers/FilterHelpersTest.php index f43ea2fb7..e31db44c3 100644 --- a/tests/Traits/Helpers/FilterHelpersTest.php +++ b/tests/Traits/Helpers/FilterHelpersTest.php @@ -64,7 +64,7 @@ public function can_get_component_filters(): void /** @test */ public function can_get_component_filter_count(): void { - $this->assertEquals(1, $this->basicTable->getFiltersCount()); + $this->assertEquals(2, $this->basicTable->getFiltersCount()); } /** @test */ @@ -111,7 +111,7 @@ public function can_set_filter_defaults(): void $this->basicTable->setFilterDefaults(); - $this->assertSame(['breed' => []], $this->basicTable->getAppliedFilters()); + $this->assertSame(['breed' => [], 'species' => []], $this->basicTable->getAppliedFilters()); } /** @test */ @@ -167,4 +167,24 @@ public function can_check_if_filter_layout_is_slidedown(): void $this->assertTrue($this->basicTable->isFilterLayoutSlideDown()); } + + /** @test */ + public function can_check_if_filter_layout_slidedown_is_visible(): void + { + $this->assertFalse($this->basicTable->getFilterSlideDownDefaultStatus()); + + $this->basicTable->setFilterSlideDownDefaultStatusEnabled(); + + $this->assertTrue($this->basicTable->getFilterSlideDownDefaultStatus()); + } + + /** @test */ + public function can_check_if_filter_layout_slidedown_is_hidden(): void + { + $this->assertFalse($this->basicTable->getFilterSlideDownDefaultStatus()); + + $this->basicTable->setFilterSlideDownDefaultStatusDisabled(); + + $this->assertFalse($this->basicTable->getFilterSlideDownDefaultStatus()); + } } diff --git a/tests/Traits/Visuals/ReorderingVisualsTest.php b/tests/Traits/Visuals/ReorderingVisualsTest.php index 56075173f..e26be74c1 100644 --- a/tests/Traits/Visuals/ReorderingVisualsTest.php +++ b/tests/Traits/Visuals/ReorderingVisualsTest.php @@ -89,7 +89,7 @@ public function sorting_is_disabled_on_reorder(): void ->call('setReorderEnabled') ->assertSet('sortingStatus', true) ->call('sortBy', 'id') - ->assertSet('table', ['sorts' => ['id' => 'asc'], 'filters' => ['breed' => []], 'columns' => []]) + ->assertSet('table', ['sorts' => ['id' => 'asc'], 'filters' => ['breed' => [], 'species' => []], 'columns' => []]) ->assertSeeHtml('wire:click="sortBy(\'id\')"') ->call('enableReordering') ->assertSet('sortingStatus', false) @@ -97,7 +97,7 @@ public function sorting_is_disabled_on_reorder(): void ->assertDontSeeHtml('wire:click="sortBy(\'id\')"') ->call('disableReordering') ->assertSet('sortingStatus', true) - ->assertSet('table', ['sorts' => ['id' => 'asc'], 'filters' => ['breed' => []], 'columns' => []]) + ->assertSet('table', ['sorts' => ['id' => 'asc'], 'filters' => ['breed' => [], 'species' => []], 'columns' => []]) ->assertSeeHtml('wire:click="sortBy(\'id\')"'); } @@ -264,7 +264,7 @@ public function filters_are_disabled_on_reorder(): void ->call('setReorderEnabled') ->assertSet('filtersStatus', true) ->set('table.filters.breed', [1]) - ->assertSet('table', ['filters' => ['breed' => [1]], 'sorts' => [], 'columns' => []]) + ->assertSet('table', ['filters' => ['breed' => [1], 'species' => []], 'sorts' => [], 'columns' => []]) ->assertSee('Filters') ->call('enableReordering') ->assertSet('filtersStatus', false) @@ -272,7 +272,7 @@ public function filters_are_disabled_on_reorder(): void ->assertDontSeeHtml('Filters') ->call('disableReordering') ->assertSet('filtersStatus', true) - ->assertSet('table', ['filters' => ['breed' => [1]], 'sorts' => [], 'columns' => []]) + ->assertSet('table', ['filters' => ['breed' => [1], 'species' => []], 'sorts' => [], 'columns' => []]) ->assertSeeHtml('Filters'); } @@ -282,7 +282,7 @@ public function filter_pills_hide_on_reorder(): void Livewire::test(PetsTable::class) ->call('setReorderEnabled') ->set('table.filters.breed', [1]) - ->assertSet('table', ['filters' => ['breed' => [1]], 'sorts' => [], 'columns' => []]) + ->assertSet('table', ['filters' => ['breed' => [1], 'species' => []], 'sorts' => [], 'columns' => []]) ->assertSee('Applied Filters') ->call('enableReordering') ->assertDontSee('Applied Filters'); diff --git a/tests/Views/Traits/Helpers/FilterHelpersTest.php b/tests/Views/Traits/Helpers/FilterHelpersTest.php index c17d529fd..9ecf343a0 100644 --- a/tests/Views/Traits/Helpers/FilterHelpersTest.php +++ b/tests/Views/Traits/Helpers/FilterHelpersTest.php @@ -4,6 +4,7 @@ use Illuminate\Database\Eloquent\Builder; use Rappasoft\LaravelLivewireTables\Tests\TestCase; +use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectDropdownFilter; use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter; use Rappasoft\LaravelLivewireTables\Views\Filters\SelectFilter; @@ -54,7 +55,7 @@ public function can_get_filter_keys(): void $this->assertSame([], $filter->getKeys()); $filter->options(['foo' => 'bar']); - + $this->assertSame(['foo'], $filter->getKeys()); } @@ -84,6 +85,10 @@ public function can_get_filter_default_value(): void $filter = MultiSelectFilter::make('Active'); $this->assertSame([], $filter->getDefaultValue()); + + $filter = MultiSelectDropdownFilter::make('Active'); + + $this->assertSame([], $filter->getDefaultValue()); } /** @test */