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 */