Skip to content

Commit 5ec4a23

Browse files
authored
Merge pull request #566 from rappasoft/develop
1.21.0
2 parents 9d6bb5e + 274ab1d commit 5ec4a23

20 files changed

+216
-38
lines changed

CHANGELOG.md

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@ All notable changes to `laravel-livewire-tables` will be documented in this file
44

55
## [Unreleased]
66

7+
## [1.21.0] - 2021-11-20
8+
9+
### Added
10+
11+
- Added Chinese translation - https://github.com/rappasoft/laravel-livewire-tables/pull/540
12+
- Added 'select all' checkbox for multiselect filters - https://github.com/rappasoft/laravel-livewire-tables/pull/551
13+
- Added attributes to filters - https://github.com/rappasoft/laravel-livewire-tables/pull/558
14+
- Added 4th option for pills fallback value - https://github.com/rappasoft/laravel-livewire-tables/pull/538
15+
16+
### Changed
17+
18+
- Removed excess left padding on Bootstrap 5 form check on multiselect filters.
19+
- Patch bulk actions random wire:key - https://github.com/rappasoft/laravel-livewire-tables/pull/557
20+
721
## [1.20.1] - 2021-11-01
822

923
### Changed
@@ -561,7 +575,8 @@ All notable changes to `laravel-livewire-tables` will be documented in this file
561575
- Initial release
562576

563577
[Unreleased]: https://github.com/rappasoft/laravel-livewire-tables/compare/v1.20.1...development
564-
[1.20.1]: https://github.com/rappasoft/laravel-livewire-tables/compare/v1.19.3...v1.20.1
578+
[1.21.0]: https://github.com/rappasoft/laravel-livewire-tables/compare/v1.20.1...v1.21.0
579+
[1.20.1]: https://github.com/rappasoft/laravel-livewire-tables/compare/v1.20.0...v1.20.1
565580
[1.20.0]: https://github.com/rappasoft/laravel-livewire-tables/compare/v1.19.3...v1.20.0
566581
[1.19.3]: https://github.com/rappasoft/laravel-livewire-tables/compare/v1.19.2...v1.19.3
567582
[1.19.2]: https://github.com/rappasoft/laravel-livewire-tables/compare/v1.19.1...v1.19.2

resources/lang/tw.json

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"All": "全部",
3+
"Applied Filters": "已套用的過濾規則",
4+
"Applied Sorting": "已套用的搜尋規則",
5+
"Bulk Actions": "批次操作",
6+
"Clear": "清除",
7+
"Columns": "欄位",
8+
"Done Reordering": "排序完成",
9+
"Filters": "過濾規則",
10+
"Remove filter option": "移除過濾規則",
11+
"Remove sort option": "移除排序規則",
12+
"Search": "搜尋",
13+
"Select All": "搜尋全部",
14+
"Showing": "顯示",
15+
"Unselect All": "取消選擇",
16+
"You are currently selecting all": "您目前已選擇全部資料",
17+
"You are not connected to the internet.": "目前為離線模式",
18+
"You have selected": "您已選擇",
19+
"of": "筆資料,共",
20+
"Reorder": "重新排序",
21+
"results": "筆資料",
22+
"rows": "筆資料",
23+
"rows, do you want to select all": "筆資料,您是否要全選",
24+
"No items found. Try to broaden your search.": "無資料呈現。請嘗試擴大搜尋範圍。",
25+
"to": ""
26+
}

resources/views/bootstrap-4/components/table/row.blade.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@props(['url' => null, 'target' => '_self', 'reordering' => false, 'customAttributes' => []])
22

3-
@if (!$reordering && $attributes->has('wire:sortable.item'))
3+
@if (!$reordering && (method_exists($attributes, 'has') ? $attributes->has('wire:sortable.item') : array_key_exists('wire:sortable.item', $attributes->getAttributes())))
44
@php
55
$attributes = $attributes->filter(fn ($value, $key) => $key !== 'wire:sortable.item');
66
@endphp

resources/views/bootstrap-4/includes/filter-pills.blade.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
wire:key="filter-pill-{{ $key }}"
1010
class="badge badge-pill badge-info d-inline-flex align-items-center"
1111
>
12-
{{ $filterNames[$key] ?? collect($this->columns())->pluck('text', 'column')->get($key, ucwords(strtr($key, ['_' => ' ', '-' => ' ']))) }}:
12+
{{ $filterNames[$key] ?? collect($this->columns())->pluck('text', 'column')->get($key, isset($customFilters[$key]) && property_exists($customFilters[$key], 'name') ? $customFilters[$key]->name : ucwords(strtr($key, ['_' => ' ', '-' => ' ']))) }}:
1313
@if(isset($customFilters[$key]) && method_exists($customFilters[$key], 'options'))
1414
@if(is_array($value))
1515
@foreach($value as $selectedValue)

resources/views/bootstrap-4/includes/filter-type-multiselect.blade.php

+11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
<div class="form-check">
2+
<input
3+
class="form-check-input"
4+
onclick="event.stopPropagation();"
5+
type="checkbox"
6+
id="filter-{{$key}}-select-all"
7+
wire:input="selectAllFilters('{{ $key }}')"
8+
{{ count($filters[$key]) === count($filter->options()) ? 'checked' : ''}}
9+
>
10+
<label class="form-check-label" for="filter-{{$key}}-select-all">@lang('All')</label>
11+
</div>
112
@foreach($filter->options() as $optionKey => $value)
213
<div class="form-check" wire:key="filter-{{ $key }}-multiselect-{{ $optionKey }}">
314
<input

resources/views/bootstrap-4/includes/table.blade.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
@forelse ($rows as $index => $row)
9494
<x-livewire-tables::bs4.table.row
9595
wire:loading.class.delay="text-muted"
96-
wire:key="table-row-{{ $row->{$primaryKey} }}"
96+
wire:key="table-row-{{ md5(mt_rand()) }}-{{ $row->{$this->parseField($primaryKey)} }}"
9797
wire:sortable.item="{{ $row->{$primaryKey} }}"
9898
:reordering="$reordering"
9999
:url="method_exists($this, 'getTableRowUrl') ? $this->getTableRowUrl($row) : ''"
@@ -115,7 +115,7 @@
115115
<input
116116
wire:model="selected"
117117
wire:loading.attr.delay="disabled"
118-
value="{{ $row->{\Rappasoft\LaravelLivewireTables\Utilities\ColumnUtilities::parseField($primaryKey)} }}"
118+
value="{{ $row->{$this->parseField($primaryKey)} }}"
119119
onclick="event.stopPropagation();return true;"
120120
type="checkbox"
121121
/>

resources/views/bootstrap-5/components/table/row.blade.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@props(['url' => null, 'target' => '_self', 'reordering' => false, 'customAttributes' => []])
22

3-
@if (!$reordering && $attributes->has('wire:sortable.item'))
3+
@if (!$reordering && (method_exists($attributes, 'has') ? $attributes->has('wire:sortable.item') : array_key_exists('wire:sortable.item', $attributes->getAttributes())))
44
@php
55
$attributes = $attributes->filter(fn ($value, $key) => $key !== 'wire:sortable.item');
66
@endphp

resources/views/bootstrap-5/includes/filter-pills.blade.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
wire:key="filter-pill-{{ $key }}"
1010
class="badge rounded-pill bg-info d-inline-flex align-items-center"
1111
>
12-
{{ $filterNames[$key] ?? collect($this->columns())->pluck('text', 'column')->get($key, ucwords(strtr($key, ['_' => ' ', '-' => ' ']))) }}:
12+
{{ $filterNames[$key] ?? collect($this->columns())->pluck('text', 'column')->get($key, isset($customFilters[$key]) && property_exists($customFilters[$key], 'name') ? $customFilters[$key]->name : ucwords(strtr($key, ['_' => ' ', '-' => ' ']))) }}:
1313
@if(isset($customFilters[$key]) && method_exists($customFilters[$key], 'options'))
1414
@if(is_array($value))
1515
@foreach($value as $selectedValue)

resources/views/bootstrap-5/includes/filter-type-multiselect.blade.php

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1+
<div class="form-check p-0">
2+
<input
3+
onclick="event.stopPropagation();"
4+
type="checkbox"
5+
id="filter-{{$key}}-select-all"
6+
wire:input="selectAllFilters('{{ $key }}')"
7+
{{ count($filters[$key]) === count($filter->options()) ? 'checked' : ''}}
8+
>
9+
<label class="form-check-label" for="filter-{{$key}}-select-all">@lang('All')</label>
10+
</div>
111
@foreach($filter->options() as $optionKey => $value)
2-
<div class="form-check" wire:key="filter-{{ $key }}-multiselect-{{ $optionKey }}">
12+
<div class="form-check p-0" wire:key="filter-{{ $key }}-multiselect-{{ $optionKey }}">
313
<input
414
onclick="event.stopPropagation();"
515
type="checkbox"

resources/views/bootstrap-5/includes/table.blade.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class="form-check-input"
9494
@forelse ($rows as $index => $row)
9595
<x-livewire-tables::bs5.table.row
9696
wire:loading.class.delay="text-muted"
97-
wire:key="table-row-{{ $row->{$primaryKey} }}"
97+
wire:key="table-row-{{ md5(mt_rand()) }}-{{ $row->{$this->parseField($primaryKey)} }}"
9898
wire:sortable.item="{{ $row->{$primaryKey} }}"
9999
:reordering="$reordering"
100100
:url="method_exists($this, 'getTableRowUrl') ? $this->getTableRowUrl($row) : ''"
@@ -116,7 +116,7 @@ class="form-check-input"
116116
<input
117117
wire:model="selected"
118118
wire:loading.attr.delay="disabled"
119-
value="{{ $row->{\Rappasoft\LaravelLivewireTables\Utilities\ColumnUtilities::parseField($primaryKey)} }}"
119+
value="{{ $row->{$this->parseField($primaryKey)} }}"
120120
onclick="event.stopPropagation();return true;"
121121
class="form-check-input"
122122
type="checkbox"

resources/views/tailwind/components/table/row.blade.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
@props(['url' => null, 'target' => '_self', 'reordering' => false, 'customAttributes' => []])
22

3-
@if (!$reordering && $attributes->has('wire:sortable.item'))
3+
@if (!$reordering && (method_exists($attributes, 'has') ? $attributes->has('wire:sortable.item') : array_key_exists('wire:sortable.item', $attributes->getAttributes())))
44
@php
55
$attributes = $attributes->filter(fn ($value, $key) => $key !== 'wire:sortable.item');
66
@endphp
77
@endif
88

99
<tr
10-
{{ $attributes->merge($customAttributes)->class(['cursor-pointer' => $url]) }}
10+
{{ $attributes->merge($customAttributes)->merge(['class' => $url ? 'cursor-pointer' : '']) }}
1111

1212
@if ($url)
1313
onclick="window.open('{{ $url }}', '{{ $target }}')"

resources/views/tailwind/includes/filter-pills.blade.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
wire:key="filter-pill-{{ $key }}"
1010
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium leading-4 bg-indigo-100 text-indigo-800 capitalize dark:bg-indigo-200 dark:text-indigo-900"
1111
>
12-
{{ $filterNames[$key] ?? collect($this->columns())->pluck('text', 'column')->get($key, ucwords(strtr($key, ['_' => ' ', '-' => ' ']))) }}:
12+
{{ $filterNames[$key] ?? collect($this->columns())->pluck('text', 'column')->get($key, isset($customFilters[$key]) && property_exists($customFilters[$key], 'name') ? $customFilters[$key]->name : ucwords(strtr($key, ['_' => ' ', '-' => ' ']))) }}:
1313
@if(isset($customFilters[$key]) && method_exists($customFilters[$key], 'options'))
1414
@if(is_array($value))
1515
@foreach($value as $selectedValue)

resources/views/tailwind/includes/filter-type-multiselect.blade.php

+9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
<div class="mt-1 relative rounded-md">
2+
<div>
3+
<input
4+
type="checkbox"
5+
id="filter-{{$key}}-select-all"
6+
wire:input="selectAllFilters('{{ $key }}')"
7+
{{ count($filters[$key]) === count($filter->options()) ? 'checked' : ''}}
8+
>
9+
<label for="filter-{{$key}}-select-all">@lang('All')</label>
10+
</div>
211
@foreach($filter->options() as $optionKey => $value)
312
<div wire:key="filter-{{ $key }}-multiselect-{{ $optionKey }}">
413
<input

resources/views/tailwind/includes/table.blade.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class="rounded border-gray-300 text-indigo-600 shadow-sm transition duration-150
9696
@forelse ($rows as $index => $row)
9797
<x-livewire-tables::table.row
9898
wire:loading.class.delay="opacity-50 dark:bg-gray-900 dark:opacity-60"
99-
wire:key="table-row-{{ $row->{$primaryKey} }}"
99+
wire:key="table-row-{{ md5(mt_rand()) }}-{{ $row->{$this->parseField($primaryKey)} }}"
100100
wire:sortable.item="{{ $row->{$primaryKey} }}"
101101
:reordering="$reordering"
102102
:url="method_exists($this, 'getTableRowUrl') ? $this->getTableRowUrl($row) : ''"
@@ -125,7 +125,7 @@ class="rounded border-gray-300 text-indigo-600 shadow-sm transition duration-150
125125
<input
126126
wire:model="selected"
127127
wire:loading.attr.delay="disabled"
128-
value="{{ $row->{\Rappasoft\LaravelLivewireTables\Utilities\ColumnUtilities::parseField($primaryKey)} }}"
128+
value="{{ $row->{$this->parseField($primaryKey)} }}"
129129
onclick="event.stopPropagation();return true;"
130130
type="checkbox"
131131
class="rounded border-gray-300 text-indigo-600 shadow-sm transition duration-150 ease-in-out focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 dark:bg-gray-900 dark:text-white dark:border-gray-600 dark:hover:bg-gray-600 dark:focus:bg-gray-600"

src/DataTableComponent.php

+2-14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Illuminate\Database\Eloquent\Builder;
66
use Illuminate\Database\Eloquent\Relations\Relation;
77
use Livewire\Component;
8+
use Rappasoft\LaravelLivewireTables\Traits\ComponentHelpers;
89
use Rappasoft\LaravelLivewireTables\Traits\WithBulkActions;
910
use Rappasoft\LaravelLivewireTables\Traits\WithColumnSelect;
1011
use Rappasoft\LaravelLivewireTables\Traits\WithCustomPagination;
@@ -23,6 +24,7 @@
2324
*/
2425
abstract class DataTableComponent extends Component
2526
{
27+
use ComponentHelpers;
2628
use WithBulkActions;
2729
use WithColumnSelect;
2830
use WithCustomPagination;
@@ -226,18 +228,4 @@ public function render()
226228
'bulkActions' => $this->bulkActions,
227229
]);
228230
}
229-
230-
/**
231-
* Get a column object by its field
232-
*
233-
* @param string $column
234-
*
235-
* @return mixed
236-
*/
237-
protected function getColumn(string $column)
238-
{
239-
return collect($this->columns())
240-
->where('column', $column)
241-
->first();
242-
}
243231
}

src/Traits/ComponentHelpers.php

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Rappasoft\LaravelLivewireTables\Traits;
4+
5+
use Rappasoft\LaravelLivewireTables\Utilities\ColumnUtilities;
6+
7+
/**
8+
* Trait ComponentHelpers.
9+
*/
10+
trait ComponentHelpers
11+
{
12+
/**
13+
* Get a column object by its field
14+
*
15+
* @param string $column
16+
*
17+
* @return mixed
18+
*/
19+
protected function getColumn(string $column)
20+
{
21+
return collect($this->columns())
22+
->where('column', $column)
23+
->first();
24+
}
25+
26+
/**
27+
* @param string $field
28+
*
29+
* @return string
30+
*/
31+
protected function parseField(string $field): string
32+
{
33+
return ColumnUtilities::parseField($field);
34+
}
35+
}

src/Traits/WithFilters.php

+17
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,23 @@ public function cleanFilters(): void
196196
})->toArray();
197197
}
198198

199+
public function selectAllFilters($filterKey): void
200+
{
201+
$filter = $this->filters()[$filterKey];
202+
203+
if (! $filter->isMultiSelect()) {
204+
return;
205+
}
206+
207+
if (count($this->filters[$filterKey]) === count($filter->options())) {
208+
$this->removeFilter($filterKey);
209+
210+
return;
211+
}
212+
213+
$this->filters[$filterKey] = array_keys($filter->options());
214+
}
215+
199216
/**
200217
* Define the string location to a view to be included as the filters view
201218
*

src/Views/Filter.php

+13-7
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,29 @@ class Filter
2929
public array $options = [];
3030

3131
/**
32-
* Filter constructor.
33-
*
34-
* @param string $name
32+
* @var array
33+
*/
34+
public array $attributes = [];
35+
36+
/**
37+
* @param string $name
38+
* @param array|null $attributes
3539
*/
36-
public function __construct(string $name)
40+
public function __construct(string $name, ?array $attributes = [])
3741
{
3842
$this->name = $name;
43+
$this->attributes = $attributes;
3944
}
4045

4146
/**
42-
* @param string $name
47+
* @param string $name
48+
* @param array|null $attributes
4349
*
4450
* @return Filter
4551
*/
46-
public static function make(string $name): Filter
52+
public static function make(string $name, ?array $attributes = []): Filter
4753
{
48-
return new static($name);
54+
return new static($name, $attributes);
4955
}
5056

5157
/**

0 commit comments

Comments
 (0)