From c8b019892fe5fe287601484b1d8661aa649d48ca Mon Sep 17 00:00:00 2001 From: Oussama Date: Thu, 24 Sep 2020 16:01:04 +0100 Subject: [PATCH 001/217] Design enhancement (#37) * Eloquent Refactoring * enhancement * Update src/Http/Livewire/LivewireDatatable.php Co-authored-by: Wouter van Marrum * Using Conditional Clauses instead of Conditional Statement Co-authored-by: Wouter van Marrum --- .../livewire/datatables/datatable.blade.php | 81 ++++++++++--------- src/Http/Livewire/LivewireDatatable.php | 10 ++- 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index a473ab20..2d24837a 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -56,7 +56,7 @@ @endif
-
+
@unless($this->hideHeader)
@@ -106,52 +106,59 @@ @endforeach
@endif - @foreach($this->results as $result) -
- @foreach($this->columns as $column) - @if($column['hidden']) - @if($hideable === 'inline') -
+ @forelse($this->results as $result) +
+ @foreach($this->columns as $column) + @if($column['hidden']) + @if($hideable === 'inline') +
+ @endif + @elseif($column['type'] === 'checkbox') + @include('datatables::checkbox', ['value' => $result->checkbox_attribute]) + @else +
+ {!! $result->{$column['name']} !!} +
@endif - @elseif($column['type'] === 'checkbox') - @include('datatables::checkbox', ['value' => $result->checkbox_attribute]) - @else -
- {!! $result->{$column['name']} !!} -
- @endif - @endforeach -
- @endforeach + @endforeach +
+ @empty +

+ There's Nothing to show at the moment +

+ @endforelse
@unless($this->hidePagination)
-
- -
- -
-
- {{ $this->results->links('datatables::tailwind-simple-pagination') }} + {{-- check if there is any data --}} + @if($this->results[1]) +
+
- -
- Results {{ $this->results->firstItem() }} - {{ $this->results->lastItem() }} of - {{ $this->results->total() }} -
+
+ Results {{ $this->results->firstItem() }} - {{ $this->results->lastItem() }} of + {{ $this->results->total() }} +
+ @endif
@endif diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 1b0f4037..ee32e724 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -700,7 +700,7 @@ public function buildDatabaseQuery() public function addGlobalSearch() { - if (! $this->search) { + if (!$this->search) { return $this; } @@ -710,7 +710,13 @@ public function addGlobalSearch() $this->searchableColumns()->each(function ($column, $i) use ($query, $search) { $query->orWhere(function ($query) use ($i, $search) { foreach ($this->getColumnField($i) as $column) { - $query->orWhereRaw('LOWER('.$column.') like ?', "%$search%"); + $query->when(is_array($column), function ($query) use ($search, $column) { + foreach ($column as $col) { + $query->orWhereRaw('LOWER(' . $col . ') like ?', "%$search%"); + } + }, function ($query) use ($search, $column) { + $query->orWhereRaw('LOWER(' . $column . ') like ?', "%$search%"); + }); } }); }); From 8bf0c99e2a1256fcbe1df7927dcef251fc08b57d Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Thu, 24 Sep 2020 16:01:53 +0100 Subject: [PATCH 002/217] Apply fixes from StyleCI (#46) Co-authored-by: Mark Salmon --- src/Http/Livewire/LivewireDatatable.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index ee32e724..fa748262 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -700,7 +700,7 @@ public function buildDatabaseQuery() public function addGlobalSearch() { - if (!$this->search) { + if (! $this->search) { return $this; } @@ -712,10 +712,10 @@ public function addGlobalSearch() foreach ($this->getColumnField($i) as $column) { $query->when(is_array($column), function ($query) use ($search, $column) { foreach ($column as $col) { - $query->orWhereRaw('LOWER(' . $col . ') like ?', "%$search%"); + $query->orWhereRaw('LOWER('.$col.') like ?', "%$search%"); } }, function ($query) use ($search, $column) { - $query->orWhereRaw('LOWER(' . $column . ') like ?', "%$search%"); + $query->orWhereRaw('LOWER('.$column.') like ?', "%$search%"); }); } }); From 3649215527e55800df8b000f75cc187643c8eb63 Mon Sep 17 00:00:00 2001 From: Oussama Date: Thu, 15 Oct 2020 13:54:28 +0100 Subject: [PATCH 003/217] Eloquent Refactoring (#35) * Eloquent Refactoring * Eloquent Refactoring * Eloquent Refactoring * Remove Spaces From b22006b404d710e8bd2ead4cf7a0344a2fabc42c Mon Sep 17 00:00:00 2001 From: Ed Grosvenor Date: Thu, 15 Oct 2020 08:56:02 -0400 Subject: [PATCH 004/217] Add optional parameter to editable() to allow for conditional setting (#53) --- src/Column.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Column.php b/src/Column.php index 3c49365c..47000b1b 100644 --- a/src/Column.php +++ b/src/Column.php @@ -172,9 +172,9 @@ public function additionalSelects($selects) return $this; } - public function editable() + public function editable($editable = true) { - return $this->setType('editable'); + return $editable ? $this->setType('editable') : $this; } public function isEditable() From 9645df8f6c9140624a0ec36d0621b033bd76e12c Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Thu, 15 Oct 2020 22:32:17 +0100 Subject: [PATCH 005/217] wip --- resources/views/livewire/datatables/datatable.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index 2d24837a..e4e2a1c8 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -55,8 +55,8 @@
@endif -
-
+
+
@unless($this->hideHeader)
From ca864fdf077642559c82902b31d3ee3dce2ffc9a Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Tue, 3 Nov 2020 15:22:58 +0000 Subject: [PATCH 006/217] laravel 8.12 --- src/Http/Livewire/LivewireDatatable.php | 6 +++--- src/LivewireDatatablesServiceProvider.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index fa748262..a60fca31 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -256,7 +256,7 @@ protected function joinRelation($relation, $relationColumn, $aggregate = null, $ break; case $model instanceof HasMany: - $this->query->withAggregate($relation, $aggregate ?? 'count', $relationColumn, $alias); + $this->query->customWithAggregate($relation, $aggregate ?? 'count', $relationColumn, $alias); $table = null; break; @@ -267,7 +267,7 @@ protected function joinRelation($relation, $relationColumn, $aggregate = null, $ break; case $model instanceof BelongsToMany: - $this->query->withAggregate($relation, $aggregate ?? 'count', $relationColumn, $alias); + $this->query->customWithAggregate($relation, $aggregate ?? 'count', $relationColumn, $alias); $table = null; break; @@ -286,7 +286,7 @@ protected function joinRelation($relation, $relationColumn, $aggregate = null, $ break; default: - $this->query->withAggregate($relation, $aggregate ?? 'count', $relationColumn, $alias); + $this->query->customWithAggregate($relation, $aggregate ?? 'count', $relationColumn, $alias); } if ($table) { $this->performJoin($table, $foreign, $other); diff --git a/src/LivewireDatatablesServiceProvider.php b/src/LivewireDatatablesServiceProvider.php index 0530ec77..5ad9809d 100644 --- a/src/LivewireDatatablesServiceProvider.php +++ b/src/LivewireDatatablesServiceProvider.php @@ -73,7 +73,7 @@ public function loadBuilderMacros() public function loadEloquentBuilderMacros() { - EloquentBuilder::macro('withAggregate', function ($relations, $aggregate, $column, $alias = null) { + EloquentBuilder::macro('customWithAggregate', function ($relations, $aggregate, $column, $alias = null) { if (empty($relations)) { return $this; } From b292acfb82a68b900f2cbf138d79a0f571b46db6 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Tue, 3 Nov 2020 15:38:58 +0000 Subject: [PATCH 007/217] fix mobile paginator links --- .../datatables/tailwind-simple-pagination.blade.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/views/livewire/datatables/tailwind-simple-pagination.blade.php b/resources/views/livewire/datatables/tailwind-simple-pagination.blade.php index 5180b149..d55d4100 100644 --- a/resources/views/livewire/datatables/tailwind-simple-pagination.blade.php +++ b/resources/views/livewire/datatables/tailwind-simple-pagination.blade.php @@ -6,19 +6,19 @@ Previous
@else - @endif @if ($paginator->hasMorePages()) - @else
Next From 32cd72face77ef9e899385b1898ee5046306fd89 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Tue, 3 Nov 2020 15:59:13 +0000 Subject: [PATCH 008/217] fix combined truncate and search --- src/Http/Livewire/LivewireDatatable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index a60fca31..62d60299 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -955,7 +955,7 @@ public function highlight($value, $string) if ($value instanceof View) { return $value - ->with(['value' => str_ireplace($string, view('datatables::highlight', ['slot' => $output]), $value->gatherData()['value'])]); + ->with(['value' => str_ireplace($string, view('datatables::highlight', ['slot' => $output]), $value->gatherData()['value'] ?? $value->gatherData()['slot'])]); } return str_ireplace($string, view('datatables::highlight', ['slot' => $output]), $value); From 13cfa95195a3d622e2f100e9bee54667a1c15db8 Mon Sep 17 00:00:00 2001 From: Kyle Pilquist Date: Mon, 16 Nov 2020 04:59:16 -0700 Subject: [PATCH 009/217] Update LivewireDatatable.php (#79) * Update LivewireDatatable.php In getSortString() the default is to use a back tick " ` " for the order by field. This causes an error in postgresql which likes it to be ' " '. My fix is to test the enviroment variable, and if it is set to "pgsql" it will use ' " ' otherwise it will give " ` ". * Update LivewireDatatable.php Changed quotation style. --- src/Http/Livewire/LivewireDatatable.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index a60fca31..9105b902 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -355,6 +355,7 @@ public function defaultSort() public function getSortString() { $column = $this->freshColumns[$this->sort]; + $dbTable = env('DB_CONNECTION'); switch (true) { case $column['sort']: @@ -373,8 +374,10 @@ public function getSortString() return Str::before($column['select'], ' AS '); break; - default: - return new Expression('`'.$column['name'].'`'); + default: + return $dbTable == 'pgsql' + ? new Expression('"'.$column['name'].'"') + : new Expression('`'.$column['name'].'`'); break; } } From 02e71ff4a20ed1c7313442b2223d5f6dc396c0bc Mon Sep 17 00:00:00 2001 From: JJ Date: Mon, 16 Nov 2020 07:00:18 -0500 Subject: [PATCH 010/217] Make possible to disable highlighting (#75) * fix mobile paginator links * fix combined truncate and search * Add configuration option that suppresses highlighting. * add highlighting method more usable to user space inside callback, namely 'highlightStringWithCurrentSearchTerm' * Make possible to disable highlighting Co-authored-by: Mark Salmon Co-authored-by: jjrohrer --- config/livewire-datatables.php | 1 + .../tailwind-simple-pagination.blade.php | 8 ++--- src/Http/Livewire/LivewireDatatable.php | 31 +++++++++++++++++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/config/livewire-datatables.php b/config/livewire-datatables.php index a60e8a9c..0702c8e4 100644 --- a/config/livewire-datatables.php +++ b/config/livewire-datatables.php @@ -3,4 +3,5 @@ return [ 'default_time_format' => 'H:i', 'default_date_format' => 'd/m/Y', + 'suppress_search_highlights' => false, // When searching, don't highlight matching search results when set to true ]; diff --git a/resources/views/livewire/datatables/tailwind-simple-pagination.blade.php b/resources/views/livewire/datatables/tailwind-simple-pagination.blade.php index 5180b149..d55d4100 100644 --- a/resources/views/livewire/datatables/tailwind-simple-pagination.blade.php +++ b/resources/views/livewire/datatables/tailwind-simple-pagination.blade.php @@ -6,19 +6,19 @@ Previous
@else - @endif @if ($paginator->hasMorePages()) - @else
Next diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 9105b902..ac0e2e80 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -934,7 +934,7 @@ public function mapCallbacks($paginatedCollection) $row->$name = $this->callbacks[$name]($value, $row); } - if ($this->search && $this->searchableColumns()->firstWhere('name', $name)) { + if ($this->search && ! config('livewire-datatables.suppress_search_highlights') && $this->searchableColumns()->firstWhere('name', $name)) { $row->$name = $this->highlight($row->$name, $this->search); } } @@ -952,13 +952,40 @@ public function getDisplayValue($index, $value) : $value; } + /* This can be called to apply highlting of the search term to some string. + * Motivation: Call this from your Column::Callback to apply highlight to a chosen section of the result. + */ + public function highlightStringWithCurrentSearchTerm(string $originalString) + { + if (!$this->search) { + return $originalString; + } else { + return static::highlightString($originalString, $this->search); + } + } + + /* Utility function for applying highlighting to given string */ + public static function highlightString(string $originalString, string $searchingForThisSubstring) + { + $searchStringNicelyHighlightedWithHtml = view( + 'datatables::highlight', + ['slot' => $searchingForThisSubstring] + )->render(); + $stringWithHighlightedSubstring = str_ireplace( + $searchingForThisSubstring, + $searchStringNicelyHighlightedWithHtml, + $originalString + ); + return $stringWithHighlightedSubstring; + } + public function highlight($value, $string) { $output = substr($value, stripos($value, $string), strlen($string)); if ($value instanceof View) { return $value - ->with(['value' => str_ireplace($string, view('datatables::highlight', ['slot' => $output]), $value->gatherData()['value'])]); + ->with(['value' => str_ireplace($string, view('datatables::highlight', ['slot' => $output]), $value->gatherData()['value'] ?? $value->gatherData()['slot'])]); } return str_ireplace($string, view('datatables::highlight', ['slot' => $output]), $value); From 05b42cca4b09d9b111e2914f06fe83769a6d9e41 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 16 Nov 2020 12:00:54 +0000 Subject: [PATCH 011/217] Apply fixes from StyleCI (#81) Co-authored-by: Mark Salmon --- src/Http/Livewire/LivewireDatatable.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index ac0e2e80..a713b201 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -957,7 +957,7 @@ public function getDisplayValue($index, $value) */ public function highlightStringWithCurrentSearchTerm(string $originalString) { - if (!$this->search) { + if (! $this->search) { return $originalString; } else { return static::highlightString($originalString, $this->search); @@ -976,6 +976,7 @@ public static function highlightString(string $originalString, string $searching $searchStringNicelyHighlightedWithHtml, $originalString ); + return $stringWithHighlightedSubstring; } From 20449358c1dd4407e1680fc838d066892594256d Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 16 Nov 2020 12:01:15 +0000 Subject: [PATCH 012/217] Truncate search (#72) * fix mobile paginator links * fix combined truncate and search Co-authored-by: Mark Salmon From b0f3b3b9ee801d6870de898436090b27b2bc19c0 Mon Sep 17 00:00:00 2001 From: waffshappen <44290023+waffshappen@users.noreply.github.com> Date: Mon, 16 Nov 2020 13:02:40 +0100 Subject: [PATCH 013/217] Update README.md (#64) * Update README.md Fix spelling * Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c664b6f..4ae4a23a 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ somewhere in your CSS |**hide-header**|*Boolean* default: *false*|The top row of the table including the column titles is removed if this is ```true```| | |**hide-pagination**|*Boolean* default: *false*|Pagination controls are removed if this is ```true```| | |**per-page**|*Integer* default: 10|Number of rows per page| ```per-page="20"``` | -|**exportable**|*Boolean* default: *false*|Allows tabel to bbe exported| `````` | +|**exportable**|*Boolean* default: *false*|Allows table to be exported| `````` | |**hideable**| _String_ | gives ability to show/hide columns, accepts strings 'inline', 'buttons', or 'select'| `````` | |**beforeTableSlot**| _String_ |blade view to be included immediately before the table in the component, which can therefore access public properties| | |**afterTableSlot**| _String_ |blade view to be included immediately after the table in the component, which can therefore access public properties| [demo](https://livewire-datatables.com/complex) | From 2db0794934c49ff9f66dc7701f3bc4e852388294 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Thu, 28 Jan 2021 13:59:15 +0000 Subject: [PATCH 014/217] wip --- resources/views/livewire/datatables/filters/select.blade.php | 4 ++-- src/Http/Livewire/LivewireDatatable.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/views/livewire/datatables/filters/select.blade.php b/resources/views/livewire/datatables/filters/select.blade.php index 3d5349d0..1b5a13ed 100644 --- a/resources/views/livewire/datatables/filters/select.blade.php +++ b/resources/views/livewire/datatables/filters/select.blade.php @@ -3,7 +3,7 @@ diff --git a/resources/views/livewire/datatables/filters/select.blade.php b/resources/views/livewire/datatables/filters/select.blade.php index 3d5349d0..1b5a13ed 100644 --- a/resources/views/livewire/datatables/filters/select.blade.php +++ b/resources/views/livewire/datatables/filters/select.blade.php @@ -3,7 +3,7 @@ -
\ No newline at end of file +
From ad44d925b38ba690096e5842d988ef258169de2e Mon Sep 17 00:00:00 2001 From: victorelec14 Date: Thu, 28 Jan 2021 20:19:11 +0100 Subject: [PATCH 022/217] Laravel localization compatibility (#122) --- .../views/livewire/datatables/datatable.blade.php | 10 +++++----- resources/views/livewire/datatables/delete.blade.php | 8 ++++---- .../livewire/datatables/filters/boolean.blade.php | 8 ++++---- .../livewire/datatables/filters/number.blade.php | 4 ++-- .../datatables/hide-column-multiselect.blade.php | 2 +- .../datatables/tailwind-pagination.blade.php | 12 ++++++------ .../datatables/tailwind-simple-pagination.blade.php | 8 ++++---- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index 03f7d41f..8c5b389c 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -15,7 +15,7 @@
- +
@endif @@ -124,7 +124,7 @@
@empty

- There's Nothing to show at the moment + {{ __("There's Nothing to show at the moment") }}

@endforelse
@@ -140,7 +140,7 @@ - +
@@ -155,7 +155,7 @@
- Results {{ $this->results->firstItem() }} - {{ $this->results->lastItem() }} of + {{__('Results')}} {{ $this->results->firstItem() }} - {{ $this->results->lastItem() }} {{__('of')}} {{ $this->results->total() }}
@endif diff --git a/resources/views/livewire/datatables/delete.blade.php b/resources/views/livewire/datatables/delete.blade.php index 0615430b..4a69e2fe 100644 --- a/resources/views/livewire/datatables/delete.blade.php +++ b/resources/views/livewire/datatables/delete.blade.php @@ -31,21 +31,21 @@ class="text-gray-400 hover:text-gray-500 focus:outline-none focus:text-gray-500

- Delete {{ $value }} + {{ __('Delete') }} {{ $value }}

- Are you sure? + {{ __('Are you sure?')}}
diff --git a/resources/views/livewire/datatables/filters/boolean.blade.php b/resources/views/livewire/datatables/filters/boolean.blade.php index e57bc874..9b57871a 100644 --- a/resources/views/livewire/datatables/filters/boolean.blade.php +++ b/resources/views/livewire/datatables/filters/boolean.blade.php @@ -7,8 +7,8 @@ class="m-1 text-sm leading-4 flex-grow form-select" x-on:input="$refs.select.value=''" > - - + +
@@ -16,13 +16,13 @@ class="m-1 text-sm leading-4 flex-grow form-select" @if($this->activeBooleanFilters[$index] == 1) @elseif(strlen($this->activeBooleanFilters[$index]) > 0) @endif diff --git a/resources/views/livewire/datatables/filters/number.blade.php b/resources/views/livewire/datatables/filters/number.blade.php index 88d78d4a..9f60b871 100644 --- a/resources/views/livewire/datatables/filters/number.blade.php +++ b/resources/views/livewire/datatables/filters/number.blade.php @@ -5,7 +5,7 @@ type="number" wire:input.debounce.500ms="doNumberFilterStart('{{ $index }}', $event.target.value)" class="m-1 pr-6 text-sm leading-4 flex-grow form-input" - placeholder="MIN" + placeholder="{{ __('MIN') }}" />
diff --git a/resources/views/livewire/datatables/tailwind-pagination.blade.php b/resources/views/livewire/datatables/tailwind-pagination.blade.php index 6f48e93e..7c323b87 100644 --- a/resources/views/livewire/datatables/tailwind-pagination.blade.php +++ b/resources/views/livewire/datatables/tailwind-pagination.blade.php @@ -1,13 +1,13 @@ - diff --git a/resources/views/livewire/datatables/filters/number.blade.php b/resources/views/livewire/datatables/filters/number.blade.php index 9f60b871..cec0361e 100644 --- a/resources/views/livewire/datatables/filters/number.blade.php +++ b/resources/views/livewire/datatables/filters/number.blade.php @@ -1,31 +1,31 @@
-
-
-
\ No newline at end of file +
diff --git a/resources/views/livewire/datatables/filters/select.blade.php b/resources/views/livewire/datatables/filters/select.blade.php index 1b5a13ed..adcb1252 100644 --- a/resources/views/livewire/datatables/filters/select.blade.php +++ b/resources/views/livewire/datatables/filters/select.blade.php @@ -3,7 +3,7 @@ diff --git a/resources/views/livewire/datatables/filters/time.blade.php b/resources/views/livewire/datatables/filters/time.blade.php index f6bf072c..6f1dea07 100644 --- a/resources/views/livewire/datatables/filters/time.blade.php +++ b/resources/views/livewire/datatables/filters/time.blade.php @@ -1,20 +1,20 @@
- -
-
- -
-
-
\ No newline at end of file +
diff --git a/src/Column.php b/src/Column.php index 279e8bb8..25dfb762 100644 --- a/src/Column.php +++ b/src/Column.php @@ -34,7 +34,7 @@ public static function name($name) $column = new static; $column->name = $name; $column->aggregate = Str::contains($name, ':') ? Str::after($name, ':') : $column->aggregate(); - $column->label = (string) Str::of($name)->after('.')->ucfirst(); + $column->label = (string) Str::of($name)->after('.')->ucfirst()->replace('_', ' '); if (Str::contains(Str::lower($name), ' as ')) { $column->name = array_reverse(preg_split('/ as /i', $name))[0]; @@ -128,6 +128,14 @@ public function filterable($options = null, $scopeFilter = null) return $this; } + public function booleanFilterable() + { + $this->filterable = true; + $this->filterView = 'boolean'; + + return $this; + } + public function excludeFromExport() { $this->preventExport = true; @@ -174,6 +182,13 @@ public function view($view) return $this; } + public function filterView($view) + { + $this->filterView = $view; + + return $this; + } + public function additionalSelects($selects) { $this->additionalSelects = is_array($selects) ? $selects : array_map('trim', explode(',', $selects)); diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 3c9c27a3..ef6dda85 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -111,7 +111,7 @@ public function getViewColumns() 'align', 'type', 'filterable', - 'filterview', + 'filterView', 'name', 'params', 'width', @@ -700,11 +700,13 @@ public function columnIsAggregateRelation($column) public function columnAggregateType($column) { - $custom_aggregate = Str::after(explode('.', $column['name'])[1], ':'); - - return $column['type'] === 'string' - ? 'group_concat' - : $custom_aggregate ?? 'count'; + return Str::contains($column['name'], ':') + ? Str::after(explode('.', $column['name'])[1], ':') + : ( + $column['type'] === 'string' + ? 'group_concat' + : 'count' + ); } public function buildDatabaseQuery($export = false) @@ -812,6 +814,16 @@ public function addBooleanFilters() $this->addScopeSelectFilter($query, $index, $value); } elseif ($this->columnIsAggregateRelation($this->freshColumns[$index])) { $this->addAggregateFilter($query, $index, $value); + } elseif ($this->freshColumns[$index]['type'] === 'string') { + if ($value == 1) { + $query->whereNotNull($this->getColumnField($index)[0]) + ->where($this->getColumnField($index)[0], '<>', ''); + } elseif (strlen($value)) { + $query->where(function ($query) use ($index) { + $query->whereNull(DB::raw($this->getColumnField($index)[0])) + ->orWhere(DB::raw($this->getColumnField($index)[0]), ''); + }); + } } elseif ($value == 1) { $query->where(DB::raw($this->getColumnField($index)[0]), '>', 0); } elseif (strlen($value)) { diff --git a/src/LivewireDatatablesServiceProvider.php b/src/LivewireDatatablesServiceProvider.php index 918a3eaa..540851ce 100644 --- a/src/LivewireDatatablesServiceProvider.php +++ b/src/LivewireDatatablesServiceProvider.php @@ -146,7 +146,6 @@ public function loadRelationMacros() } $expression = $aggregate === 'group_concat' - ? $distinct_aggregate : new Expression('COALESCE('.$aggregate."({$column}),0)"); diff --git a/tests/ColumnSetTest.php b/tests/ColumnSetTest.php index 68ab4cd1..14130cf0 100644 --- a/tests/ColumnSetTest.php +++ b/tests/ColumnSetTest.php @@ -48,9 +48,9 @@ public function fieldDataProvider() ['Category', 1, 'category'], ['Body', 2, 'body'], ['Flag', 3, 'flag'], - ['Expires_at', 4, 'expires_at'], - ['Updated_at', 5, 'updated_at'], - ['Created_at', 6, 'created_at'], + ['Expires at', 4, 'expires_at'], + ['Updated at', 5, 'updated_at'], + ['Created at', 6, 'created_at'], ['Id', 7, 'id'], ]; } diff --git a/tests/LivewireDatatableClassTest.php b/tests/LivewireDatatableClassTest.php index 20ae7de2..8b7182e8 100644 --- a/tests/LivewireDatatableClassTest.php +++ b/tests/LivewireDatatableClassTest.php @@ -27,6 +27,7 @@ public function it_can_mount_using_the_class() 4 => 'Flag', 5 => 'Expiry', 6 => 'Relation', + 7 => 'BooleanFilterableSubject', ], collect($subject->columns)->map->label->toArray()); } @@ -101,6 +102,18 @@ public function it_can_filter_results_based_on_boolean() ->assertSee('Results 1 - 1'); } + /** @test */ + public function it_can_filter_strings_as_a_boolean() + { + factory(DummyModel::class)->create(['subject' => 'has contents']); + factory(DummyModel::class)->create(['subject' => '']); + + $subject = Livewire::test(DummyTable::class) + ->assertSee('Results 1 - 2') + ->call('doBooleanFilter', 7, '1') + ->assertSee('Results 1 - 1'); + } + /** @test */ public function it_can_filter_results_based_on_selects() { diff --git a/tests/LivewireDatatableTemplateTest.php b/tests/LivewireDatatableTemplateTest.php index 0c0a9e7e..577df2be 100644 --- a/tests/LivewireDatatableTemplateTest.php +++ b/tests/LivewireDatatableTemplateTest.php @@ -23,9 +23,9 @@ public function it_can_mount_from_the_default_template_with_a_model() 2 => 'Category', 3 => 'Body', 4 => 'Flag', - 5 => 'Expires_at', - 6 => 'Created_at', - 7 => 'Updated_at', + 5 => 'Expires at', + 6 => 'Created at', + 7 => 'Updated at', ], collect($subject->columns)->map->label->toArray()); } @@ -100,9 +100,9 @@ public function it_can_exclude_columns_from_a_property() 2 => 'Category', 3 => 'Body', 4 => 'Flag', - 5 => 'Expires_at', - 6 => 'Created_at', - 7 => 'Updated_at', + 5 => 'Expires at', + 6 => 'Created at', + 7 => 'Updated at', ], collect($subject->columns)->map->label->toArray()); } diff --git a/tests/classes/DummyTable.php b/tests/classes/DummyTable.php index 0992f763..441f4701 100644 --- a/tests/classes/DummyTable.php +++ b/tests/classes/DummyTable.php @@ -41,6 +41,11 @@ public function columns() Column::name('dummy_has_one.name') ->label('Relation'), + + Column::name('subject AS string') + ->label('BooleanFilterableSubject') + ->booleanFilterable() + ->hide(), ]; } } From 22f548673e168cd7dd931259b3f2a5ecf585084f Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 5 Jul 2021 15:26:34 +0100 Subject: [PATCH 055/217] search box style --- resources/views/livewire/datatables/datatable.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index 3e897036..0376de07 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -15,8 +15,8 @@
- -
+ +
From 5931fec53e4940138e6bd216a94734f09dab99d1 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 5 Jul 2021 22:46:38 +0100 Subject: [PATCH 056/217] fix relational callback columns --- src/Http/Livewire/LivewireDatatable.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index ef6dda85..accbe06f 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -167,9 +167,9 @@ public function resolveCheckboxColumnName($column) public function resolveAdditionalSelects($column) { - $selects = collect($column->additionalSelects)->map(function ($select) { + $selects = collect($column->additionalSelects)->map(function ($select) use ($column) { return Str::contains($select, '.') - ? $this->resolveRelationColumn($select, Str::contains($select, ':') ? Str::before($select, ':') : null) + ? $this->resolveRelationColumn($select, Str::contains($select, ':') ? Str::after($select, ':') : null, $column->name) : $this->query->getModel()->getTable().'.'.$select; }); @@ -246,14 +246,14 @@ public function getSelectStatements($withAlias = false, $export = false) }); } - protected function resolveRelationColumn($name, $aggregate = null) + protected function resolveRelationColumn($name, $aggregate = null, $alias = null) { $parts = explode('.', Str::before($name, ':')); $columnName = array_pop($parts); $relation = implode('.', $parts); return method_exists($this->query->getModel(), $parts[0]) - ? $this->joinRelation($relation, $columnName, $aggregate, $name) + ? $this->joinRelation($relation, $columnName, $aggregate, $alias ?? $name) : $name; } From f75471560b36aee38ff10a67ee18a0e209f381e4 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 5 Jul 2021 23:02:24 +0100 Subject: [PATCH 057/217] fixed session storage for mulitple tables --- src/Http/Livewire/LivewireDatatable.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index accbe06f..1f457907 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -92,8 +92,9 @@ public function mount( $this->initialiseSort(); // check if there are sorting vars in the session - $this->sort = session()->get('dt_'.$this->name.'_sort', $this->sort); - $this->direction = session()->get('dt_'.$this->name.'_direction', $this->direction); + $key = Str::snake(Str::afterLast(get_called_class(), '\\')); + $this->sort = session()->get($key.$this->name.'_sort', $this->sort); + $this->direction = session()->get($key.$this->name.'_direction', $this->direction); $this->perPage = $perPage ?? config('livewire-datatables.default_per_page', 10); } @@ -418,8 +419,10 @@ public function sort($index) } $this->page = 1; + //pp8ODFIWKxcObIP6dXT0 // put sorting info in the session - session()->put(['dt_'.$this->name.'_sort' => $this->sort, 'dt_'.$this->name.'_direction' => $this->direction]); + $key = Str::snake(Str::afterLast(get_called_class(), '\\')); + session()->put([$key.$this->name.'_sort' => $this->sort, $key.$this->name.'_direction' => $this->direction]); } public function toggle($index) From b8933d5562212a01512f235207ef9f9276c7bcf1 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 5 Jul 2021 23:06:35 +0100 Subject: [PATCH 058/217] recognise $perPage public property on class --- src/Http/Livewire/LivewireDatatable.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 1f457907..a7277525 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -95,7 +95,7 @@ public function mount( $key = Str::snake(Str::afterLast(get_called_class(), '\\')); $this->sort = session()->get($key.$this->name.'_sort', $this->sort); $this->direction = session()->get($key.$this->name.'_direction', $this->direction); - $this->perPage = $perPage ?? config('livewire-datatables.default_per_page', 10); + $this->perPage = $perPage ?? $this->perPage ?? config('livewire-datatables.default_per_page', 10); } public function columns() @@ -419,8 +419,6 @@ public function sort($index) } $this->page = 1; - //pp8ODFIWKxcObIP6dXT0 - // put sorting info in the session $key = Str::snake(Str::afterLast(get_called_class(), '\\')); session()->put([$key.$this->name.'_sort' => $this->sort, $key.$this->name.'_direction' => $this->direction]); } From d93862f7ba33f1ce5fe7ea032a390f59085f7d14 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Tue, 6 Jul 2021 11:20:58 +0100 Subject: [PATCH 059/217] #31 make column unsortable --- README.md | 3 +- .../datatables/header-inline-hide.blade.php | 35 +++++++++++-------- .../datatables/header-no-hide.blade.php | 33 +++++++++-------- src/Column.php | 8 +++++ src/Http/Livewire/LivewireDatatable.php | 1 + tests/ColumnTest.php | 3 ++ 6 files changed, 54 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 14ae8699..a5689cf8 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,8 @@ class ComplexDemoTable extends LivewireDatatable |**alignCenter**| | Center-aligns column header and contents |```Column::delete()->alignCenter()```| |**alignRight**| | Right-aligns column header and contents |```Column::delete()->alignRight()```| |**editable**| | Marks the column as editable | _(see below)_| -|**excludeFromExport**| | Prevents the column as editable |```Column::name('email')->exclude```| +|**excludeFromExport**| | Excludes the column from export |```Column::name('email')->excludeFromExport()```| +|**unsortable**| | Prevents the column being sortable |```Column::name('email')->unsortable()```| ___ ### Listener diff --git a/resources/views/livewire/datatables/header-inline-hide.blade.php b/resources/views/livewire/datatables/header-inline-hide.blade.php index d16bb7bd..0a9c53b9 100644 --- a/resources/views/livewire/datatables/header-inline-hide.blade.php +++ b/resources/views/livewire/datatables/header-inline-hide.blade.php @@ -1,6 +1,7 @@ @endif diff --git a/src/Column.php b/src/Column.php index 25dfb762..2b601545 100644 --- a/src/Column.php +++ b/src/Column.php @@ -17,6 +17,7 @@ class Column public $searchable; public $filterable; public $sort; + public $unsortable; public $defaultSort; public $callback; public $hidden; @@ -113,6 +114,13 @@ public function defaultSort($direction = true) return $this; } + public function unsortable() + { + $this->unsortable = true; + + return $this; + } + public function searchable() { $this->searchable = true; diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index a7277525..6b4df4c8 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -116,6 +116,7 @@ public function getViewColumns() 'name', 'params', 'width', + 'unsortable', ])->toArray(); })->toArray(); } diff --git a/tests/ColumnTest.php b/tests/ColumnTest.php index f22b3f0f..e5b128ef 100644 --- a/tests/ColumnTest.php +++ b/tests/ColumnTest.php @@ -92,6 +92,7 @@ public function it_returns_an_array_from_column() 'align' => 'left', 'preventExport' => null, 'width' => null, + 'unsortable' => null, ], $subject); } @@ -127,6 +128,7 @@ public function it_returns_an_array_from_raw() 'align' => 'left', 'preventExport' => null, 'width' => null, + 'unsortable' => null, ], $subject); } @@ -161,6 +163,7 @@ public function it_returns_width_property_from_column() 'align' => 'left', 'preventExport' => null, 'width' => '1em', + 'unsortable' => null, ], $subject); } From bd73fec5cb5309d58d37224d198cd33d97394826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C4=B7elis=20Za=C4=BCais?= Date: Thu, 15 Jul 2021 00:47:05 +0300 Subject: [PATCH 060/217] Make search field compatible with tailwindcss/forms (#234) This makes search field look nicer out of the box. --- resources/views/livewire/datatables/datatable.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index 0376de07..0deea7d4 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -15,7 +15,7 @@
- +
+ + +
+
+ @if(count($rule['content']) > 1) +
+ + +
+ @endif +
+
+
+ @include('datatables::complex-query-group', [ + 'parentIndex' => $key, + 'rules' => $rule['content'], + 'logic' => $rule['logic'] + ]) +
+
+
+ + +
+ @unless($key === 0) + + @endunless +
+ +
+ @endif +
+ @endforeach +
diff --git a/resources/views/livewire/datatables/complex-query-rule.blade.php b/resources/views/livewire/datatables/complex-query-rule.blade.php new file mode 100644 index 00000000..ded5e07d --- /dev/null +++ b/resources/views/livewire/datatables/complex-query-rule.blade.php @@ -0,0 +1,96 @@ +
+ @php $key = collect(explode('.', $parentIndex))->join(".content.") . ".content" @endphp +
+
+
+ +
+ +
+
+ + @if ($options = $this->getOperands($key)) +
+ +
+ +
+
+ @endif + + @if (!in_array($rule['content']['operand'], ['is empty', 'is not empty'])) +
+ @if ($column = $this->getRuleColumn($key)) + +
+ @if (is_array($column['filterable'])) + + @elseif($column['type'] === 'boolean') + + @elseif($column['type'] === 'date') + + @elseif($column['type'] === 'time') + + @else + + @endif +
+ @endif +
+ @endif +
+
+ + +
+
+
diff --git a/resources/views/livewire/datatables/complex-query.blade.php b/resources/views/livewire/datatables/complex-query.blade.php new file mode 100644 index 00000000..3d7b9cd3 --- /dev/null +++ b/resources/views/livewire/datatables/complex-query.blade.php @@ -0,0 +1,73 @@ +
+
+ Query Builder + @if($errors->any()) +
You have missing values in your rules
+ @endif
+
+ + @if(count($this->rules[0]['content'])) +
{{ $this->rulesString }}@if($errors->any()) Invalid rules @endif
+ @endif + +
@include('datatables::complex-query-group', ['rules' => $rules, 'parentIndex' => null])
+ + @if(count($this->rules[0]['content'])) + @unless($errors->any()) +
+
+ {{-- --}} +
+
+ @isset($savedQueries) +
+ + +
+ @endisset + +
+
+ @endif + + @endif + @if(count($savedQueries ?? [])) +
+
Saved Queries
+
+ @foreach($savedQueries as $saved) +
+ + +
+ @endforeach +
+
+ @endif +
diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index c67dd1fe..560d0231 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -6,7 +6,7 @@ @endif
-
+
@if($this->searchableColumns()->count())
@@ -26,12 +26,22 @@ @endif
+ @if($this->activeFilters) + FILTERS ACTIVE + @endif +
+ @if($this->activeFilters) + + @endif + @if($exportable)
@@ -55,7 +65,7 @@
@endif -
+
@unless($this->hideHeader) @@ -131,8 +141,10 @@ @endforelse
- @unless($this->hidePagination) -
+
+ + @unless($this->hidePagination) +
{{-- check if there is any data --}} @if(count($this->results)) @@ -162,9 +174,15 @@ @endif
- @endif -
+ @endif
+ + @if($complex) +
+ +
+ @endif + @if($afterTableSlot)
@include($afterTableSlot) diff --git a/resources/views/livewire/datatables/filters/select.blade.php b/resources/views/livewire/datatables/filters/select.blade.php index adcb1252..6261461f 100644 --- a/resources/views/livewire/datatables/filters/select.blade.php +++ b/resources/views/livewire/datatables/filters/select.blade.php @@ -9,15 +9,15 @@ class="w-full m-1 text-sm leading-4 block rounded-md border-gray-300 shadow-sm f > @foreach($options as $value => $label) - @if(is_object($label)) - - @elseif(is_array($label)) - - @elseif(is_numeric($value)) - - @else - - @endif + @if(is_object($label)) + + @elseif(is_array($label)) + + @elseif(is_numeric($value)) + + @else + + @endif @endforeach
diff --git a/src/Column.php b/src/Column.php index 72b0b4a5..efe3b731 100644 --- a/src/Column.php +++ b/src/Column.php @@ -15,6 +15,7 @@ class Column public $base; public $raw; public $searchable; + public $filterOn; public $filterable; public $sort; public $unsortable; @@ -139,6 +140,13 @@ public function filterable($options = null, $scopeFilter = null) return $this; } + public function filterOn($query) + { + $this->filterOn = $query; + + return $this; + } + public function booleanFilterable() { $this->filterable = true; diff --git a/src/Http/Livewire/ComplexQuery.php b/src/Http/Livewire/ComplexQuery.php new file mode 100644 index 00000000..8341c62a --- /dev/null +++ b/src/Http/Livewire/ComplexQuery.php @@ -0,0 +1,228 @@ + 'group', + 'logic' => 'and', + 'content' => [], + ], + ]; + + protected $listeners = ['updateSavedQueries', 'resetQuery']; + + public function mount($columns, $persistKey, $savedQueries = null) + { + $this->columns = $columns; + $this->persistKey = $persistKey; + $this->savedQueries = $savedQueries; + } + + public function updateSavedQueries($savedQueries = null) + { + $this->mount($this->columns, $this->persistKey, $savedQueries ?? $this->savedQueries); + } + + public function updatedRules($value, $key) + { + $this->clearOperandAndValueWhenColumnChanged($key); + + $this->runQuery(); + } + + public function clearOperandAndValueWhenColumnChanged($key) + { + if (Str::endsWith($key, 'column')) { + data_set($this->rules, str_replace('column', 'operand', $key), null); + data_set($this->rules, str_replace('column', 'value', $key), null); + } + } + + public function getRulesStringProperty($rules = null, $logic = 'and') + { + return collect($rules ?? $this->rules)->map(function ($rule) { + return $rule['type'] === 'rule' + ? implode(' ', [$this->columns[$rule['content']['column']]['label'] ?? '', $rule['content']['operand'] ?? '', $rule['content']['value'] ?? '']) + : '(' . $this->getRulesStringProperty($rule['content'], $rule['logic']) . ')'; + })->join(strtoupper(" $logic ")); + } + + public function runQuery() + { + $this->validateRules(); + + $this->emit('complexQuery', count($this->rules[0]['content']) ? $this->rules : null); + } + + public function saveQuery($name) + { + $this->emitUp('saveQuery', $name, $this->rules); + } + + public function loadRules($rules) + { + $this->rules = $rules; + $this->runQuery(); + } + + public function deleteRules($id) + { + $this->emitUp('deleteQuery', $id); + } + + public function resetQuery() + { + $this->reset('rules'); + $this->runQuery(); + } + + public function validateRules($rules = null, $key = '') + { + $rules = $rules ?? $this->rules[0]['content']; + + collect($rules)->each(function ($rule, $i) { + if ($rule['type'] === 'rule') { + $v = Validator::make($rule['content'], ['column' => 'required']); + + $v->sometimes('operand', 'required', function ($rule) { + return ! ($rule['value'] === 'true' || $rule['value'] === 'false'); + }); + + $v->sometimes('value', 'required', function ($rule) { + return ! collect([ + 'is empty', + 'is not empty', + ])->contains($rule['operand']); + }); + + $v->validate(); + } else { + $this->validateRules($rule['content']); + } + }); + } + + public function addRule($index) + { + $temp = Arr::get($this->rules, $index); + + $temp[] = [ + 'type' => 'rule', + 'content' => [ + 'column' => null, + 'operand' => null, + 'value' => null, + ], + ]; + + Arr::set($this->rules, $index, $temp); + + $this->validateRules(); + } + + public function duplicateRule($index) + { + $current = Arr::get($this->rules, Str::beforeLast($index, '.content')); + $parentGroup = Arr::get($this->rules, Str::beforeLast(Str::beforeLast($index, '.content'), '.')); + + $parentGroup[] = $current; + + Arr::set($this->rules, Str::beforeLast(Str::beforeLast($index, '.content'), '.'), $parentGroup); + + $this->validateRules(); + } + + public function moveRule($from, $to) + { + $mover = Arr::get($this->rules, Str::beforeLast($from, '.')); + $newParent = Arr::get($this->rules, $to); + + if (is_array($newParent) && is_array($mover)) { + array_push($newParent, $mover); + Arr::set($this->rules, $to, $newParent); + Arr::pull($this->rules, Str::beforeLast($from, '.')); + } + + $this->runQuery(); + } + + public function addGroup($index) + { + $temp = Arr::get($this->rules, $index); + + $temp[] = [ + 'type' => 'group', + 'logic' => 'and', + 'content' => [], + ]; + + Arr::set($this->rules, $index, $temp); + } + + public function removeRule($index) + { + Arr::pull($this->rules, Str::beforeLast($index, '.')); + + $this->runQuery(); + } + + public function setRuleColumn($index, $value) + { + $this->rules[$index]['column'] = $this->columns[$value]; + } + + public function setRuleOperand($index, $value) + { + $this->rules[$index]['operand'] = $value; + } + + public function setRuleValue($index, $value) + { + $this->rules[$index]['value'] = $value; + } + + public function getRuleColumn($key) + { + return $this->columns[Arr::get($this->rules, $key . '.column')] ?? null; + } + + public function getOperands($key) + { + $operands = [ + 'string' => ['equals', 'does not equal', 'contains', 'does not contain', 'is empty', 'is not empty', 'begins with', 'ends with'], + 'json' => ['equals', 'does not equal', 'contains', 'does not contain', 'is empty', 'is not empty', 'begins with', 'ends with'], + 'editable' => ['equals', 'does not equal', 'contains', 'does not contain', 'is empty', 'is not empty', 'begins with', 'ends with'], + 'number' => ['=', '<>', '<', '<=', '>', '>='], + 'date' => ['=', '<>', '<', '<=', '>', '>='], + 'time' => ['=', '<>', '<', '<=', '>', '>='], + 'boolean' => [], + 'scope' => ['includes'], + ]; + + if (! $this->getRuleColumn($key)) { + return []; + } + + return optional($this->getRuleColumn($key))['scopeFilter'] + ? $operands['scope'] + : $operands[$this->getRuleColumn($key)['type']]; + } + + public function render() + { + return view('datatables::complex-query'); + } +} diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index c283940c..9967fcf5 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasOneThrough; use Illuminate\Database\Query\Expression; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; use Illuminate\View\View; @@ -53,10 +54,34 @@ class LivewireDatatable extends Component public $selected = []; public $beforeTableSlot; public $afterTableSlot; + public $complex; + public $complexQuery; + public $persistComplexQuery; + public $title; public $name; + public $userFilter; protected $query; - protected $listeners = ['refreshLivewireDatatable']; + protected $listeners = ['refreshLivewireDatatable', 'complexQuery', 'saveQuery', 'deleteQuery']; + + protected $operators = [ + '=' => '=', + '>' => '>', + '<' => '<', + '<>' => '<>', + '>=' => '>=', + '<=' => '<=', + 'equals' => '=', + 'does not equal' => '<>', + 'contains' => 'LIKE', + 'does not contain' => 'NOT LIKE', + 'begins with' => 'LIKE', + 'ends with' => 'LIKE', + 'is empty' => '=', + 'is not empty' => '<>', + 'includes' => '=', + 'does not include' => '<>', + ]; public function updatedSearch() { @@ -112,6 +137,7 @@ public function getViewColumns() 'align', 'type', 'filterable', + 'complex', 'filterView', 'name', 'params', @@ -122,6 +148,20 @@ public function getViewColumns() })->toArray(); } + public function getComplexColumnsProperty() + { + return collect($this->columns)->filter(function ($column) { + return $column['filterable']; + }); + } + + public function getPersistKeyProperty() + { + return $this->persistComplexQuery + ? Str::kebab(Str::afterLast(get_class($this), '\\')) + : null; + } + public function getModelInstanceProperty() { return $this->model::firstOrFail(); @@ -139,7 +179,6 @@ public function delete($id) public function getProcessedColumnsProperty() { - // dd($this->columns()); return ColumnSet::build($this->columns()) ->include($this->include) ->exclude($this->exclude) @@ -455,6 +494,7 @@ public function doTextFilter($index, $value) foreach (explode(' ', $value) as $val) { $this->activeTextFilters[$index][] = $val; } + $this->page = 1; } @@ -501,6 +541,7 @@ public function clearEmptyNumberFilter($index) if ((! isset($this->activeNumberFilters[$index]['start']) || $this->activeNumberFilters[$index]['start'] == '') && (! isset($this->activeNumberFilters[$index]['end']) || $this->activeNumberFilters[$index]['end'] == '')) { $this->removeNumberFilter($index); } + $this->page = 1; } public function removeSelectFilter($column, $key = null) @@ -509,16 +550,19 @@ public function removeSelectFilter($column, $key = null) if (count($this->activeSelectFilters[$column]) < 1) { unset($this->activeSelectFilters[$column]); } + $this->page = 1; } public function clearDateFilter() { $this->dates = null; + $this->page = 1; } public function clearTimeFilter() { $this->times = null; + $this->page = 1; } public function clearFilters() @@ -527,6 +571,7 @@ public function clearFilters() $this->activeBooleanFilters = []; $this->activeTextFilters = []; $this->activeNumberFilters = []; + $this->page = 1; } public function clearAllFilters() @@ -537,6 +582,11 @@ public function clearAllFilters() $this->activeBooleanFilters = []; $this->activeTextFilters = []; $this->activeNumberFilters = []; + $this->complexQuery = null; + $this->userFilter = null; + $this->page = 1; + + $this->emitTo('complex-query', 'resetQuery'); } public function removeBooleanFilter($column) @@ -561,8 +611,16 @@ public function removeNumberFilter($column) unset($this->activeNumberFilters[$column]); } - public function getColumnField($index) + public function getColumnFilterStatement($index) { + if ($this->freshColumns[$index]['type'] === 'editable') { + return [$this->getSelectStatements()[$index][0]]; + } + + if ($this->freshColumns[$index]['filterOn']) { + return [$this->freshColumns[$index]['filterOn']]; + } + if ($this->freshColumns[$index]['scope']) { return 'scope'; } @@ -571,7 +629,7 @@ public function getColumnField($index) return [(string) $this->freshColumns[$index]['sort']]; } - return [$this->getSelectStatements()[$index]]; + return Arr::wrap($this->getSelectStatements()[$index]); } public function addScopeSelectFilter($query, $index, $value) @@ -592,13 +650,15 @@ public function addScopeNumberFilter($query, $index, $value) return $query->{$this->freshColumns[$index]['scopeFilter']}($value); } - public function addAggregateFilter($query, $index, $filter) + public function addAggregateFilter($query, $index, $filter, $operand = null) { $column = $this->freshColumns[$index]; $relation = Str::before($column['name'], '.'); $aggregate = $this->columnAggregateType($column); $field = Str::before(explode('.', $column['name'])[1], ':'); + $filter = Arr::wrap($filter); + $query->when($column['type'] === 'boolean', function ($query) use ($filter, $relation, $field, $aggregate) { $query->where(function ($query) use ($filter, $relation, $field, $aggregate) { if ($filter) { @@ -617,6 +677,8 @@ public function addAggregateFilter($query, $index, $filter) $query->hasAggregate($relation, $field, $aggregate, '>=', $filter['start']); })->when(isset($filter['end']), function ($query) use ($filter, $relation, $field, $aggregate) { $query->hasAggregate($relation, $field, $aggregate, '<=', $filter['end']); + })->when(isset($operand), function ($query) use ($filter, $relation, $field, $aggregate, $operand) { + $query->hasAggregate($relation, $field, $aggregate, $operand, $filter); }); } @@ -683,7 +745,9 @@ public function getActiveFiltersProperty() || count($this->activeSelectFilters) || count($this->activeBooleanFilters) || count($this->activeTextFilters) - || count($this->activeNumberFilters); + || count($this->activeNumberFilters) + || is_array($this->complexQuery) + || $this->userFilter; } public function columnIsRelation($column) @@ -698,7 +762,7 @@ public function columnIsAggregateRelation($column) } $relation = $this->builder()->getRelation(Str::before($column['name'], '.')); - return /* $relation instanceof HasOne || */ $relation instanceof HasManyThrough || $relation instanceof HasMany || $relation instanceof belongsToMany; + return $relation instanceof HasManyThrough || $relation instanceof HasMany || $relation instanceof belongsToMany; } public function columnAggregateType($column) @@ -718,9 +782,9 @@ public function buildDatabaseQuery($export = false) $this->query->addSelect( $this->getSelectStatements(true, $export) - ->filter() - ->flatten() - ->toArray() + ->filter() + ->flatten() + ->toArray() ); $this->addGlobalSearch() @@ -731,9 +795,99 @@ public function buildDatabaseQuery($export = false) ->addNumberFilters() ->addDateRangeFilter() ->addTimeRangeFilter() + ->addComplexQuery() ->addSort(); } + public function complexQuery($rules) + { + $this->complexQuery = $rules; + } + + public function addComplexQuery() + { + if (! $this->complexQuery) { + return $this; + } + + $this->query->where(function ($query) { + $this->processNested($this->complexQuery, $query); + }); + + $this->page = 1; + + return $this; + } + + private function complexOperator($operand) + { + return $operand ? $this->operators[$operand] : '='; + } + + private function complexValue($rule) + { + if (isset($rule['content']['operand'])) { + if ($rule['content']['operand'] === 'contains') { + return '%' . $rule['content']['value'] . '%'; + } elseif ($rule['content']['operand'] === 'does not contain') { + return '%' . $rule['content']['value'] . '%'; + } elseif ($rule['content']['operand'] === 'begins with') { + return $rule['content']['value'] . '%'; + } elseif ($rule['content']['operand'] === 'ends with') { + return '%' . $rule['content']['value']; + } elseif ($rule['content']['operand'] === 'is empty' || $rule['content']['operand'] === 'is not empty') { + return ''; + } + } + + return $rule['content']['value']; + } + + public function processNested($rules = null, $query = null, $logic = 'and') + { + collect($rules)->each(function ($rule) use ($query, $logic) { + if ($rule['type'] === 'rule' && isset($rule['content']['column'])) { + $query->where(function ($query) use ($rule) { + if (! $this->addScopeSelectFilter($query, $rule['content']['column'], $rule['content']['value'])) { + if ($this->columnIsAggregateRelation($this->freshColumns[$rule['content']['column']])) { + $query = $this->addAggregateFilter($query, $rule['content']['column'], $this->complexValue($rule), $this->complexOperator($rule['content']['operand'])); + } else { + foreach ($this->getColumnFilterStatement($rule['content']['column']) as $column) { + if ($rule['content']['operand'] === 'is empty') { + $query->whereNull($column); + } elseif ($rule['content']['operand'] === 'is not empty') { + $query->whereNotNull($column); + } elseif ($this->columns[$rule['content']['column']]['type'] === 'boolean') { + if ($rule['content']['value'] === 'true') { + $query->whereNotNull(Str::contains($column, '(') ? DB::raw($column) : $column); + } else { + $query->whereNull(Str::contains($column, '(') ? DB::raw($column) : $column); + } + } else { + $col = (isset($this->freshColumns[$rule['content']['column']]['round']) && $this->freshColumns[$rule['content']['column']]['round'] !== null) + ? DB::raw('ROUND(' . $column . ', ' . $this->freshColumns[$rule['content']['column']]['round'] . ')') + : (Str::contains($column, '(') ? DB::raw($column) : $column); + + $query->orWhere( + $col, + $this->complexOperator($rule['content']['operand']), + $this->complexValue($rule) + ); + } + } + } + } + }, null, null, $logic); + } else { + $query->where(function ($q) use ($rule) { + $this->processNested($rule['content'], $q, $rule['logic']); + }, null, null, $logic); + } + }); + + return $query; + } + public function addGlobalSearch() { if (! $this->search) { @@ -745,7 +899,7 @@ public function addGlobalSearch() $query->where(function ($query) use ($search) { $this->searchableColumns()->each(function ($column, $i) use ($query, $search) { $query->orWhere(function ($query) use ($i, $search) { - foreach ($this->getColumnField($i) as $column) { + foreach ($this->getColumnFilterStatement($i) as $column) { $query->when(is_array($column), function ($query) use ($search, $column) { foreach ($column as $col) { $query->orWhereRaw('LOWER(' . $col . ') like ?', '%' . mb_strtolower($search) . '%'); @@ -791,11 +945,23 @@ public function addSelectFilters() $this->addAggregateFilter($query, $index, $activeSelectFilter); } else { if (! $this->addScopeSelectFilter($query, $index, $value)) { - $query->orWhere(function ($query) use ($value, $index) { - foreach ($this->getColumnField($index) as $column) { - $query->orWhere($column, $value); - } - }); + if ($this->freshColumns[$index]['type'] === 'json') { + $query->where(function ($query) use ($value, $index) { + foreach ($this->getColumnFilterStatement($index) as $column) { + $query->whereRaw('LOWER(' . $column . ') like ?', [strtolower("%$value%")]); + } + }); + } else { + $query->orWhere(function ($query) use ($value, $index) { + foreach ($this->getColumnFilterStatement($index) as $column) { + if (Str::contains(strtolower($column), 'concat')) { + $query->orWhereRaw('LOWER(' . $column . ') like ?', [strtolower("%$value%")]); + } else { + $query->orWhereRaw($column . ' = ?', $value); + } + } + }); + } } } } @@ -813,26 +979,26 @@ public function addBooleanFilters() } $this->query->where(function ($query) { foreach ($this->activeBooleanFilters as $index => $value) { - if ($this->getColumnField($index) === 'scope') { + if ($this->getColumnFilterStatement($index) === 'scope') { $this->addScopeSelectFilter($query, $index, $value); } elseif ($this->columnIsAggregateRelation($this->freshColumns[$index])) { $this->addAggregateFilter($query, $index, $value); } elseif ($this->freshColumns[$index]['type'] === 'string') { if ($value == 1) { - $query->whereNotNull($this->getColumnField($index)[0]) - ->where($this->getColumnField($index)[0], '<>', ''); + $query->whereNotNull($this->getColumnFilterStatement($index)[0]) + ->where($this->getColumnFilterStatement($index)[0], '<>', ''); } elseif (strlen($value)) { $query->where(function ($query) use ($index) { - $query->whereNull(DB::raw($this->getColumnField($index)[0])) - ->orWhere(DB::raw($this->getColumnField($index)[0]), ''); + $query->whereNull(DB::raw($this->getColumnFilterStatement($index)[0])) + ->orWhere(DB::raw($this->getColumnFilterStatement($index)[0]), ''); }); } } elseif ($value == 1) { - $query->where(DB::raw($this->getColumnField($index)[0]), '>', 0); + $query->where(DB::raw($this->getColumnFilterStatement($index)[0]), '>', 0); } elseif (strlen($value)) { $query->where(function ($query) use ($index) { - $query->whereNull(DB::raw($this->getColumnField($index)[0])) - ->orWhere(DB::raw($this->getColumnField($index)[0]), 0); + $query->whereNull(DB::raw($this->getColumnFilterStatement($index)[0])) + ->orWhere(DB::raw($this->getColumnFilterStatement($index)[0]), 0); }); } } @@ -855,7 +1021,7 @@ public function addTextFilters() $this->addAggregateFilter($query, $index, $activeTextFilter); } else { $query->orWhere(function ($query) use ($index, $value) { - foreach ($this->getColumnField($index) as $column) { + foreach ($this->getColumnFilterStatement($index) as $column) { $column = is_array($column) ? $column[0] : $column; $query->orWhereRaw('LOWER(' . $column . ') like ?', [mb_strtolower("%$value%")]); } @@ -882,12 +1048,15 @@ public function addNumberFilters() $this->addScopeNumberFilter($query, $index, [ isset($filter['start']) ? $filter['start'] : 0, isset($filter['end']) ? $filter['end'] : 9999999999, - ]) - ?? $query->when(isset($filter['start']), function ($query) use ($filter, $index) { - $query->whereRaw($this->getColumnField($index)[0] . ' >= ?', $filter['start']); - })->when(isset($filter['end']), function ($query) use ($filter, $index) { - $query->whereRaw($this->getColumnField($index)[0] . ' <= ?', $filter['end']); - }); + ]) ?? $query->when(isset($filter['start']), function ($query) use ($filter, $index) { + $query->whereRaw($this->getColumnFilterStatement($index)[0] . ' >= ?', $filter['start']); + })->when(isset($filter['end']), function ($query) use ($filter, $index) { + if (isset($this->freshColumns[$index]['round']) && $this->freshColumns[$index]['round'] !== null) { + $query->whereRaw('ROUND(' . $this->getColumnFilterStatement($index)[0] . ',' . $this->freshColumns[$index]['round'] . ') <= ?', $filter['end']); + } else { + $query->whereRaw($this->getColumnFilterStatement($index)[0] . ' <= ?', $filter['end']); + } + }); } } }); @@ -906,7 +1075,7 @@ public function addDateRangeFilter() if (! ((isset($filter['start']) && $filter['start'] != '') || (isset($filter['end']) && $filter['end'] != ''))) { break; } - $query->whereBetween($this->getColumnField($index)[0], [ + $query->whereBetween($this->getColumnFilterStatement($index)[0], [ isset($filter['start']) && $filter['start'] != '' ? $filter['start'] : '0000-00-00', isset($filter['end']) && $filter['end'] != '' ? $filter['end'] : now()->format('Y-m-d'), ]); @@ -929,11 +1098,11 @@ public function addTimeRangeFilter() if ($end < $start) { $query->where(function ($subQuery) use ($index, $start, $end) { - $subQuery->whereBetween($this->getColumnField($index)[0], [$start, '23:59']) - ->orWhereBetween($this->getColumnField($index)[0], ['00:00', $end]); + $subQuery->whereBetween($this->getColumnFilterStatement($index)[0], [$start, '23:59']) + ->orWhereBetween($this->getColumnFilterStatement($index)[0], ['00:00', $end]); }); } else { - $query->whereBetween($this->getColumnField($index)[0], [$start, $end]); + $query->whereBetween($this->getColumnFilterStatement($index)[0], [$start, $end]); } } }); @@ -978,7 +1147,6 @@ public function mapCallbacks($paginatedCollection, $export = false) $paginatedCollection->collect()->map(function ($row, $i) use ($export) { foreach ($row as $name => $value) { if ($export && isset($this->export_callbacks[$name])) { - // dd($this->callbacks, $this->export_callbacks, $value, $row); $values = Str::contains($value, static::SEPARATOR) ? explode(static::SEPARATOR, $value) : [$value, $row]; $row->$name = $this->export_callbacks[$name](...$values); } elseif (isset($this->editables[$name])) { @@ -986,7 +1154,7 @@ public function mapCallbacks($paginatedCollection, $export = false) 'value' => $value, 'table' => $this->builder()->getModel()->getTable(), 'column' => Str::after($name, '.'), - 'rowId' => $row->{$this->builder()->getModel()->getTable() . '.' . $this->builder()->getModel()->getKeyName()}, + 'rowId' => $row->{$this->builder()->getModel()->getTable() . '.' . $this->builder()->getModel()->getKeyName()} ?? $row->{$this->builder()->getModel()->getKeyName()}, ]); } elseif ($export && isset($this->export_callbacks[$name])) { $row->$name = $this->export_callbacks[$name]($value, $row); @@ -1049,8 +1217,7 @@ public function highlight($value, $string) $output = substr($value, stripos($value, $string), strlen($string)); if ($value instanceof View) { - return $value - ->with(['value' => str_ireplace($string, (string) view('datatables::highlight', ['slot' => $output]), $value->gatherData()['value'] ?? $value->gatherData()['slot'])]); + return $value->with(['value' => str_ireplace($string, (string) view('datatables::highlight', ['slot' => $output]), $value->gatherData()['value'] ?? $value->gatherData()['slot'])]); } return str_ireplace($string, (string) view('datatables::highlight', ['slot' => $output]), $value); @@ -1060,7 +1227,7 @@ public function render() { $this->emit('refreshDynamic'); - return view('datatables::datatable'); + return view('datatables::datatable')->layoutData(['title' => $this->title]); } public function export() @@ -1087,7 +1254,7 @@ public function getQuery($export = false) public function checkboxQuery() { - $select = $this->resolveCheckboxColumnName(collect($this->freshColumns)->firstWhere('type', 'checkbox')); + $this->resolveCheckboxColumnName(collect($this->freshColumns)->firstWhere('type', 'checkbox')); return $this->query->reorder()->get()->map(function ($row) { return (string) $row->checkbox_attribute; @@ -1103,4 +1270,19 @@ public function toggleSelectAll() } $this->forgetComputed(); } + + // public function saveQuery($name, $rules) + // { + // // Override this method with your own method for saving + // } + + // public function deleteQuery($id) + // { + // // Override this method with your own method for deleting + // } + + // public function getSavedQueries() + // { + // // Override this method with your own method for getting saved queries + // } } diff --git a/src/JsonColumn.php b/src/JsonColumn.php new file mode 100644 index 00000000..4b89d168 --- /dev/null +++ b/src/JsonColumn.php @@ -0,0 +1,18 @@ +callback = function ($value) { + return $value ? join(', ', json_decode($value)) : null; + }; + + return $this; + } +} diff --git a/src/LivewireDatatablesServiceProvider.php b/src/LivewireDatatablesServiceProvider.php index 26ade317..dba39a17 100644 --- a/src/LivewireDatatablesServiceProvider.php +++ b/src/LivewireDatatablesServiceProvider.php @@ -13,6 +13,7 @@ use Livewire\Livewire; use Mediconesystems\LivewireDatatables\Commands\MakeDatatableCommand; use Mediconesystems\LivewireDatatables\Http\Controllers\FileExportController; +use Mediconesystems\LivewireDatatables\Http\Livewire\ComplexQuery; use Mediconesystems\LivewireDatatables\Http\Livewire\LivewireDatatable; class LivewireDatatablesServiceProvider extends ServiceProvider @@ -20,6 +21,7 @@ class LivewireDatatablesServiceProvider extends ServiceProvider public function boot() { Livewire::component('datatable', LivewireDatatable::class); + Livewire::component('complex-query', ComplexQuery::class); $this->loadViewsFrom(__DIR__ . '/../resources/views/livewire/datatables', 'datatables'); $this->loadViewsFrom(__DIR__ . '/../resources/views/icons', 'icons'); @@ -31,6 +33,7 @@ public function boot() Blade::component('icons::chevron-down', 'icons.chevron-down'); Blade::component('icons::cog', 'icons.cog'); Blade::component('icons::trash', 'icons.trash'); + Blade::component('icons::copy', 'icons.copy'); Blade::component('icons::excel', 'icons.excel'); Blade::component('icons::x-circle', 'icons.x-circle'); Blade::component('icons::check-circle', 'icons.check-circle'); diff --git a/src/NumberColumn.php b/src/NumberColumn.php index 26a5ba58..c00ac698 100644 --- a/src/NumberColumn.php +++ b/src/NumberColumn.php @@ -5,4 +5,16 @@ class NumberColumn extends Column { public $type = 'number'; + public $round; + + public function round($places = 0) + { + $this->round = $places; + + $this->callback = function ($value) { + return round($value, $this->round); + }; + + return $this; + } } diff --git a/tests/ColumnTest.php b/tests/ColumnTest.php index f8bc2e13..ff380122 100644 --- a/tests/ColumnTest.php +++ b/tests/ColumnTest.php @@ -95,6 +95,7 @@ public function it_returns_an_array_from_column() 'unsortable' => null, 'exportCallback' => function () { }, + 'filterOn' => null, ], $subject); } @@ -132,6 +133,7 @@ public function it_returns_an_array_from_raw() 'width' => null, 'unsortable' => null, 'exportCallback' => null, + 'filterOn' => null, ], $subject); } @@ -168,6 +170,7 @@ public function it_returns_width_property_from_column() 'width' => '1em', 'unsortable' => null, 'exportCallback' => null, + 'filterOn' => null, ], $subject); } diff --git a/tests/LivewireDatatableQueryBuilderTest.php b/tests/LivewireDatatableQueryBuilderTest.php index b3f2d26a..6d839891 100644 --- a/tests/LivewireDatatableQueryBuilderTest.php +++ b/tests/LivewireDatatableQueryBuilderTest.php @@ -59,7 +59,7 @@ public function it_creates_a_where_query_for_a_has_one_column() $subject->mount(DummyModel::class, ['id', 'dummy_has_one.name']); $subject->doSelectFilter(1, 'dwight'); - $this->assertEquals('select "dummy_models"."id" as "id", "dummy_has_one_models"."name" as "dummy_has_one.name" from "dummy_models" left join "dummy_has_one_models" on "dummy_has_one_models"."dummy_model_id" = "dummy_models"."id" where ((("dummy_has_one_models"."name" = ?))) order by `id` desc', $subject->getQuery()->toSql()); + $this->assertEquals('select "dummy_models"."id" as "id", "dummy_has_one_models"."name" as "dummy_has_one.name" from "dummy_models" left join "dummy_has_one_models" on "dummy_has_one_models"."dummy_model_id" = "dummy_models"."id" where (((dummy_has_one_models.name = ?))) order by `id` desc', $subject->getQuery()->toSql()); $this->assertEquals(['dwight'], $subject->getQuery()->getBindings()); } From 8bcab841322a8077da40cc01efe44e6567ebb597 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 23 Aug 2021 18:00:32 +0100 Subject: [PATCH 070/217] replace strtolower with mb_strtolower --- src/Column.php | 2 -- src/Http/Livewire/LivewireDatatable.php | 31 +++++++++++------------ src/LivewireDatatablesServiceProvider.php | 4 +-- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/Column.php b/src/Column.php index efe3b731..70da13f7 100644 --- a/src/Column.php +++ b/src/Column.php @@ -348,12 +348,10 @@ public function addParams($params) public function width($width) { - // only numbers? add the default px unit if (preg_match('/^\\d*\\.?\\d+$/i', $width) === 1) { $width .= 'px'; } - // check if the $with contains invalid units if (preg_match('/^(\\d*\\.?\\d+)\\s?(cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vmin|vmax|%+)$/i', $width) === 0) { return $this; } diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 9967fcf5..0a2a70d2 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -116,7 +116,6 @@ public function mount( $this->initialiseSort(); - // check if there are sorting vars in the session $key = Str::snake(Str::afterLast(get_called_class(), '\\')); $this->sort = session()->get($key . $this->name . '_sort', $this->sort); $this->direction = session()->get($key . $this->name . '_direction', $this->direction); @@ -948,14 +947,14 @@ public function addSelectFilters() if ($this->freshColumns[$index]['type'] === 'json') { $query->where(function ($query) use ($value, $index) { foreach ($this->getColumnFilterStatement($index) as $column) { - $query->whereRaw('LOWER(' . $column . ') like ?', [strtolower("%$value%")]); + $query->whereRaw('LOWER(' . $column . ') like ?', [mb_strtolower("%$value%")]); } }); } else { $query->orWhere(function ($query) use ($value, $index) { foreach ($this->getColumnFilterStatement($index) as $column) { - if (Str::contains(strtolower($column), 'concat')) { - $query->orWhereRaw('LOWER(' . $column . ') like ?', [strtolower("%$value%")]); + if (Str::contains(mb_strtolower($column), 'concat')) { + $query->orWhereRaw('LOWER(' . $column . ') like ?', [mb_strtolower("%$value%")]); } else { $query->orWhereRaw($column . ' = ?', $value); } @@ -1271,18 +1270,18 @@ public function toggleSelectAll() $this->forgetComputed(); } - // public function saveQuery($name, $rules) - // { - // // Override this method with your own method for saving - // } + public function saveQuery($name, $rules) + { + // Override this method with your own method for saving + } - // public function deleteQuery($id) - // { - // // Override this method with your own method for deleting - // } + public function deleteQuery($id) + { + // Override this method with your own method for deleting + } - // public function getSavedQueries() - // { - // // Override this method with your own method for getting saved queries - // } + public function getSavedQueries() + { + // Override this method with your own method for getting saved queries + } } diff --git a/src/LivewireDatatablesServiceProvider.php b/src/LivewireDatatablesServiceProvider.php index dba39a17..8fcaa3f2 100644 --- a/src/LivewireDatatablesServiceProvider.php +++ b/src/LivewireDatatablesServiceProvider.php @@ -106,14 +106,14 @@ public function loadEloquentBuilderMacros() $query->callScope($constraints); $query = $query->mergeConstraintsFrom($relation->getQuery())->toBase(); - // dd($relations, $column, $aggregate); + if (count($query->columns) > 1) { $query->columns = [$query->columns[0]]; } $columnAlias = new Expression('`' . ($alias ?? collect([$relations, $column])->filter()->flatten()->join('.')) . '`'); $this->selectSub($query, $columnAlias); } - // $this->groupIfNotGrouped($this->getModel()->getTable() . '.' . $this->getModel()->getKeyName()); + return $this; }); From 6e812ff72506a8c3803dab2cd17272f4cc575347 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Tue, 24 Aug 2021 16:51:57 +0100 Subject: [PATCH 071/217] remove prefetch from column sorting --- .../views/livewire/datatables/header-inline-hide.blade.php | 2 +- resources/views/livewire/datatables/header-no-hide.blade.php | 2 +- tests/LivewireDatatableTemplateTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/views/livewire/datatables/header-inline-hide.blade.php b/resources/views/livewire/datatables/header-inline-hide.blade.php index 0a9c53b9..c4088562 100644 --- a/resources/views/livewire/datatables/header-inline-hide.blade.php +++ b/resources/views/livewire/datatables/header-inline-hide.blade.php @@ -20,7 +20,7 @@ class="@if($column['hidden']) hidden @else relative h-12 overflow-hidden align-t {{ str_replace('_', ' ', $column['label']) }}
@else -
@else - Date: Tue, 24 Aug 2021 17:56:35 +0100 Subject: [PATCH 073/217] filterOn readme --- README.md | 2 +- src/Http/Livewire/LivewireDatatable.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eaff2f40..ef292ea0 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ class ComplexDemoTable extends LivewireDatatable |**defaultSort**|[*String* $direction (default: 'desc')]|Marks the column as the default search column|```Column::name('name')->defaultSort('asc')```| |**searchable**| |Includes the column in the global search|```Column::name('name')->searchable()```| |**filterable**|[*Array* $options], [*String* $filterScope]|Adds a filter to the column, according to Column type. If an array of options is passed it wil be used to populate a select input. If the column is a scope column then the name of the filter scope must also be passed|```Column::name('allegiance')->filterable(['Rebellion', 'Empire'])```| -|**filterOn**|*String* $statement|Allows you to specify a column name or sql statement upon which to perform the filter. Useful if using a callback to modify |```Column::name('allegiance')->filterable(['Rebellion', 'Empire'])```| +|**filterOn**|*String/Array* $statement|Allows you to specify a column name or sql statement upon which to perform the filter (must use SQL syntax, not Eloquent eg. ```'users.name'``` instead of ```'user.name'```). Useful if using a callback to modify the displayed values. Can pass a single string or array of strings which will be combined with ```OR```|```Column::callback(['name', 'allegiance'], function ($name, $allegiance) { return "$name is allied to $allegiance"; })->filterable(['Rebellion', 'Empire'])->filterOn('users.allegiance')```| |**view**|*String* $viewName| Passes the column value, whole row of values, and any additional parameters to a view template | _(see below)_| |**editable**| | Marks the column as editable | _(see below)_| |**alignCenter**| | Center-aligns column header and contents |```Column::delete()->alignCenter()```| diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 0a2a70d2..9d594e52 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -617,7 +617,7 @@ public function getColumnFilterStatement($index) } if ($this->freshColumns[$index]['filterOn']) { - return [$this->freshColumns[$index]['filterOn']]; + return Arr::wrap($this->freshColumns[$index]['filterOn']); } if ($this->freshColumns[$index]['scope']) { From 53076136c345aa876a1be7dbb483a3d89887a97c Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Tue, 24 Aug 2021 17:57:45 +0100 Subject: [PATCH 074/217] Change default end date of date filter --- src/Http/Livewire/LivewireDatatable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 9d594e52..b6a546f6 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1076,7 +1076,7 @@ public function addDateRangeFilter() } $query->whereBetween($this->getColumnFilterStatement($index)[0], [ isset($filter['start']) && $filter['start'] != '' ? $filter['start'] : '0000-00-00', - isset($filter['end']) && $filter['end'] != '' ? $filter['end'] : now()->format('Y-m-d'), + isset($filter['end']) && $filter['end'] != '' ? $filter['end'] : '9999-12-31', ]); } }); From e1920e5184220992a3a36952899bb92fd92be493 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Tue, 24 Aug 2021 18:04:42 +0100 Subject: [PATCH 075/217] fix clearAllFilters for date and time filters --- src/Http/Livewire/LivewireDatatable.php | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index b6a546f6..07e83860 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -552,31 +552,10 @@ public function removeSelectFilter($column, $key = null) $this->page = 1; } - public function clearDateFilter() - { - $this->dates = null; - $this->page = 1; - } - - public function clearTimeFilter() - { - $this->times = null; - $this->page = 1; - } - - public function clearFilters() - { - $this->activeSelectFilters = []; - $this->activeBooleanFilters = []; - $this->activeTextFilters = []; - $this->activeNumberFilters = []; - $this->page = 1; - } - public function clearAllFilters() { - $this->clearDateFilter(); - $this->clearTimeFilter(); + $this->activeDateFilters = []; + $this->activeTimeFilters = []; $this->activeSelectFilters = []; $this->activeBooleanFilters = []; $this->activeTextFilters = []; From 505fc4292418fccfe4d9cc885faf2c39e8a67339 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Tue, 24 Aug 2021 18:27:49 +0100 Subject: [PATCH 076/217] export now respects checkbox selection --- src/Http/Livewire/LivewireDatatable.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 07e83860..b7f3bf0d 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1212,7 +1212,12 @@ public function export() { $this->forgetComputed(); - $results = $this->mapCallbacks($this->getQuery()->get(), true)->map(function ($item) { + $results = $this->mapCallbacks( + $this->getQuery()->when(count($this->selected), function ($query) { + return $query->havingRaw('checkbox_attribute IN (' . implode(',', $this->selected) . ')'); + })->get(), + true + )->map(function ($item) { return collect($this->columns)->reject(function ($value, $key) { return $value['preventExport'] == true || $value['hidden'] == true; })->mapWithKeys(function ($value, $key) use ($item) { From 351dfa49bffba76a79cf1c72732a1d0c907db40a Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Tue, 24 Aug 2021 19:58:10 +0100 Subject: [PATCH 077/217] fix sort --- src/Http/Livewire/LivewireDatatable.php | 60 ++++++++++++++++--------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index b7f3bf0d..5f1936ba 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -60,6 +60,7 @@ class LivewireDatatable extends Component public $title; public $name; public $userFilter; + public $persistSort = true; protected $query; protected $listeners = ['refreshLivewireDatatable', 'complexQuery', 'saveQuery', 'deleteQuery']; @@ -116,9 +117,6 @@ public function mount( $this->initialiseSort(); - $key = Str::snake(Str::afterLast(get_called_class(), '\\')); - $this->sort = session()->get($key . $this->name . '_sort', $this->sort); - $this->direction = session()->get($key . $this->name . '_direction', $this->direction); $this->perPage = $perPage ?? $this->perPage ?? config('livewire-datatables.default_per_page', 10); } @@ -388,13 +386,48 @@ public function getFreshColumnsProperty() return $columns; } + public function sessionStorageKey() + { + return Str::snake(Str::afterLast(get_called_class(), '\\')); + } + + public function getSessionStoredSort() + { + $this->sort = session()->get($this->sessionStorageKey() . $this->name . '_sort', $this->sort); + $this->direction = session()->get($this->sessionStorageKey() . $this->name . '_direction', $this->direction); + } + + public function setSessionStoredSort() + { + session()->put([$this->sessionStorageKey() . $this->name . '_sort' => $this->sort, $this->sessionStorageKey() . $this->name . '_direction' => $this->direction]); + } + + public function sort($index) + { + if ($this->sort === (int) $index) { + $this->direction = ! $this->direction; + } else { + $this->sort = (int) $index; + } + $this->page = 1; + + if ($this->persistSort) { + $this->setSessionStoredSort(); + } + } + public function initialiseSort() { $this->sort = $this->defaultSort() - ? $this->defaultSort()['key'] - : collect($this->freshColumns)->reject(function ($column) { - return $column['type'] === 'checkbox' || $column['hidden']; - })->keys()->first(); + ? $this->defaultSort()['key'] + : collect($this->freshColumns)->reject(function ($column) { + return $column['type'] === 'checkbox' || $column['hidden']; + })->keys()->first(); + + if ($this->persistSort) { + $this->getSessionStoredSort(); + } + $this->direction = $this->defaultSort() && $this->defaultSort()['direction'] === 'asc'; } @@ -450,19 +483,6 @@ public function refreshLivewireDatatable() $this->page = 1; } - public function sort($index) - { - if ($this->sort === (int) $index) { - $this->direction = ! $this->direction; - } else { - $this->sort = (int) $index; - } - $this->page = 1; - - $key = Str::snake(Str::afterLast(get_called_class(), '\\')); - session()->put([$key . $this->name . '_sort' => $this->sort, $key . $this->name . '_direction' => $this->direction]); - } - public function toggle($index) { if ($this->sort == $index) { From 23b66e471dd43215b15cfe84feb1fed5e62a80b1 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Wed, 25 Aug 2021 11:27:20 +0100 Subject: [PATCH 078/217] dynamic row and cell classes --- README.md | 17 ++++++++++++++++- .../livewire/datatables/datatable.blade.php | 19 ++++++++++--------- src/Http/Livewire/LivewireDatatable.php | 17 +++++++++++++++++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ef292ea0..3f3206a5 100644 --- a/README.md +++ b/README.md @@ -417,9 +417,24 @@ class TableWithSaving extends Livewire Datatable ``` -## Styling +# Styling I know it's not cool to provide a package with tons of opionated markup and styling. Most other packages seem to have gone down the route of passing optional classes around as arguments or config variables. My take is that because this is just blade with tailwind, you can publish the templates and do whatever you like to them - it should be obvious where the Livewire and Alpine moving parts are. +There are methods for applying styles to rows and cells. ```rowClasses``` receives the ```$row``` and the [laravel loop variable](https://laravel.com/docs/8.x/blade#the-loop-variable) as parameters. ```cellClasses``` receives the ```$row``` and ```$column``` + +For example: +```php +public function rowClasses($row, $loop) +{ + return 'divide-x divide-gray-100 text-sm text-gray-900 ' . ($this->rowIsSelected($row) ? 'bg-yellow-100' : ($row->{'car.model'} === 'Ferrari' ? 'bg-red-500' : ($loop->even ? 'bg-gray-100' : 'bg-gray-50'))); +} + +public function cellClasses($row, $column) +{ + return 'text-sm ' . ($this->rowIsSelected($row) ? ' text-gray-900' : ($row->{'car.model'} === 'Ferrari' ? ' text-white' : ' text-gray-900')); +} +``` + You could also override the render method in your table's class to provide different templates for different tables. diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index 560d0231..5fc073a8 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -65,8 +65,8 @@
@endif -
-
+
+
@unless($this->hideHeader)
@@ -75,7 +75,7 @@ @include('datatables::header-inline-hide', ['column' => $column, 'sort' => $sort]) @elseif($column['type'] === 'checkbox') @unless($column['hidden']) -
+
{{ count($selected) }}
@@ -118,18 +118,18 @@ @endforeach
@endif - @forelse($this->results as $result) -
+ @forelse($this->results as $row) +
@foreach($this->columns as $column) @if($column['hidden']) @if($hideable === 'inline')
@endif @elseif($column['type'] === 'checkbox') - @include('datatables::checkbox', ['value' => $result->checkbox_attribute]) + @include('datatables::checkbox', ['value' => $row->checkbox_attribute]) @else -
- {!! $result->{$column['name']} !!} +
+ {!! $row->{$column['name']} !!}
@endif @endforeach @@ -144,7 +144,7 @@
@unless($this->hidePagination) -
+
{{-- check if there is any data --}} @if(count($this->results)) @@ -188,4 +188,5 @@ @include($afterTableSlot)
@endif +
diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 5f1936ba..d94cda7b 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1274,6 +1274,11 @@ public function toggleSelectAll() $this->forgetComputed(); } + public function rowIsSelected($row) + { + return isset($row->checkbox_attribute) && in_array($row->checkbox_attribute, $this->selected); + } + public function saveQuery($name, $rules) { // Override this method with your own method for saving @@ -1288,4 +1293,16 @@ public function getSavedQueries() { // Override this method with your own method for getting saved queries } + + public function rowClasses($row, $loop) + { + // Override this method with your own method for adding classes to a row + return 'divide-x divide-gray-100 text-sm text-gray-900 ' . ($this->rowIsSelected($row) ? 'bg-yellow-100' : ($loop->even ? 'bg-gray-100' : 'bg-gray-50')); + } + + public function cellClasses($row, $column) + { + // Override this method with your own method for adding classes to a cell + return 'text-sm text-gray-900'; + } } From 5888c133683ff4a1d0b557495907aec225fe4acf Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 30 Aug 2021 20:45:48 +0100 Subject: [PATCH 079/217] fix persist bug --- resources/views/livewire/datatables/complex-query.blade.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/views/livewire/datatables/complex-query.blade.php b/resources/views/livewire/datatables/complex-query.blade.php index 3d7b9cd3..57542edf 100644 --- a/resources/views/livewire/datatables/complex-query.blade.php +++ b/resources/views/livewire/datatables/complex-query.blade.php @@ -1,5 +1,5 @@ -
this.rules = rules) if (this.rules && this.rules !== '') { @@ -7,7 +7,7 @@ $wire.runQuery() } } - }" @endif class="" + }" class="" >
Query Builder From d42a1c789ead11a6fcf00b94658829879bc368f9 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 30 Aug 2021 20:45:56 +0100 Subject: [PATCH 080/217] right align number columns --- src/NumberColumn.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NumberColumn.php b/src/NumberColumn.php index c00ac698..e37dd442 100644 --- a/src/NumberColumn.php +++ b/src/NumberColumn.php @@ -5,6 +5,7 @@ class NumberColumn extends Column { public $type = 'number'; + public $align = 'right'; public $round; public function round($places = 0) From 5bc4d1b26872cbe3e45a02d5aec69a42581ce34c Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Wed, 8 Sep 2021 17:56:26 +0200 Subject: [PATCH 081/217] introduce the ability to set a specific direction in sort() method, introduce applyToTable(), introduce resetTable() (#272) * introduce the ability to set a specific direction in sort() method * introduce 'apply' listener to allow to control the datatable from outside * s/apply/applyToTable * introduce resetTable() * introduce ability to set hidden columns via external livewire component by using Co-authored-by: Herbert Maschke --- src/Http/Livewire/LivewireDatatable.php | 83 ++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index d94cda7b..bd9055a9 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -63,7 +63,7 @@ class LivewireDatatable extends Component public $persistSort = true; protected $query; - protected $listeners = ['refreshLivewireDatatable', 'complexQuery', 'saveQuery', 'deleteQuery']; + protected $listeners = ['refreshLivewireDatatable', 'complexQuery', 'saveQuery', 'deleteQuery', 'applyToTable', 'resetTable']; protected $operators = [ '=' => '=', @@ -84,6 +84,59 @@ class LivewireDatatable extends Component 'does not include' => '<>', ]; + /** + * This events allows to control the options of the datatable from foreign livewire components + * by using $emit. + * + * @example $this->emit('applyToTable', ['perPage' => 25]); // in any other livewire component on the same page + */ + public function applyToTable($options) + { + if (isset($options['sort'])) { + $this->sort($options['sort'], $options['direction'] ?? null); + } + + if (isset($options['hiddenColumns']) && is_array($options['hiddenColumns'])) { + // first display all columns, + foreach ($this->columns as $key => $column) { + $this->columns[$key]['hidden'] = false; + } + + // then hide all columns that should be hidden: + foreach ($options['hiddenColumns'] as $columnToHide) { + foreach ($this->columns as $key => $column) { + if ($column['name'] === $columnToHide) { + $this->columns[$key]['hidden'] = true; + } + } + } + } + + foreach (['perPage', 'search', 'activeSelectFilters', 'activeDateFilters', 'activeTimeFilters', 'activeBooleanFilters', 'activeTextFilters', 'activeNumberFilters', 'hide', 'selected'] as $property) { + if (isset($options[$property])) { + $this->$property = $options[$property]; + } + } + } + + /** + * Call to clear all searches, filters, selections, return to page 1 and set perPage to default. + */ + public function resetTable() + { + $this->perPage = config('livewire-datatables.default_per_page', 10); + $this->search = null; + $this->page = 1; + $this->activeSelectFilters = []; + $this->activeDateFilters = []; + $this->activeTimeFilters = []; + $this->activeTextFilters = []; + $this->activeBooleanFilters = []; + $this->activeNumberFilters = []; + $this->hide = null; + $this->selected = []; + } + public function updatedSearch() { $this->page = 1; @@ -483,6 +536,34 @@ public function refreshLivewireDatatable() $this->page = 1; } + /** + * Order the table by a given column index starting from 0. + * + * @param int $index which column to sort by + * @param string|null $direction needs to be 'asc' or 'desc'. set to null to toggle the current direction. + * @return void + */ + public function sort($index, $direction = null) + { + if (! in_array($direction, [null, 'asc', 'desc'])) { + throw new \Exception("Invalid direction $direction given in sort() method. Allowed values: asc, desc."); + } + + if ($this->sort === (int) $index) { + if ($direction === null) { // toggle direction + $this->direction = ! $this->direction; + } else { + $this->direction = $direction === 'desc' ? false : true; + } + } else { + $this->sort = (int) $index; + } + $this->page = 1; + + $key = Str::snake(Str::afterLast(get_called_class(), '\\')); + session()->put([$key . $this->name . '_sort' => $this->sort, $key . $this->name . '_direction' => $this->direction]); + } + public function toggle($index) { if ($this->sort == $index) { From 4250025cdd9e0c227406d6f1eb9f2445a0342664 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Wed, 8 Sep 2021 16:57:40 +0100 Subject: [PATCH 082/217] Apply fixes from StyleCI (#276) Co-authored-by: Mark Salmon --- src/Http/Livewire/LivewireDatatable.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index bd9055a9..2871b23b 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -539,8 +539,8 @@ public function refreshLivewireDatatable() /** * Order the table by a given column index starting from 0. * - * @param int $index which column to sort by - * @param string|null $direction needs to be 'asc' or 'desc'. set to null to toggle the current direction. + * @param int $index which column to sort by + * @param string|null $direction needs to be 'asc' or 'desc'. set to null to toggle the current direction. * @return void */ public function sort($index, $direction = null) From 0fd2ca9b7b943d5e35fa735ceeb2fa8cb1e8c18d Mon Sep 17 00:00:00 2001 From: Mohammad Salehi Date: Wed, 8 Sep 2021 20:35:45 +0430 Subject: [PATCH 083/217] Fixed bug #267 (#269) * Fixed bug #267 * Fixed some styleci errors * fixed some styleci errors * fixed some styleci errors --- src/Http/Livewire/LivewireDatatable.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 2871b23b..37bd426b 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1291,8 +1291,18 @@ public static function highlightString(string $originalString, string $searching return $stringWithHighlightedSubstring; } + public function isRtl($value) + { + $rtlChar = '/[\x{0590}-\x{083F}]|[\x{08A0}-\x{08FF}]|[\x{FB1D}-\x{FDFF}]|[\x{FE70}-\x{FEFF}]/u'; + + return preg_match($rtlChar, $value) != 0; + } + public function highlight($value, $string) { + if ($this->isRtl($value)) { + $output = $string; + } $output = substr($value, stripos($value, $string), strlen($string)); if ($value instanceof View) { From e1f58905b4fb77121e377171bb647daf96f1a123 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Wed, 8 Sep 2021 17:06:09 +0100 Subject: [PATCH 084/217] Apply fixes from StyleCI (#277) Co-authored-by: Mark Salmon --- src/Http/Livewire/LivewireDatatable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 37bd426b..29ff790f 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1294,7 +1294,7 @@ public static function highlightString(string $originalString, string $searching public function isRtl($value) { $rtlChar = '/[\x{0590}-\x{083F}]|[\x{08A0}-\x{08FF}]|[\x{FB1D}-\x{FDFF}]|[\x{FE70}-\x{FEFF}]/u'; - + return preg_match($rtlChar, $value) != 0; } From 805726fc817127ae425043f2851377a70346aad4 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Thu, 9 Sep 2021 10:39:29 +0100 Subject: [PATCH 085/217] update livewire dependency --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 74b16360..963137f4 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "require": { "php": "^7.2.5|^8.0", "illuminate/support": "^7.0|^8.0", - "livewire/livewire": "^1.2|^2.0", + "livewire/livewire": "^2.4.4", "maatwebsite/excel": "^3.1" }, "require-dev": { From ddb91bb58d9e459115d405f096cd53ec778fc2ef Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Thu, 9 Sep 2021 11:41:25 +0200 Subject: [PATCH 086/217] introduce ability to persist filters, perpage and hidden columns in session (#274) * introduce ability to persist filters in session * introduce ability to persist perpage in session * introduce ability to persist hidden columns in session * use UK, not US spelling (s/initialize/initialise) Co-authored-by: Herbert Maschke --- src/Http/Livewire/LivewireDatatable.php | 122 ++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 6 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 29ff790f..e6cb6c62 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -56,11 +56,14 @@ class LivewireDatatable extends Component public $afterTableSlot; public $complex; public $complexQuery; - public $persistComplexQuery; public $title; public $name; public $userFilter; + public $persistComplexQuery; + public $persistHiddenColumns = true; public $persistSort = true; + public $persistPerPage = true; + public $persistFilters = true; protected $query; protected $listeners = ['refreshLivewireDatatable', 'complexQuery', 'saveQuery', 'deleteQuery', 'applyToTable', 'resetTable']; @@ -169,8 +172,9 @@ public function mount( $this->columns = $this->getViewColumns(); $this->initialiseSort(); - - $this->perPage = $perPage ?? $this->perPage ?? config('livewire-datatables.default_per_page', 10); + $this->initialiseHiddenColumns(); + $this->initialiseFilters(); + $this->initialisePerPage(); } public function columns() @@ -446,15 +450,50 @@ public function sessionStorageKey() public function getSessionStoredSort() { + if (! $this->persistSort) { + return; + } + $this->sort = session()->get($this->sessionStorageKey() . $this->name . '_sort', $this->sort); $this->direction = session()->get($this->sessionStorageKey() . $this->name . '_direction', $this->direction); } + public function getSessionStoredPerPage() + { + if (! $this->persistPerPage) { + return; + } + + $this->perPage = session()->get($this->sessionStorageKey() . $this->name . '_perpage', $this->perPage); + } + public function setSessionStoredSort() { + if (! $this->persistSort) { + return; + } + session()->put([$this->sessionStorageKey() . $this->name . '_sort' => $this->sort, $this->sessionStorageKey() . $this->name . '_direction' => $this->direction]); } + public function setSessionStoredFilters() + { + if (! $this->persistFilters) { + return; + } + + session()->put([ + $this->sessionStorageKey() . $this->name . '_filter' => [ + 'text' => $this->activeTextFilters, + 'boolean' => $this->activeBooleanFilters, + 'select' => $this->activeSelectFilters, + 'date' => $this->activeDateFilters, + 'time' => $this->activeTimeFilters, + 'number' => $this->activeNumberFilters, + ], + ]); + } + public function sort($index) { if ($this->sort === (int) $index) { @@ -477,13 +516,53 @@ public function initialiseSort() return $column['type'] === 'checkbox' || $column['hidden']; })->keys()->first(); - if ($this->persistSort) { - $this->getSessionStoredSort(); - } + $this->getSessionStoredSort(); $this->direction = $this->defaultSort() && $this->defaultSort()['direction'] === 'asc'; } + public function initialiseHiddenColumns() + { + if (! $this->persistHiddenColumns) { + return; + } + + if (session()->has($this->sessionStorageKey() . $this->name . '_hidden_columns')) { + foreach (session()->get($this->sessionStorageKey() . $this->name . '_hidden_columns') as $name) { + foreach ($this->columns as $key => $column) { + if ($column['name'] === $name) { + $this->columns[$key]['hidden'] = 1; + } + } + } + } + } + + public function initialisePerPage() + { + $this->getSessionStoredPerPage(); + + if (! $this->perPage) { + $this->perPage = $this->perPage ?? config('livewire-datatables.default_per_page', 10); + } + } + + public function initialiseFilters() + { + if (! $this->persistFilters) { + return; + } + + $filters = session()->get($this->sessionStorageKey() . $this->name . '_filter'); + + $this->activeBooleanFilters = $filters['boolean'] ?? []; + $this->activeSelect = $filters['select'] ?? []; + $this->activeTextFilters = $filters['text'] ?? []; + $this->activeDateFilters = $filters['date'] ?? []; + $this->activeTimeFilters = $filters['time'] ?? []; + $this->activeNumberFilters = $filters['number'] ?? []; + } + public function defaultSort() { $columnIndex = collect($this->freshColumns)->search(function ($column) { @@ -575,18 +654,32 @@ public function toggle($index) } $this->columns[$index]['hidden'] = ! $this->columns[$index]['hidden']; + + if ($this->persistHiddenColumns) { + $hidden = []; + + foreach ($this->columns as $column) { + if ($column['hidden']) { + $hidden[] = $column['name']; + } + } + + session()->put([$this->sessionStorageKey() . $this->name . '_hidden_columns' => $hidden]); + } } public function doBooleanFilter($index, $value) { $this->activeBooleanFilters[$index] = $value; $this->page = 1; + $this->setSessionStoredFilters(); } public function doSelectFilter($index, $value) { $this->activeSelectFilters[$index][] = $value; $this->page = 1; + $this->setSessionStoredFilters(); } public function doTextFilter($index, $value) @@ -596,30 +689,35 @@ public function doTextFilter($index, $value) } $this->page = 1; + $this->setSessionStoredFilters(); } public function doDateFilterStart($index, $start) { $this->activeDateFilters[$index]['start'] = $start; $this->page = 1; + $this->setSessionStoredFilters(); } public function doDateFilterEnd($index, $end) { $this->activeDateFilters[$index]['end'] = $end; $this->page = 1; + $this->setSessionStoredFilters(); } public function doTimeFilterStart($index, $start) { $this->activeTimeFilters[$index]['start'] = $start; $this->page = 1; + $this->setSessionStoredFilters(); } public function doTimeFilterEnd($index, $end) { $this->activeTimeFilters[$index]['end'] = $end; $this->page = 1; + $this->setSessionStoredFilters(); } public function doNumberFilterStart($index, $start) @@ -627,6 +725,7 @@ public function doNumberFilterStart($index, $start) $this->activeNumberFilters[$index]['start'] = $start ? (int) $start : null; $this->clearEmptyNumberFilter($index); $this->page = 1; + $this->setSessionStoredFilters(); } public function doNumberFilterEnd($index, $end) @@ -634,6 +733,7 @@ public function doNumberFilterEnd($index, $end) $this->activeNumberFilters[$index]['end'] = ($end !== '') ? (int) $end : null; $this->clearEmptyNumberFilter($index); $this->page = 1; + $this->setSessionStoredFilters(); } public function clearEmptyNumberFilter($index) @@ -642,6 +742,7 @@ public function clearEmptyNumberFilter($index) $this->removeNumberFilter($index); } $this->page = 1; + $this->setSessionStoredFilters(); } public function removeSelectFilter($column, $key = null) @@ -651,6 +752,7 @@ public function removeSelectFilter($column, $key = null) unset($this->activeSelectFilters[$column]); } $this->page = 1; + $this->setSessionStoredFilters(); } public function clearAllFilters() @@ -664,6 +766,7 @@ public function clearAllFilters() $this->complexQuery = null; $this->userFilter = null; $this->page = 1; + $this->setSessionStoredFilters(); $this->emitTo('complex-query', 'resetQuery'); } @@ -671,6 +774,7 @@ public function clearAllFilters() public function removeBooleanFilter($column) { unset($this->activeBooleanFilters[$column]); + $this->setSessionStoredFilters(); } public function removeTextFilter($column, $key = null) @@ -683,11 +787,13 @@ public function removeTextFilter($column, $key = null) } else { unset($this->activeTextFilters[$column]); } + $this->setSessionStoredFilters(); } public function removeNumberFilter($column) { unset($this->activeNumberFilters[$column]); + $this->setSessionStoredFilters(); } public function getColumnFilterStatement($index) @@ -1316,6 +1422,10 @@ public function render() { $this->emit('refreshDynamic'); + if ($this->persistPerPage) { + session()->put([$this->sessionStorageKey() . $this->name . '_perpage' => $this->perPage]); + } + return view('datatables::datatable')->layoutData(['title' => $this->title]); } From 44eee2274ad795c2f459f3b9d40edcb8c77fe4dc Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Thu, 9 Sep 2021 11:16:02 +0100 Subject: [PATCH 087/217] fix persist --- src/Http/Livewire/LivewireDatatable.php | 33 ++++--------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index e6cb6c62..adae9f70 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -494,20 +494,6 @@ public function setSessionStoredFilters() ]); } - public function sort($index) - { - if ($this->sort === (int) $index) { - $this->direction = ! $this->direction; - } else { - $this->sort = (int) $index; - } - $this->page = 1; - - if ($this->persistSort) { - $this->setSessionStoredSort(); - } - } - public function initialiseSort() { $this->sort = $this->defaultSort() @@ -528,13 +514,10 @@ public function initialiseHiddenColumns() } if (session()->has($this->sessionStorageKey() . $this->name . '_hidden_columns')) { - foreach (session()->get($this->sessionStorageKey() . $this->name . '_hidden_columns') as $name) { - foreach ($this->columns as $key => $column) { - if ($column['name'] === $name) { - $this->columns[$key]['hidden'] = 1; - } - } - } + $this->columns = collect($this->columns)->map(function ($column, $index) { + $column['hidden'] = in_array($index, session()->get($this->sessionStorageKey() . $this->name . '_hidden_columns')); + return $column; + })->toArray(); } } @@ -656,13 +639,7 @@ public function toggle($index) $this->columns[$index]['hidden'] = ! $this->columns[$index]['hidden']; if ($this->persistHiddenColumns) { - $hidden = []; - - foreach ($this->columns as $column) { - if ($column['hidden']) { - $hidden[] = $column['name']; - } - } + $hidden = collect($this->columns)->filter->hidden->keys()->toArray(); session()->put([$this->sessionStorageKey() . $this->name . '_hidden_columns' => $hidden]); } From cb71e6f23f886423ab524c10013245dff6c41438 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Thu, 9 Sep 2021 11:18:47 +0100 Subject: [PATCH 088/217] Apply fixes from StyleCI (#280) Co-authored-by: Mark Salmon --- src/Http/Livewire/LivewireDatatable.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index adae9f70..069aab56 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -516,6 +516,7 @@ public function initialiseHiddenColumns() if (session()->has($this->sessionStorageKey() . $this->name . '_hidden_columns')) { $this->columns = collect($this->columns)->map(function ($column, $index) { $column['hidden'] = in_array($index, session()->get($this->sessionStorageKey() . $this->name . '_hidden_columns')); + return $column; })->toArray(); } From 0163d62bd4a243d3d19a7838b451b945027f91c6 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Thu, 9 Sep 2021 13:57:12 +0100 Subject: [PATCH 089/217] wip --- resources/views/livewire/datatables/delete.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/livewire/datatables/delete.blade.php b/resources/views/livewire/datatables/delete.blade.php index 4f6cfdfe..56aff510 100644 --- a/resources/views/livewire/datatables/delete.blade.php +++ b/resources/views/livewire/datatables/delete.blade.php @@ -1,4 +1,4 @@ -
+
From ecd2d2920f2d94212e026d93541f07499c93ae3c Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Thu, 9 Sep 2021 14:24:03 +0100 Subject: [PATCH 090/217] editable field, update with primary key other than id (#282) * wip * Apply fixes from StyleCI (#281) Co-authored-by: Mark Salmon Co-authored-by: Mark Salmon --- .phpunit.result.cache | 1 + resources/views/livewire/datatables/editable.blade.php | 2 +- src/Http/Livewire/LivewireDatatable.php | 2 +- src/Traits/WithCallbacks.php | 7 ++++--- 4 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 .phpunit.result.cache diff --git a/.phpunit.result.cache b/.phpunit.result.cache new file mode 100644 index 00000000..5bbf4446 --- /dev/null +++ b/.phpunit.result.cache @@ -0,0 +1 @@ +{"version":1,"defects":[],"times":{"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_generate_an_array_of_columns_from_a_model":0.269,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #0":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #1":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #2":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #3":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #4":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #5":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #6":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #7":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_exclude_columns":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_include_columns":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_rename_columns":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_column_from_a_table_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_column_from_a_scope":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_delete_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #0":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #1":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #2":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #3":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #4":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_column":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_raw":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_width_property_from_column":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_mount_using_the_class":0.089,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_set_a_default_sort":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_show_and_hide_a_column":0.043,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_order_results":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_text":0.028,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_boolean":0.025,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_strings_as_a_boolean":0.028,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_selects":0.026,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_numbers":0.062,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_base_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_one_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_a_has_one_column":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_many_relation_columns":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_many_relation_column_with_specific_aggregate":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_has_many_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_belongs_to_relation_columns":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_belongs_to_relation_columns":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_belongs_to_many_relation_columns":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a__where_query_for_belongs_to_many_relation_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mount_from_the_default_template_with_a_model":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::the_header_can_be_hidden_with_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::the_pagination_bar_can_be_hidden_with_a_property":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_set_per_page_with_a_property":0.023,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_include_columns_from_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_exclude_columns_from_a_property":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_hide_columns_from_a_property":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mark_columns_for_date_format_from_a_property":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mark_columns_for_time_format_from_a_property":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_set_sort_from_a_property":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::component_is_created_by_make_command":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::dot_nested_component_is_created_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::forward_slash_nested_component_is_created_by_make_command":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::multiword_component_is_created_by_make_command":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::pascal_case_component_is_automatically_converted_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::snake_case_component_is_automatically_converted_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::snake_case_component_is_automatically_converted_by_make_command_on_nested_component":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::new_component_model_name_matches_option":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::a_component_is_not_created_with_a_reserved_class_name":0.012}} \ No newline at end of file diff --git a/resources/views/livewire/datatables/editable.blade.php b/resources/views/livewire/datatables/editable.blade.php index 8f57e3b9..925cc050 100644 --- a/resources/views/livewire/datatables/editable.blade.php +++ b/resources/views/livewire/datatables/editable.blade.php @@ -16,7 +16,7 @@ x-on:click="edit = true; $nextTick(() => { $refs.input.focus() })">{!! htmlspecialchars($value) !!}
diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 069aab56..838bb948 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1315,7 +1315,7 @@ public function mapCallbacks($paginatedCollection, $export = false) } elseif (isset($this->editables[$name])) { $row->$name = view('datatables::editable', [ 'value' => $value, - 'table' => $this->builder()->getModel()->getTable(), + 'key' => $this->builder()->getModel()->getQualifiedKeyName(), 'column' => Str::after($name, '.'), 'rowId' => $row->{$this->builder()->getModel()->getTable() . '.' . $this->builder()->getModel()->getKeyName()} ?? $row->{$this->builder()->getModel()->getKeyName()}, ]); diff --git a/src/Traits/WithCallbacks.php b/src/Traits/WithCallbacks.php index 24f7c509..5a72d64a 100644 --- a/src/Traits/WithCallbacks.php +++ b/src/Traits/WithCallbacks.php @@ -3,13 +3,14 @@ namespace Mediconesystems\LivewireDatatables\Traits; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Str; trait WithCallbacks { - public function edited($value, $table, $column, $rowId) + public function edited($value, $key, $column, $rowId) { - DB::table($table) - ->where('id', $rowId) + DB::table(Str::before($key, '.')) + ->where(Str::after($key, '.'), $rowId) ->update([$column => $value]); $this->emit('fieldEdited', $rowId); From d5b6f389e3c67cf173182a81ea77b57f5dc9fc4f Mon Sep 17 00:00:00 2001 From: Regan Date: Thu, 16 Sep 2021 12:37:15 +0100 Subject: [PATCH 091/217] Fixed typo: Updated variable use of '->activeSelect' to '->activeSelectFilters' (#287) Co-authored-by: Regan --- src/Http/Livewire/LivewireDatatable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 838bb948..a408762e 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -540,7 +540,7 @@ public function initialiseFilters() $filters = session()->get($this->sessionStorageKey() . $this->name . '_filter'); $this->activeBooleanFilters = $filters['boolean'] ?? []; - $this->activeSelect = $filters['select'] ?? []; + $this->activeSelectFilters = $filters['select'] ?? []; $this->activeTextFilters = $filters['text'] ?? []; $this->activeDateFilters = $filters['date'] ?? []; $this->activeTimeFilters = $filters['time'] ?? []; From 0d66457b243cc3815c38ab74daf7b008c24c6ac5 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Thu, 16 Sep 2021 13:38:29 +0200 Subject: [PATCH 092/217] introduce the ability to define which columns the user should be able to hide (#286) Co-authored-by: Herbert Maschke --- README.md | 3 +++ .../views/livewire/datatables/datatable.blade.php | 10 ++++++---- .../livewire/datatables/header-inline-hide.blade.php | 11 +++++++---- src/Column.php | 8 ++++++++ src/Http/Livewire/LivewireDatatable.php | 3 ++- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 3f3206a5..15139573 100644 --- a/README.md +++ b/README.md @@ -140,11 +140,13 @@ class ComplexDemoTable extends LivewireDatatable Column::name('name') ->defaultSort('asc') ->searchable() + ->hideable() ->filterable(), Column::name('planet.name') ->label('Planet') ->searchable() + ->hideable() ->filterable($this->planets), DateColumn::name('dob') @@ -175,6 +177,7 @@ class ComplexDemoTable extends LivewireDatatable |**round**|[*Integer* $precision (default: 0)]|Rounds value to given precision|```Column::name('age')->round()```| |**defaultSort**|[*String* $direction (default: 'desc')]|Marks the column as the default search column|```Column::name('name')->defaultSort('asc')```| |**searchable**| |Includes the column in the global search|```Column::name('name')->searchable()```| +|**hideable**| |The user is able to toggle the visibility of this column|```Column::name('name')->hideable()```| |**filterable**|[*Array* $options], [*String* $filterScope]|Adds a filter to the column, according to Column type. If an array of options is passed it wil be used to populate a select input. If the column is a scope column then the name of the filter scope must also be passed|```Column::name('allegiance')->filterable(['Rebellion', 'Empire'])```| |**filterOn**|*String/Array* $statement|Allows you to specify a column name or sql statement upon which to perform the filter (must use SQL syntax, not Eloquent eg. ```'users.name'``` instead of ```'user.name'```). Useful if using a callback to modify the displayed values. Can pass a single string or array of strings which will be combined with ```OR```|```Column::callback(['name', 'allegiance'], function ($name, $allegiance) { return "$name is allied to $allegiance"; })->filterable(['Rebellion', 'Empire'])->filterOn('users.allegiance')```| |**view**|*String* $viewName| Passes the column value, whole row of values, and any additional parameters to a view template | _(see below)_| diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index 5fc073a8..e995193f 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -57,10 +57,12 @@ @if($hideable === 'buttons')
@foreach($this->columns as $index => $column) - + @if ($column['hideable']) + + @endif @endforeach
@endif diff --git a/resources/views/livewire/datatables/header-inline-hide.blade.php b/resources/views/livewire/datatables/header-inline-hide.blade.php index c4088562..14b86c83 100644 --- a/resources/views/livewire/datatables/header-inline-hide.blade.php +++ b/resources/views/livewire/datatables/header-inline-hide.blade.php @@ -34,8 +34,11 @@ class="w-full h-full px-6 py-3 border-b border-gray-200 bg-gray-50 text-xs leadi @endif - + + @if ($column['hideable']) + + @endif
diff --git a/src/Column.php b/src/Column.php index 70da13f7..79433dcd 100644 --- a/src/Column.php +++ b/src/Column.php @@ -17,6 +17,7 @@ class Column public $searchable; public $filterOn; public $filterable; + public $hideable; public $sort; public $unsortable; public $defaultSort; @@ -118,6 +119,13 @@ public function defaultSort($direction = true) return $this; } + public function hideable() + { + $this->hideable = true; + + return $this; + } + public function unsortable() { $this->unsortable = true; diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index a408762e..3e3cb794 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -191,6 +191,7 @@ public function getViewColumns() 'align', 'type', 'filterable', + 'hideable', 'complex', 'filterView', 'name', @@ -1347,7 +1348,7 @@ public function getDisplayValue($index, $value) : $value; } - /* This can be called to apply highlting of the search term to some string. + /* This can be called to apply highlighting of the search term to some string. * Motivation: Call this from your Column::Callback to apply highlight to a chosen section of the result. */ public function highlightStringWithCurrentSearchTerm(string $originalString) From a82cc955a89d566f26d0297278cc5a7dc3aa40e4 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Thu, 16 Sep 2021 13:39:00 +0200 Subject: [PATCH 093/217] introduce label column (#288) Co-authored-by: Herbert Maschke --- README.md | 9 ++++--- .../livewire/datatables/datatable.blade.php | 6 +++++ .../views/livewire/datatables/label.blade.php | 3 +++ src/Http/Livewire/LivewireDatatable.php | 3 ++- src/LabelColumn.php | 25 +++++++++++++++++++ 5 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 resources/views/livewire/datatables/label.blade.php create mode 100644 src/LabelColumn.php diff --git a/README.md b/README.md index 15139573..2da10cc8 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,6 @@ somewhere in your CSS ### Provide a datasource by declaring public property ```$model``` **OR** public method ```builder()``` that returns an instance of ```Illuminate\Database\Eloquent\Builder``` > ```php artisan livewire:datatable users-table --model=user``` --> 'app/Http/Livewire/UsersTable.php' with ```public $model = User::class``` - ### Declare a public method ```columns``` that returns an array containing one or more ```Mediconesystems\LivewireDatatables\Column``` @@ -106,7 +105,6 @@ somewhere in your CSS Columns can be built using any of the static methods below, and then their attributes assigned using fluent method chains. There are additional specific types of Column; ```NumberColumn```, ```DateColumn```, ```TimeColumn```, using the correct one for your datatype will enable type-specific formatting and filtering: - | Class | Description | |---|---| |Column|Generic string-based column. Filter will be a text input| @@ -114,6 +112,7 @@ There are additional specific types of Column; ```NumberColumn```, ```DateColumn |BooleanColumn| Values will be automatically formatted to a yes/no icon, filters will be yes/no| |DateColumn| Values will be automatically formatted to the default date format. Filters will be a date range| |TimeColumn| Values will be automatically formatted to the default time format. Filters will be a time range| +|LabelColumn| Fixed header string ("label") with fixed content string in every row. No SQL is executed at all| ___ ```php @@ -152,7 +151,11 @@ class ComplexDemoTable extends LivewireDatatable DateColumn::name('dob') ->label('DOB') ->filterable() - ->hide() + ->hide(), + + (new LabelColumn()) + ->label('My custom heading') + ->content('This fixed string appears in every row') ]; } } diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index e995193f..f04601c1 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -102,6 +102,10 @@ results->total()) checked @endif class="form-checkbox mt-1 h-4 w-4 text-blue-600 transition duration-150 ease-in-out" />
+ @elseif($column['type'] === 'label') +
+ {{ $column['label'] ?? '' }} +
@else
@isset($column['filterable']) @@ -129,6 +133,8 @@ @endif @elseif($column['type'] === 'checkbox') @include('datatables::checkbox', ['value' => $row->checkbox_attribute]) + @elseif($column['type'] === 'label') + @include('datatables::label') @else
{!! $row->{$column['name']} !!} diff --git a/resources/views/livewire/datatables/label.blade.php b/resources/views/livewire/datatables/label.blade.php new file mode 100644 index 00000000..7bed4d3b --- /dev/null +++ b/resources/views/livewire/datatables/label.blade.php @@ -0,0 +1,3 @@ +
+ {!! $column['content'] ?? '' !!} +
diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 3e3cb794..d6e9e483 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -188,6 +188,7 @@ public function getViewColumns() return collect($column)->only([ 'hidden', 'label', + 'content', 'align', 'type', 'filterable', @@ -290,7 +291,7 @@ public function getSelectStatements($withAlias = false, $export = false) { return $this->processedColumns->columns ->reject(function ($column) use ($export) { - return $column->scope || ($export && $column->preventExport); + return $column->scope || $column->type === 'label' || ($export && $column->preventExport); })->map(function ($column) { if ($column->select) { return $column; diff --git a/src/LabelColumn.php b/src/LabelColumn.php new file mode 100644 index 00000000..4c94cc88 --- /dev/null +++ b/src/LabelColumn.php @@ -0,0 +1,25 @@ +label('foo')->content('bar'), + */ +class LabelColumn extends Column +{ + public $type = 'label'; + + public $content = ''; + + /** + * Which fixed string should always be displayed in every row of this column? + */ + public function content($content) + { + $this->content = $content; + + return $this; + } +} From c5618acf9d6b5c84918b3726ed41d5921316b3f1 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Mon, 20 Sep 2021 11:42:15 +0200 Subject: [PATCH 094/217] bugfix: avoid exception when defining a label column as very first column (index 0) (#292) Co-authored-by: Herbert Maschke --- src/Http/Livewire/LivewireDatatable.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index d6e9e483..7ae4cfe5 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -501,11 +501,11 @@ public function initialiseSort() $this->sort = $this->defaultSort() ? $this->defaultSort()['key'] : collect($this->freshColumns)->reject(function ($column) { - return $column['type'] === 'checkbox' || $column['hidden']; + // list all column types that are not sortable by SQL: + return in_array($column['type'], ['checkbox', 'label']) || $column['hidden']; })->keys()->first(); $this->getSessionStoredSort(); - $this->direction = $this->defaultSort() && $this->defaultSort()['direction'] === 'asc'; } @@ -1275,9 +1275,15 @@ public function addTimeRangeFilter() return $this; } + /** + * Set the 'ORDER BY' clause of the SQL query. + * + * Do not set a 'ORDER BY' clause if the column to be sorted does not have a name assigned. + * This could be a 'label' or 'checkbox' column which is not 'sortable' by SQL by design. + */ public function addSort() { - if (isset($this->sort) && isset($this->freshColumns[$this->sort])) { + if (isset($this->sort) && isset($this->freshColumns[$this->sort]) && $this->freshColumns[$this->sort]['name']) { $this->query->orderBy(DB::raw($this->getSortString()), $this->direction ? 'asc' : 'desc'); } From fed8ad6d31c4d174b3805293c438eaf2d3c1655c Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Mon, 20 Sep 2021 14:05:12 +0200 Subject: [PATCH 095/217] allow to have more than just one label column or checkbox column per (#293) table Co-authored-by: Herbert Maschke --- src/Column.php | 3 +++ src/Http/Livewire/LivewireDatatable.php | 12 ++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Column.php b/src/Column.php index 79433dcd..8b8f507b 100644 --- a/src/Column.php +++ b/src/Column.php @@ -33,6 +33,9 @@ class Column public $width; public $exportCallback; + /** @var array list all column types that are not sortable by SQL here */ + public const UNSORTABLE_TYPES = ['label', 'checkbox']; + public static function name($name) { $column = new static; diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 7ae4cfe5..9e94b4e6 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -17,6 +17,7 @@ use Livewire\Component; use Livewire\WithPagination; use Maatwebsite\Excel\Facades\Excel; +use Mediconesystems\LivewireDatatables\Column; use Mediconesystems\LivewireDatatables\ColumnSet; use Mediconesystems\LivewireDatatables\Exports\DatatableExport; use Mediconesystems\LivewireDatatables\Traits\WithCallbacks; @@ -438,8 +439,12 @@ public function getFreshColumnsProperty() { $columns = $this->processedColumns->columnsArray(); - if (($name = collect($columns)->pluck('name')->duplicates()) && collect($columns)->pluck('name')->duplicates()->count()) { - throw new Exception('Duplicate Column Name: ' . $name->first()); + $duplicates = collect($columns)->reject(function ($column) { + return in_array($column['type'], Column::UNSORTABLE_TYPES); + })->pluck('name')->duplicates(); + + if ($duplicates->count()) { + throw new Exception('Duplicate Column Name(s): ' . implode(', ', $duplicates->toArray())); } return $columns; @@ -501,8 +506,7 @@ public function initialiseSort() $this->sort = $this->defaultSort() ? $this->defaultSort()['key'] : collect($this->freshColumns)->reject(function ($column) { - // list all column types that are not sortable by SQL: - return in_array($column['type'], ['checkbox', 'label']) || $column['hidden']; + return in_array($column['type'], Column::UNSORTABLE_TYPES) || $column['hidden']; })->keys()->first(); $this->getSessionStoredSort(); From 5f7a1015b913863a8ed78d615404828f623fb063 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 20 Sep 2021 13:39:10 +0100 Subject: [PATCH 096/217] fix coalesce bug --- .phpunit.result.cache | 2 +- src/Http/Livewire/LivewireDatatable.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.phpunit.result.cache b/.phpunit.result.cache index 5bbf4446..a87734ac 100644 --- a/.phpunit.result.cache +++ b/.phpunit.result.cache @@ -1 +1 @@ -{"version":1,"defects":[],"times":{"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_generate_an_array_of_columns_from_a_model":0.269,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #0":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #1":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #2":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #3":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #4":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #5":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #6":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #7":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_exclude_columns":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_include_columns":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_rename_columns":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_column_from_a_table_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_column_from_a_scope":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_delete_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #0":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #1":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #2":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #3":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #4":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_column":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_raw":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_width_property_from_column":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_mount_using_the_class":0.089,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_set_a_default_sort":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_show_and_hide_a_column":0.043,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_order_results":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_text":0.028,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_boolean":0.025,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_strings_as_a_boolean":0.028,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_selects":0.026,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_numbers":0.062,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_base_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_one_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_a_has_one_column":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_many_relation_columns":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_many_relation_column_with_specific_aggregate":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_has_many_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_belongs_to_relation_columns":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_belongs_to_relation_columns":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_belongs_to_many_relation_columns":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a__where_query_for_belongs_to_many_relation_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mount_from_the_default_template_with_a_model":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::the_header_can_be_hidden_with_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::the_pagination_bar_can_be_hidden_with_a_property":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_set_per_page_with_a_property":0.023,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_include_columns_from_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_exclude_columns_from_a_property":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_hide_columns_from_a_property":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mark_columns_for_date_format_from_a_property":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mark_columns_for_time_format_from_a_property":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_set_sort_from_a_property":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::component_is_created_by_make_command":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::dot_nested_component_is_created_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::forward_slash_nested_component_is_created_by_make_command":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::multiword_component_is_created_by_make_command":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::pascal_case_component_is_automatically_converted_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::snake_case_component_is_automatically_converted_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::snake_case_component_is_automatically_converted_by_make_command_on_nested_component":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::new_component_model_name_matches_option":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::a_component_is_not_created_with_a_reserved_class_name":0.012}} \ No newline at end of file +{"version":1,"defects":[],"times":{"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_generate_an_array_of_columns_from_a_model":0.124,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #0":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #1":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #2":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #3":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #4":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #5":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #6":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #7":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_exclude_columns":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_include_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_rename_columns":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_column_from_a_table_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_column_from_a_scope":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_delete_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #0":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #1":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #2":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #3":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #4":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_column":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_raw":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_width_property_from_column":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_mount_using_the_class":0.102,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_set_a_default_sort":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_show_and_hide_a_column":0.044,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_order_results":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_text":0.026,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_boolean":0.026,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_strings_as_a_boolean":0.029,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_selects":0.025,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_numbers":0.059,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_base_columns":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_one_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_a_has_one_column":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_many_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_many_relation_column_with_specific_aggregate":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_has_many_relation_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_belongs_to_relation_columns":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_belongs_to_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_belongs_to_many_relation_columns":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a__where_query_for_belongs_to_many_relation_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mount_from_the_default_template_with_a_model":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::the_header_can_be_hidden_with_a_property":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::the_pagination_bar_can_be_hidden_with_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_set_per_page_with_a_property":0.022,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_include_columns_from_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_exclude_columns_from_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_hide_columns_from_a_property":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mark_columns_for_date_format_from_a_property":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mark_columns_for_time_format_from_a_property":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_set_sort_from_a_property":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::component_is_created_by_make_command":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::dot_nested_component_is_created_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::forward_slash_nested_component_is_created_by_make_command":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::multiword_component_is_created_by_make_command":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::pascal_case_component_is_automatically_converted_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::snake_case_component_is_automatically_converted_by_make_command":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::snake_case_component_is_automatically_converted_by_make_command_on_nested_component":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::new_component_model_name_matches_option":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::a_component_is_not_created_with_a_reserved_class_name":0.013}} \ No newline at end of file diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 838bb948..8064e1fc 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -272,7 +272,7 @@ public function resolveAdditionalSelects($column) return $selects->count() > 1 ? new Expression("CONCAT_WS('" . static::SEPARATOR . "' ," . collect($selects)->map(function ($select) { - return "COALESCE($select, NULL)"; + return "IF($select, $select, '')"; })->join(', ') . ')') : $selects->first(); } @@ -700,7 +700,7 @@ public function doTimeFilterEnd($index, $end) public function doNumberFilterStart($index, $start) { - $this->activeNumberFilters[$index]['start'] = $start ? (int) $start : null; + $this->activeNumberFilters[$index]['start'] = ($start != '') ? (int) $start : null; $this->clearEmptyNumberFilter($index); $this->page = 1; $this->setSessionStoredFilters(); @@ -708,7 +708,7 @@ public function doNumberFilterStart($index, $start) public function doNumberFilterEnd($index, $end) { - $this->activeNumberFilters[$index]['end'] = ($end !== '') ? (int) $end : null; + $this->activeNumberFilters[$index]['end'] = ($end != '') ? (int) $end : null; $this->clearEmptyNumberFilter($index); $this->page = 1; $this->setSessionStoredFilters(); From 0823b63928d5d29f376ded61ce5b7838370b0b56 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Mon, 20 Sep 2021 15:02:36 +0200 Subject: [PATCH 097/217] introduce column groups (#294) * introduce column groups * fix coalesce bug * introduce column groups * style tweaks * fix tests Co-authored-by: Herbert Maschke Co-authored-by: Mark Salmon --- .phpunit.result.cache | 2 +- README.md | 8 +++++++ .../livewire/datatables/datatable.blade.php | 7 ++++++- src/Column.php | 11 ++++++++++ src/Http/Livewire/LivewireDatatable.php | 21 +++++++++++++++++++ tests/ColumnTest.php | 6 ++++++ 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/.phpunit.result.cache b/.phpunit.result.cache index a87734ac..03884ce7 100644 --- a/.phpunit.result.cache +++ b/.phpunit.result.cache @@ -1 +1 @@ -{"version":1,"defects":[],"times":{"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_generate_an_array_of_columns_from_a_model":0.124,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #0":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #1":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #2":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #3":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #4":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #5":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #6":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #7":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_exclude_columns":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_include_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_rename_columns":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_column_from_a_table_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_column_from_a_scope":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_delete_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #0":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #1":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #2":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #3":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #4":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_column":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_raw":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_width_property_from_column":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_mount_using_the_class":0.102,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_set_a_default_sort":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_show_and_hide_a_column":0.044,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_order_results":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_text":0.026,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_boolean":0.026,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_strings_as_a_boolean":0.029,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_selects":0.025,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_numbers":0.059,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_base_columns":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_one_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_a_has_one_column":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_many_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_many_relation_column_with_specific_aggregate":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_has_many_relation_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_belongs_to_relation_columns":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_belongs_to_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_belongs_to_many_relation_columns":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a__where_query_for_belongs_to_many_relation_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mount_from_the_default_template_with_a_model":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::the_header_can_be_hidden_with_a_property":0.015,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::the_pagination_bar_can_be_hidden_with_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_set_per_page_with_a_property":0.022,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_include_columns_from_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_exclude_columns_from_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_hide_columns_from_a_property":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mark_columns_for_date_format_from_a_property":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mark_columns_for_time_format_from_a_property":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_set_sort_from_a_property":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::component_is_created_by_make_command":0.02,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::dot_nested_component_is_created_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::forward_slash_nested_component_is_created_by_make_command":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::multiword_component_is_created_by_make_command":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::pascal_case_component_is_automatically_converted_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::snake_case_component_is_automatically_converted_by_make_command":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::snake_case_component_is_automatically_converted_by_make_command_on_nested_component":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::new_component_model_name_matches_option":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::a_component_is_not_created_with_a_reserved_class_name":0.013}} \ No newline at end of file +{"version":1,"defects":{"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_column":3,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_raw":3,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_width_property_from_column":3},"times":{"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_generate_an_array_of_columns_from_a_model":0.127,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #0":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #1":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #2":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #3":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #4":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #5":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #6":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_correctly_populate_the_columns_from_the_model with data set #7":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_exclude_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_include_columns":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnSetTest::it_can_rename_columns":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_column_from_a_table_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_column_from_a_scope":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_can_generate_a_delete_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #0":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #1":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #2":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #3":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_sets_properties_and_parameters with data set #4":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_column":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_an_array_from_raw":0.012,"Mediconesystems\\LivewireDatatables\\Tests\\ColumnTest::it_returns_width_property_from_column":0.011,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_mount_using_the_class":0.054,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_set_a_default_sort":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_show_and_hide_a_column":0.039,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_order_results":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_text":0.026,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_boolean":0.026,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_strings_as_a_boolean":0.029,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_selects":0.025,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableClassTest::it_can_filter_results_based_on_numbers":0.059,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_base_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_one_relation_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_a_has_one_column":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_many_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_has_many_relation_column_with_specific_aggregate":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_has_many_relation_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_belongs_to_relation_columns":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_where_query_for_belongs_to_relation_columns":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a_query_builder_for_belongs_to_many_relation_columns":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableQueryBuilderTest::it_creates_a__where_query_for_belongs_to_many_relation_columns":0.013,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mount_from_the_default_template_with_a_model":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::the_header_can_be_hidden_with_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::the_pagination_bar_can_be_hidden_with_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_set_per_page_with_a_property":0.023,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_include_columns_from_a_property":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_exclude_columns_from_a_property":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_hide_columns_from_a_property":0.021,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mark_columns_for_date_format_from_a_property":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_mark_columns_for_time_format_from_a_property":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\LivewireDatatableTemplateTest::it_can_set_sort_from_a_property":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::component_is_created_by_make_command":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::dot_nested_component_is_created_by_make_command":0.019,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::forward_slash_nested_component_is_created_by_make_command":0.016,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::multiword_component_is_created_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::pascal_case_component_is_automatically_converted_by_make_command":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::snake_case_component_is_automatically_converted_by_make_command":0.017,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::snake_case_component_is_automatically_converted_by_make_command_on_nested_component":0.018,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::new_component_model_name_matches_option":0.014,"Mediconesystems\\LivewireDatatables\\Tests\\MakeDatatableCommandTest::a_component_is_not_created_with_a_reserved_class_name":0.013}} \ No newline at end of file diff --git a/README.md b/README.md index 2da10cc8..f4b784df 100644 --- a/README.md +++ b/README.md @@ -138,18 +138,21 @@ class ComplexDemoTable extends LivewireDatatable Column::name('name') ->defaultSort('asc') + ->group('group1') ->searchable() ->hideable() ->filterable(), Column::name('planet.name') ->label('Planet') + ->group('group1') ->searchable() ->hideable() ->filterable($this->planets), DateColumn::name('dob') ->label('DOB') + ->group('group2') ->filterable() ->hide(), @@ -171,6 +174,7 @@ class ComplexDemoTable extends LivewireDatatable |_static_ **delete**|[*String* $primaryKey default: 'id']|Adds a column with a delete button, which will call ```$this->model::destroy($primaryKey)```|```Column::delete()```| |_static_ **checkbox**|[*String* $column default: 'id']|Adds a column with a checkbox. The component public property ```$selected``` will contain an array of the named column from checked rows, |```Column::checkbox()```| |**label**|*String* $name|Changes the display name of a column|```Column::name('id')->label('ID)```| +|**group**|*String* $group|Assign the column to a group. Allows to toggle the visibility of all columns of a group at once|```Column::name('id')->group('my-group')```| |**format**|[*String* $format]|Formats the column value according to type. Dates/times will use the default format or the argument |```Column::name('email_verified_at')->filterable(),```| |**hide**| |Marks column to start as hidden|```Column::name('id')->hidden()```| |**sortBy**|*String\|Expression* $column|Changes the query by which the column is sorted|```Column::name('dob')->sortBy('DATE_FORMAT(users.dob, "%m%d%Y")'),```| @@ -209,6 +213,10 @@ NumberColumn::name('students.age:min')->label('Student Min'), NumberColumn::name('students.age:max')->label('Student Max'), ``` +### Column Groups + +When you have a very big table with a lot of columns, it is possible to create 'column groups' that allows the user to toggle the visibility of a whole group at once. Use `->group('NAME')` at any column to achieve this. + ### Custom column names It is still possible to take full control over your table, you can define a ```builder``` method using whatever query you like, using your own joins, groups whatever, and then name your columns using your normal SQL syntax: diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index f04601c1..9ab52347 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -30,7 +30,7 @@ FILTERS ACTIVE @endif -
+
@if($this->activeFilters) @@ -51,6 +51,11 @@ @if($hideable === 'select') @include('datatables::hide-column-multiselect') @endif + + @foreach ($columnGroups as $name => $group) + + @endforeach
diff --git a/src/Column.php b/src/Column.php index 8b8f507b..c4f47162 100644 --- a/src/Column.php +++ b/src/Column.php @@ -9,6 +9,7 @@ class Column { public $type = 'string'; public $label; + public $group; public $name; public $select; public $joins; @@ -333,6 +334,16 @@ public function field() return Str::afterLast($this->name, '.'); } + /** + * You can use group(null) to revoke a column from a group, if necessary. + */ + public function group($group) + { + $this->group = $group; + + return $this; + } + public function relations() { return $this->isBaseColumn() ? null : collect(explode('.', Str::beforeLast($this->name, '.'))); diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 10a10faf..64f8d8d3 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -59,6 +59,7 @@ class LivewireDatatable extends Component public $complexQuery; public $title; public $name; + public $columnGroups = []; public $userFilter; public $persistComplexQuery; public $persistHiddenColumns = true; @@ -176,6 +177,7 @@ public function mount( $this->initialiseHiddenColumns(); $this->initialiseFilters(); $this->initialisePerPage(); + $this->initialiseColumnGroups(); } public function columns() @@ -189,6 +191,7 @@ public function getViewColumns() return collect($column)->only([ 'hidden', 'label', + 'group', 'content', 'align', 'type', @@ -537,6 +540,15 @@ public function initialisePerPage() } } + public function initialiseColumnGroups() + { + array_map(function ($column) { + if ($column['group'] ?? false) { + $this->columnGroups[$column['group']][] = $column['name'] ?? $column['label']; + } + }, $this->columns); + } + public function initialiseFilters() { if (! $this->persistFilters) { @@ -652,6 +664,15 @@ public function toggle($index) } } + public function toggleGroup($group) + { + foreach ($this->columns as $key => $column) { + if ($column['group'] === $group) { + $this->toggle($key); + } + } + } + public function doBooleanFilter($index, $value) { $this->activeBooleanFilters[$index] = $value; diff --git a/tests/ColumnTest.php b/tests/ColumnTest.php index ff380122..b631e222 100644 --- a/tests/ColumnTest.php +++ b/tests/ColumnTest.php @@ -96,6 +96,8 @@ public function it_returns_an_array_from_column() 'exportCallback' => function () { }, 'filterOn' => null, + 'group' => null, + 'hideable' => null, ], $subject); } @@ -134,6 +136,8 @@ public function it_returns_an_array_from_raw() 'unsortable' => null, 'exportCallback' => null, 'filterOn' => null, + 'group' => null, + 'hideable' => null, ], $subject); } @@ -171,6 +175,8 @@ public function it_returns_width_property_from_column() 'unsortable' => null, 'exportCallback' => null, 'filterOn' => null, + 'group' => null, + 'hideable' => null, ], $subject); } From 604508f268fd9dc26da87c66b7c84a37d216017f Mon Sep 17 00:00:00 2001 From: Laurens K Date: Mon, 20 Sep 2021 15:09:13 +0200 Subject: [PATCH 098/217] Extract default CSS classes to config. (#289) Extracting the default CSS classes applied by the rowClasses() and cellClasses() methods so it's easier to globally change the style. Added a short hint in the readme. Also added some comments to the config file. --- README.md | 2 + config/livewire-datatables.php | 69 ++++++++++++++++++++++++- src/Http/Livewire/LivewireDatatable.php | 12 ++++- 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f4b784df..5c80f188 100644 --- a/README.md +++ b/README.md @@ -449,6 +449,8 @@ public function cellClasses($row, $column) } ``` +You can change the default CSS classes applied by the ```rowClasses``` and the ```cellClasses``` methods by changing ```default_classes``` in the ```livewire-datatables.php``` config file. + You could also override the render method in your table's class to provide different templates for different tables. diff --git a/config/livewire-datatables.php b/config/livewire-datatables.php index e966d179..75244478 100644 --- a/config/livewire-datatables.php +++ b/config/livewire-datatables.php @@ -1,10 +1,77 @@ 'H:i', 'default_date_format' => 'd/m/Y', - 'suppress_search_highlights' => false, // When searching, don't highlight matching search results when set to true + + /* + |-------------------------------------------------------------------------- + | Surpress Search Highlights + |-------------------------------------------------------------------------- + | When enabled, matching text won't be highlighted in the search results + | while searching. + | + */ + + 'suppress_search_highlights' => false, + + /* + |-------------------------------------------------------------------------- + | Per Page Options + |-------------------------------------------------------------------------- + | Sets the options to choose from in the `Per Page`dropdown. + | + */ + 'per_page_options' => [10, 25, 50, 100], + + /* + |-------------------------------------------------------------------------- + | Default Per Page + |-------------------------------------------------------------------------- + | Sets the default amount of rows to display per page. + | + */ + 'default_per_page' => 10, + + /* + |-------------------------------------------------------------------------- + | Model Namespace + |-------------------------------------------------------------------------- + | Sets the default namespace to be used when generating a new Datatables + | component. + | + */ + 'model_namespace' => 'App', + + /* + |-------------------------------------------------------------------------- + | Default CSS classes + |-------------------------------------------------------------------------- + | + | Sets the default classes that will be applied to each row and class + | if the rowClasses() and cellClasses() functions are not overrided. + | + */ + + 'default_classes' => [ + 'row' => [ + 'even' => 'divide-x divide-gray-100 text-sm text-gray-900 bg-gray-100', + 'odd' => 'divide-x divide-gray-100 text-sm text-gray-900 bg-gray-50', + 'selected' => 'divide-x divide-gray-100 text-sm text-gray-900 bg-yellow-100', + ], + 'cell' => 'text-sm text-gray-900' + ] ]; diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 64f8d8d3..6583d2a1 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1509,12 +1509,20 @@ public function getSavedQueries() public function rowClasses($row, $loop) { // Override this method with your own method for adding classes to a row - return 'divide-x divide-gray-100 text-sm text-gray-900 ' . ($this->rowIsSelected($row) ? 'bg-yellow-100' : ($loop->even ? 'bg-gray-100' : 'bg-gray-50')); + if ($this->rowIsSelected($row)) { + return config('livewire-datatables.default_classes.row.selected', 'divide-x divide-gray-100 text-sm text-gray-900 bg-yellow-100'); + } else { + if ($loop->even) { + return config('livewire-datatables.default_classes.row.even', 'divide-x divide-gray-100 text-sm text-gray-900 bg-gray-100'); + } else { + return config('livewire-datatables.default_classes.row.odd', 'divide-x divide-gray-100 text-sm text-gray-900 bg-gray-50'); + } + } } public function cellClasses($row, $column) { // Override this method with your own method for adding classes to a cell - return 'text-sm text-gray-900'; + return config('livewire-datatables.default_classes.cell', 'text-sm text-gray-900'); } } From b5b567d19069e6655eee19edd65ead310aa1cb25 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Mon, 20 Sep 2021 14:09:36 +0100 Subject: [PATCH 099/217] Apply fixes from StyleCI (#295) Co-authored-by: Mark Salmon --- config/livewire-datatables.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/livewire-datatables.php b/config/livewire-datatables.php index 75244478..0217f55b 100644 --- a/config/livewire-datatables.php +++ b/config/livewire-datatables.php @@ -72,6 +72,6 @@ 'odd' => 'divide-x divide-gray-100 text-sm text-gray-900 bg-gray-50', 'selected' => 'divide-x divide-gray-100 text-sm text-gray-900 bg-yellow-100', ], - 'cell' => 'text-sm text-gray-900' - ] + 'cell' => 'text-sm text-gray-900', + ], ]; From 1c5ce4664437ac90164cdbf6c6fc6cfa30befead Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Wed, 22 Sep 2021 13:51:03 +0100 Subject: [PATCH 100/217] fix callback bug --- src/Http/Livewire/LivewireDatatable.php | 2 +- tests/ColumnTest.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 6583d2a1..8f49cde5 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -278,7 +278,7 @@ public function resolveAdditionalSelects($column) return $selects->count() > 1 ? new Expression("CONCAT_WS('" . static::SEPARATOR . "' ," . collect($selects)->map(function ($select) { - return "IF($select, $select, '')"; + return "COALESCE($select, '')"; })->join(', ') . ')') : $selects->first(); } diff --git a/tests/ColumnTest.php b/tests/ColumnTest.php index b631e222..ce030439 100644 --- a/tests/ColumnTest.php +++ b/tests/ColumnTest.php @@ -168,8 +168,9 @@ public function it_returns_width_property_from_column() 'filterView' => null, 'select' => null, 'joins' => null, + 'aggregate' => 'group_concat', - 'align' => 'left', + 'align' => 'left',gch 'preventExport' => null, 'width' => '1em', 'unsortable' => null, From ce518201227e41533bb6ae44491a41a7be5e3192 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Wed, 22 Sep 2021 14:54:06 +0200 Subject: [PATCH 101/217] introduce ability to make i18nable custom column category labels (#297) * introduce ability to make i18nable custom column category labels * column group labelling improvements * remove some unnecessary code Co-authored-by: Herbert Maschke Co-authored-by: Mark Salmon --- README.md | 21 ++++++++++ .../livewire/datatables/datatable.blade.php | 6 ++- src/Column.php | 8 +++- src/Http/Livewire/LivewireDatatable.php | 40 ++++++++++++++++++- 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5c80f188..d905b1f7 100644 --- a/README.md +++ b/README.md @@ -216,6 +216,27 @@ NumberColumn::name('students.age:max')->label('Student Max'), ### Column Groups When you have a very big table with a lot of columns, it is possible to create 'column groups' that allows the user to toggle the visibility of a whole group at once. Use `->group('NAME')` at any column to achieve this. +You can human readable labels and translations of your groups via the `groupLabels` property of your table: + +```php +class GroupDemoTable extends LivewireDatatable +{ + public $groupLabels = [ + 'group1' => 'app.translation_for_group_1' + 'group2' => 'app.translation_for_group_2' + ]; + +public function columns() +{ + return [ + Column::name('planets.name') + ->group('group1') + ->label('Planet'), + + Column::name('planets.name') + ->group('group2') + ->label('Planet'), +``` ### Custom column names It is still possible to take full control over your table, you can define a ```builder``` method using whatever query you like, using your own joins, groups whatever, and then name your columns using your normal SQL syntax: diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index 9ab52347..bd854f69 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -53,8 +53,10 @@ @endif @foreach ($columnGroups as $name => $group) - + @endforeach
diff --git a/src/Column.php b/src/Column.php index c4f47162..8578111e 100644 --- a/src/Column.php +++ b/src/Column.php @@ -9,7 +9,6 @@ class Column { public $type = 'string'; public $label; - public $group; public $name; public $select; public $joins; @@ -34,6 +33,11 @@ class Column public $width; public $exportCallback; + /** + * @var string (optional) you can group your columns to let the user toggle the visibility of a group at once. + */ + public $group; + /** @var array list all column types that are not sortable by SQL here */ public const UNSORTABLE_TYPES = ['label', 'checkbox']; @@ -336,6 +340,8 @@ public function field() /** * You can use group(null) to revoke a column from a group, if necessary. + * + * @see array LivewireDatatable->groupLabels to assign a human readable and translatable label for the group */ public function group($group) { diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 8f49cde5..6d76e41d 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -67,6 +67,16 @@ class LivewireDatatable extends Component public $persistPerPage = true; public $persistFilters = true; + /** + * @var array List your groups and the corresponding label (or translation) here. + * The label can be a i18n placeholder like 'app.my_string' and it will be automatically translated via __(). + * + * Group labels are optional. If they are omitted, the 'name' of the group will be displayed to the user. + * + * @example ['group1' => 'app.toggle_group1', 'group2' => 'app.toggle_group2'] + */ + public $groupLabels = []; + protected $query; protected $listeners = ['refreshLivewireDatatable', 'complexQuery', 'saveQuery', 'deleteQuery', 'applyToTable', 'resetTable']; @@ -543,7 +553,7 @@ public function initialisePerPage() public function initialiseColumnGroups() { array_map(function ($column) { - if ($column['group'] ?? false) { + if (isset($column['group'])) { $this->columnGroups[$column['group']][] = $column['name'] ?? $column['label']; } }, $this->columns); @@ -673,6 +683,34 @@ public function toggleGroup($group) } } + /** + * @return bool returns true if all columns of the given group are _completely_ visible. + */ + public function isGroupVisible($group) + { + foreach ($this->columns as $column) { + if ($column['group'] === $group && $column['hidden']) { + return false; + } + } + + return true; + } + + /** + * @return bool returns true if all columns of the given group are _completely_ hidden. + */ + public function isGroupHidden($group) + { + foreach ($this->columns as $column) { + if ($column['group'] === $group && ! $column['hidden']) { + return false; + } + } + + return true; + } + public function doBooleanFilter($index, $value) { $this->activeBooleanFilters[$index] = $value; From e07000455f2feb0e735e3bb5d4f7ec8f84a0d7c7 Mon Sep 17 00:00:00 2001 From: Mark Salmon Date: Wed, 22 Sep 2021 14:02:02 +0100 Subject: [PATCH 102/217] test typo --- tests/ColumnTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ColumnTest.php b/tests/ColumnTest.php index ce030439..a88253dd 100644 --- a/tests/ColumnTest.php +++ b/tests/ColumnTest.php @@ -170,7 +170,7 @@ public function it_returns_width_property_from_column() 'joins' => null, 'aggregate' => 'group_concat', - 'align' => 'left',gch + 'align' => 'left', 'preventExport' => null, 'width' => '1em', 'unsortable' => null, From 3fa7aca1c57b87f62ea90168c81be94ee325be91 Mon Sep 17 00:00:00 2001 From: Tom Shaw Date: Sun, 10 Oct 2021 10:13:06 -0500 Subject: [PATCH 103/217] Base Mass Actions starting point. --- .../livewire/datatables/datatable.blade.php | 22 +++++++ src/Action.php | 57 ++++++++++++++++++ src/Http/Livewire/LivewireDatatable.php | 59 +++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 src/Action.php diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index bd854f69..c6bec622 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -39,6 +39,28 @@ @endif + @if(count($this->selectActions)) +
+ + +
+ @endif + @if($exportable)
@endforelse + + @if ($this->hasSummaryRow()) +
+ @foreach($this->columns as $column) + @if ($column['summary']) +
+ {{ $this->summarize($column['name']) }} +
+ @else +
+ @endif + @endforeach +
+ @endif
diff --git a/src/Column.php b/src/Column.php index 8578111e..34a5d2a1 100644 --- a/src/Column.php +++ b/src/Column.php @@ -33,6 +33,12 @@ class Column public $width; public $exportCallback; + /** + * @var bool should the sum of all summarizable cells in this column be + * displayed as a summary at the bottom of the table? + */ + public $summary = false; + /** * @var string (optional) you can group your columns to let the user toggle the visibility of a group at once. */ @@ -113,6 +119,20 @@ public function label($label) return $this; } + public function enableSummary() + { + $this->summary = true; + + return $this; + } + + public function disableSummary() + { + $this->summary = false; + + return $this; + } + public function sortBy($column) { $this->sort = $column; diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 6d76e41d..e09f5442 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -202,6 +202,7 @@ public function getViewColumns() 'hidden', 'label', 'group', + 'summary', 'content', 'align', 'type', @@ -617,6 +618,34 @@ public function getSortString() } } + /** + * @return bool has the user defined at least one column to display a summary row? + */ + public function hasSummaryRow() + { + foreach ($this->columns as $column) { + if ($column['summary']) { + return true; + } + } + + return false; + } + + /** + * Attempt so summarize each data cell of the given column. + * In case we have a string or any other value that is not summarizable, + * we return a empty string. + */ + public function summarize($column) + { + try { + return $this->results->sum($column); + } catch (\TypeError $e) { + return ''; + } + } + public function updatingPerPage() { $this->refreshLivewireDatatable(); From 59afa0c1b047268e2d666ea125975dfa9855ad86 Mon Sep 17 00:00:00 2001 From: Tom Shaw Date: Thu, 14 Oct 2021 10:44:08 -0500 Subject: [PATCH 109/217] Addition mass action exports with settings. --- .../livewire/datatables/datatable.blade.php | 3 +- src/Action.php | 42 ++++++- src/Exports/DatatableExport.php | 119 +++++++++++++++++- src/Http/Livewire/LivewireDatatable.php | 71 ++++++++--- 4 files changed, 212 insertions(+), 23 deletions(-) diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index c6bec622..89fe8359 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -40,7 +40,7 @@ @endif @if(count($this->selectActions)) -
+
+
@endif diff --git a/src/Action.php b/src/Action.php index c148ef40..779ffca9 100644 --- a/src/Action.php +++ b/src/Action.php @@ -7,8 +7,11 @@ class Action public $value; public $label; public $group; - public $exportable = false; - public $exportableOptions = []; + public $isExport = false; + public $name; + public $type; + public $styles = []; + public $widths = []; public $callable; public function __call($method, $args) @@ -40,7 +43,7 @@ public function group($group) return $this; } - public static function groups($group, $actions) + public static function groupBy($group, $actions) { if ($actions instanceof \Closure) { return collect($actions())->each(function ($item) use ($group) { @@ -49,10 +52,37 @@ public static function groups($group, $actions) } } - public function exportable($exportable = true, $exportableOptions = []) + public function isExport($isExport = true) { - $this->exportable = $exportable; - $this->exportableOptions = $exportableOptions; + $this->isExport = $isExport; + + return $this; + } + + public function name($name) + { + $this->name = $name; + + return $this; + } + + public function type($type) + { + $this->type = $type; + + return $this; + } + + public function styles($styles) + { + $this->styles = $styles; + + return $this; + } + + public function widths($widths) + { + $this->widths = $widths; return $this; } diff --git a/src/Exports/DatatableExport.php b/src/Exports/DatatableExport.php index a31179e5..8249d1af 100644 --- a/src/Exports/DatatableExport.php +++ b/src/Exports/DatatableExport.php @@ -2,15 +2,26 @@ namespace Mediconesystems\LivewireDatatables\Exports; +use Maatwebsite\Excel\Excel as ExcelExport; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\WithHeadings; +use Maatwebsite\Excel\Concerns\ShouldAutoSize; +use Maatwebsite\Excel\Concerns\WithColumnWidths; +use Maatwebsite\Excel\Concerns\WithStyles; +use Maatwebsite\Excel\Facades\Excel; -class DatatableExport implements FromCollection, WithHeadings +use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; + +class DatatableExport implements FromCollection, WithHeadings, ShouldAutoSize, WithColumnWidths, WithStyles { use Exportable; public $collection; + public $fileName = 'DatatableExport'; + public $fileType = 'xlsx'; + public $styles = []; + public $columnWidths = []; public function __construct($collection) { @@ -26,4 +37,110 @@ public function headings(): array { return array_keys((array) $this->collection->first()); } + + public function setFileName($fileName) + { + $this->fileName = $fileName; + + return $this; + } + + public function getFileName(): string + { + return $this->fileName; + } + + public function setFileType($fileType) + { + $this->fileType = strtolower($fileType); + + return $this; + } + + public function getFileType(): string + { + return $this->fileType; + } + + public function setColumnWidths($columnWidths) + { + $this->columnWidths = $columnWidths; + + return $this; + } + + public function getColumnWidths(): array + { + return $this->columnWidths; + } + + public function columnWidths(): array + { + return $this->getColumnWidths(); + } + + public function setStyles($styles) + { + $this->styles = $styles; + + return $this; + } + + public function getStyles(): array + { + return $this->styles; + } + + public function styles(Worksheet $sheet) + { + return $this->getStyles(); + } + + public function getFileWriter($fileType) + { + switch ($fileType) { + case "xlsx": + $writer = ExcelExport::XLSX; + break; + case "csv": + $writer = ExcelExport::CSV; + break; + case "tsv": + $writer = ExcelExport::TSV; + break; + case "ods": + $writer = ExcelExport::ODS; + break; + case "xls": + $writer = ExcelExport::XLS; + break; + case "html": + $writer = ExcelExport::HTML; + break; + case "mpdf": + $writer = ExcelExport::MPDF; + break; + case "dompdf": + $writer = ExcelExport::DOMPDF; + break; + case "tcpdf": + $writer = ExcelExport::TCPDF; + break; + default: + $writer = ExcelExport::XLSX; + } + + return $writer; + } + + public function download() + { + $fileName = $this->getFileName(); + $fileType = $this->getFileType(); + + $writer = $this->getFileWriter($fileType); + $headers = ($fileType === 'csv') ? ['Content-Type' => 'text/csv'] : []; + + return Excel::download($this, $fileName . '.' . $fileType, $writer, $headers); + } } diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index fa938a28..713125fc 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1487,7 +1487,18 @@ public function export() { $this->forgetComputed(); - $results = $this->mapCallbacks( + $export = new DatatableExport($this->getExportResultsSet()); + + $export->setFileName('DatatableExport'); + + $export->setFileType('xlsx'); + + return $export->download(); + } + + public function getExportResultsSet() + { + return $this->mapCallbacks( $this->getQuery()->when(count($this->selected), function ($query) { return $query->havingRaw('checkbox_attribute IN (' . implode(',', $this->selected) . ')'); })->get(), @@ -1499,8 +1510,6 @@ public function export() return [$value['label'] ?? $value['name'] => $item->{$value['name']}]; })->all(); }); - - return Excel::download(new DatatableExport($results), 'DatatableExport.xlsx'); } public function getQuery($export = false) @@ -1573,11 +1582,10 @@ public function cellClasses($row, $column) // Override this method with your own method for adding classes to a cell return config('livewire-datatables.default_classes.cell', 'text-sm text-gray-900'); } - public function getMassActions() { return collect($this->massActions)->map(function ($action) { - return collect($action)->except(['exportable', 'exportableOptions', 'callable'])->toArray(); + return collect($action)->except(['callable'])->toArray(); })->toArray(); } @@ -1601,28 +1609,61 @@ public function getSelectActionsProperty() }, true); } - public function updatedSelectedAction($value) + public function handleMassActions() { - if (!count($this->selected)) { - $this->selectedAction = null; + if (!$this->selectedAction) { return; } - $action = collect($this->massActions)->filter(function ($item) use ($value) { - return $item->value === $value; + $option = $this->selectedAction; + + $action = collect($this->massActions)->filter(function ($item) use ($option) { + return $item->value === $option; })->shift(); $collection = collect($action); - // @todo -- Export with type and user defined params if any. - if ($collection->has('exportable')) { - if ($collection->has('exportableOptions')) { - $exportOptions = $collection->get('exportableOptions'); + $isExport = $collection->get('isExport'); + + if ($isExport) { + + $fileName = $collection->get('name'); + $fileType = $collection->get('type'); + + $styles = $collection->get('styles'); + $widths = $collection->get('widths'); + + $datatableExport = new DatatableExport($this->getExportResultsSet()); + + if ($fileName) { + $datatableExport->setFileName($fileName); + } + + if ($fileType) { + $datatableExport->setFileType($fileType); + } + + if ($styles) { + $datatableExport->setStyles($styles); + } + + if ($widths) { + $datatableExport->setColumnWidths($widths); } + + return $datatableExport->download(); + } + + if (!count($this->selected)) { + $this->selectedAction = null; + return; } if ($collection->has('callable') && is_callable($action->callable)) { - $action->callable($value, $this->selected); + $action->callable($option, $this->selected); } + + $this->selectedAction = null; + $this->selected = []; } } From 4953ad721e45046fc7a91c5bdb42d238338bf7e3 Mon Sep 17 00:00:00 2001 From: Tom Shaw Date: Thu, 14 Oct 2021 17:15:20 -0500 Subject: [PATCH 110/217] Adjust spacing. --- src/Exports/DatatableExport.php | 18 +++++++++--------- src/Http/Livewire/LivewireDatatable.php | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Exports/DatatableExport.php b/src/Exports/DatatableExport.php index 8249d1af..fcf4f97c 100644 --- a/src/Exports/DatatableExport.php +++ b/src/Exports/DatatableExport.php @@ -99,31 +99,31 @@ public function styles(Worksheet $sheet) public function getFileWriter($fileType) { switch ($fileType) { - case "xlsx": + case 'xlsx': $writer = ExcelExport::XLSX; break; - case "csv": + case 'csv': $writer = ExcelExport::CSV; break; - case "tsv": + case 'tsv': $writer = ExcelExport::TSV; break; - case "ods": + case 'ods': $writer = ExcelExport::ODS; break; - case "xls": + case 'xls': $writer = ExcelExport::XLS; break; - case "html": + case 'html': $writer = ExcelExport::HTML; break; - case "mpdf": + case 'mpdf': $writer = ExcelExport::MPDF; break; - case "dompdf": + case 'dompdf': $writer = ExcelExport::DOMPDF; break; - case "tcpdf": + case 'tcpdf': $writer = ExcelExport::TCPDF; break; default: diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 713125fc..bf11e543 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -16,7 +16,6 @@ use Illuminate\View\View; use Livewire\Component; use Livewire\WithPagination; -use Maatwebsite\Excel\Facades\Excel; use Mediconesystems\LivewireDatatables\Column; use Mediconesystems\LivewireDatatables\ColumnSet; use Mediconesystems\LivewireDatatables\Exports\DatatableExport; @@ -1582,6 +1581,7 @@ public function cellClasses($row, $column) // Override this method with your own method for adding classes to a cell return config('livewire-datatables.default_classes.cell', 'text-sm text-gray-900'); } + public function getMassActions() { return collect($this->massActions)->map(function ($action) { @@ -1611,7 +1611,7 @@ public function getSelectActionsProperty() public function handleMassActions() { - if (!$this->selectedAction) { + if (! $this->selectedAction) { return; } @@ -1650,11 +1650,11 @@ public function handleMassActions() if ($widths) { $datatableExport->setColumnWidths($widths); } - + return $datatableExport->download(); } - if (!count($this->selected)) { + if (! count($this->selected)) { $this->selectedAction = null; return; } From abdf2dc03727f688e4f1b5198911ac5bfd1051a2 Mon Sep 17 00:00:00 2001 From: Tom Shaw Date: Thu, 14 Oct 2021 17:20:35 -0500 Subject: [PATCH 111/217] Adjust spacing. --- src/Exports/DatatableExport.php | 4 ++-- src/Http/Livewire/LivewireDatatable.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Exports/DatatableExport.php b/src/Exports/DatatableExport.php index fcf4f97c..5565ad73 100644 --- a/src/Exports/DatatableExport.php +++ b/src/Exports/DatatableExport.php @@ -2,13 +2,13 @@ namespace Mediconesystems\LivewireDatatables\Exports; -use Maatwebsite\Excel\Excel as ExcelExport; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\FromCollection; -use Maatwebsite\Excel\Concerns\WithHeadings; use Maatwebsite\Excel\Concerns\ShouldAutoSize; use Maatwebsite\Excel\Concerns\WithColumnWidths; +use Maatwebsite\Excel\Concerns\WithHeadings; use Maatwebsite\Excel\Concerns\WithStyles; +use Maatwebsite\Excel\Excel as ExcelExport; use Maatwebsite\Excel\Facades\Excel; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index bf11e543..e8758a77 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1626,7 +1626,6 @@ public function handleMassActions() $isExport = $collection->get('isExport'); if ($isExport) { - $fileName = $collection->get('name'); $fileType = $collection->get('type'); @@ -1656,6 +1655,7 @@ public function handleMassActions() if (! count($this->selected)) { $this->selectedAction = null; + return; } From 7e8b93f1cb927e5121a6c924ba49d7c73bb7db8e Mon Sep 17 00:00:00 2001 From: Tom Shaw Date: Thu, 14 Oct 2021 17:23:03 -0500 Subject: [PATCH 112/217] Adjusting style ci issues. --- src/Exports/DatatableExport.php | 1 - src/Http/Livewire/LivewireDatatable.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Exports/DatatableExport.php b/src/Exports/DatatableExport.php index 5565ad73..9304e71f 100644 --- a/src/Exports/DatatableExport.php +++ b/src/Exports/DatatableExport.php @@ -10,7 +10,6 @@ use Maatwebsite\Excel\Concerns\WithStyles; use Maatwebsite\Excel\Excel as ExcelExport; use Maatwebsite\Excel\Facades\Excel; - use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; class DatatableExport implements FromCollection, WithHeadings, ShouldAutoSize, WithColumnWidths, WithStyles diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index e8758a77..80c5c93c 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1581,7 +1581,7 @@ public function cellClasses($row, $column) // Override this method with your own method for adding classes to a cell return config('livewire-datatables.default_classes.cell', 'text-sm text-gray-900'); } - + public function getMassActions() { return collect($this->massActions)->map(function ($action) { From b922734b8fd5dde4d514e1b30e20171b20c121ec Mon Sep 17 00:00:00 2001 From: Tom Shaw Date: Fri, 15 Oct 2021 16:21:47 -0500 Subject: [PATCH 113/217] Evaluating a more verbose export API. --- src/Action.php | 19 +++----- src/Exports/DatatableExport.php | 61 +------------------------ src/Http/Livewire/LivewireDatatable.php | 21 ++------- 3 files changed, 12 insertions(+), 89 deletions(-) diff --git a/src/Action.php b/src/Action.php index 779ffca9..91d1ff06 100644 --- a/src/Action.php +++ b/src/Action.php @@ -7,9 +7,8 @@ class Action public $value; public $label; public $group; + public $fileName; public $isExport = false; - public $name; - public $type; public $styles = []; public $widths = []; public $callable; @@ -52,23 +51,17 @@ public static function groupBy($group, $actions) } } - public function isExport($isExport = true) + public function export($fileName) { - $this->isExport = $isExport; + $this->fileName = $fileName; + $this->isExport(); return $this; } - public function name($name) - { - $this->name = $name; - - return $this; - } - - public function type($type) + public function isExport($isExport = true) { - $this->type = $type; + $this->isExport = $isExport; return $this; } diff --git a/src/Exports/DatatableExport.php b/src/Exports/DatatableExport.php index 9304e71f..7800e539 100644 --- a/src/Exports/DatatableExport.php +++ b/src/Exports/DatatableExport.php @@ -8,7 +8,6 @@ use Maatwebsite\Excel\Concerns\WithColumnWidths; use Maatwebsite\Excel\Concerns\WithHeadings; use Maatwebsite\Excel\Concerns\WithStyles; -use Maatwebsite\Excel\Excel as ExcelExport; use Maatwebsite\Excel\Facades\Excel; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; @@ -17,8 +16,7 @@ class DatatableExport implements FromCollection, WithHeadings, ShouldAutoSize, W use Exportable; public $collection; - public $fileName = 'DatatableExport'; - public $fileType = 'xlsx'; + public $fileName = 'DatatableExport.xlsx'; public $styles = []; public $columnWidths = []; @@ -49,18 +47,6 @@ public function getFileName(): string return $this->fileName; } - public function setFileType($fileType) - { - $this->fileType = strtolower($fileType); - - return $this; - } - - public function getFileType(): string - { - return $this->fileType; - } - public function setColumnWidths($columnWidths) { $this->columnWidths = $columnWidths; @@ -95,51 +81,8 @@ public function styles(Worksheet $sheet) return $this->getStyles(); } - public function getFileWriter($fileType) - { - switch ($fileType) { - case 'xlsx': - $writer = ExcelExport::XLSX; - break; - case 'csv': - $writer = ExcelExport::CSV; - break; - case 'tsv': - $writer = ExcelExport::TSV; - break; - case 'ods': - $writer = ExcelExport::ODS; - break; - case 'xls': - $writer = ExcelExport::XLS; - break; - case 'html': - $writer = ExcelExport::HTML; - break; - case 'mpdf': - $writer = ExcelExport::MPDF; - break; - case 'dompdf': - $writer = ExcelExport::DOMPDF; - break; - case 'tcpdf': - $writer = ExcelExport::TCPDF; - break; - default: - $writer = ExcelExport::XLSX; - } - - return $writer; - } - public function download() { - $fileName = $this->getFileName(); - $fileType = $this->getFileType(); - - $writer = $this->getFileWriter($fileType); - $headers = ($fileType === 'csv') ? ['Content-Type' => 'text/csv'] : []; - - return Excel::download($this, $fileName . '.' . $fileType, $writer, $headers); + return Excel::download($this, $this->getFileName()); } } diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 80c5c93c..55008e51 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1488,10 +1488,6 @@ public function export() $export = new DatatableExport($this->getExportResultsSet()); - $export->setFileName('DatatableExport'); - - $export->setFileType('xlsx'); - return $export->download(); } @@ -1585,7 +1581,7 @@ public function cellClasses($row, $column) public function getMassActions() { return collect($this->massActions)->map(function ($action) { - return collect($action)->except(['callable'])->toArray(); + return collect($action)->only(['group', 'value', 'label'])->toArray(); })->toArray(); } @@ -1623,24 +1619,15 @@ public function handleMassActions() $collection = collect($action); - $isExport = $collection->get('isExport'); - - if ($isExport) { - $fileName = $collection->get('name'); - $fileType = $collection->get('type'); + if ($collection->get('isExport')) { + $fileName = $collection->get('fileName'); $styles = $collection->get('styles'); $widths = $collection->get('widths'); $datatableExport = new DatatableExport($this->getExportResultsSet()); - if ($fileName) { - $datatableExport->setFileName($fileName); - } - - if ($fileType) { - $datatableExport->setFileType($fileType); - } + $datatableExport->setFileName($fileName); if ($styles) { $datatableExport->setStyles($styles); From 47d0548d5fdce4109584df422b84caba7d63bc12 Mon Sep 17 00:00:00 2001 From: Tom Shaw Date: Sat, 16 Oct 2021 07:07:33 -0500 Subject: [PATCH 114/217] Miscellaneous code cleanup/refactoring. --- .../livewire/datatables/datatable.blade.php | 10 +++--- src/Http/Livewire/LivewireDatatable.php | 31 +++++++------------ 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/resources/views/livewire/datatables/datatable.blade.php b/resources/views/livewire/datatables/datatable.blade.php index 89fe8359..d49374ec 100644 --- a/resources/views/livewire/datatables/datatable.blade.php +++ b/resources/views/livewire/datatables/datatable.blade.php @@ -39,12 +39,12 @@ @endif - @if(count($this->selectActions)) + @if(count($this->massActionsOptions))
- - - @foreach($this->selectActions as $group => $items) + @foreach($this->massActionsOptions as $group => $items) @if(!$group) @foreach($items as $item) @@ -58,7 +58,7 @@ @endif @endforeach - +
@endif diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 55008e51..b21dbc2b 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -67,7 +67,7 @@ class LivewireDatatable extends Component public $persistFilters = true; public $actions; - public $selectedAction; + public $massActionOption; /** * @var array List your groups and the corresponding label (or translation) here. @@ -1592,26 +1592,26 @@ public function getMassActionsProperty() $duplicates = $actions->pluck('value')->duplicates(); if ($duplicates->count()) { - throw new Exception('Duplicate Action(s): ' . implode(', ', $duplicates->toArray())); + throw new Exception('Duplicate Mass Action(s): ' . implode(', ', $duplicates->toArray())); } return $actions->toArray(); } - public function getSelectActionsProperty() + public function getMassActionsOptionsProperty() { return collect($this->actions)->groupBy(function ($item) { return $item['group']; }, true); } - public function handleMassActions() + public function massActionOptionHandler() { - if (! $this->selectedAction) { + if (! $this->massActionOption) { return; } - $option = $this->selectedAction; + $option = $this->massActionOption; $action = collect($this->massActions)->filter(function ($item) use ($option) { return $item->value === $option; @@ -1620,28 +1620,19 @@ public function handleMassActions() $collection = collect($action); if ($collection->get('isExport')) { - $fileName = $collection->get('fileName'); - - $styles = $collection->get('styles'); - $widths = $collection->get('widths'); - $datatableExport = new DatatableExport($this->getExportResultsSet()); - $datatableExport->setFileName($fileName); + $datatableExport->setFileName($collection->get('fileName')); - if ($styles) { - $datatableExport->setStyles($styles); - } + $datatableExport->setStyles($collection->get('styles')); - if ($widths) { - $datatableExport->setColumnWidths($widths); - } + $datatableExport->setColumnWidths($collection->get('widths')); return $datatableExport->download(); } if (! count($this->selected)) { - $this->selectedAction = null; + $this->massActionOption = null; return; } @@ -1650,7 +1641,7 @@ public function handleMassActions() $action->callable($option, $this->selected); } - $this->selectedAction = null; + $this->massActionOption = null; $this->selected = []; } } From 72fe18a3bb49b8f025046295b7e28ad03655fc87 Mon Sep 17 00:00:00 2001 From: Siddhartha Mehta Date: Tue, 16 Nov 2021 16:31:14 +0530 Subject: [PATCH 115/217] Add format method to Number Column. formats & rounds a number with grouped thousands - 1000000 => 1,000,000.00 (If places set to 2) with variable places. --- src/NumberColumn.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/NumberColumn.php b/src/NumberColumn.php index e37dd442..f4c3dcb9 100644 --- a/src/NumberColumn.php +++ b/src/NumberColumn.php @@ -18,4 +18,15 @@ public function round($places = 0) return $this; } + + // formats & rounds a number with grouped thousands - 1000000 => 1,000,000.00 (If places set to 2) + public function format($places = 2) + { + + $this->callback = function ($value) use ($places) { + return number_format($value, $places, '.', ','); + }; + + return $this; + } } From 81166415c08b0a42763d4a48b3d0c4c17ed21314 Mon Sep 17 00:00:00 2001 From: Siddhartha Mehta Date: Tue, 16 Nov 2021 16:36:52 +0530 Subject: [PATCH 116/217] Set Default places to 0 --- src/NumberColumn.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/NumberColumn.php b/src/NumberColumn.php index f4c3dcb9..8ecf1aa6 100644 --- a/src/NumberColumn.php +++ b/src/NumberColumn.php @@ -19,8 +19,7 @@ public function round($places = 0) return $this; } - // formats & rounds a number with grouped thousands - 1000000 => 1,000,000.00 (If places set to 2) - public function format($places = 2) + public function format($places = 0) { $this->callback = function ($value) use ($places) { From 2ef864de48a1dbd142b7c74d6cb25aeeb95b67f6 Mon Sep 17 00:00:00 2001 From: Siddhartha Mehta Date: Tue, 16 Nov 2021 16:41:30 +0530 Subject: [PATCH 117/217] Update NumberColumn.php --- src/NumberColumn.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NumberColumn.php b/src/NumberColumn.php index 8ecf1aa6..49c5bccf 100644 --- a/src/NumberColumn.php +++ b/src/NumberColumn.php @@ -21,7 +21,6 @@ public function round($places = 0) public function format($places = 0) { - $this->callback = function ($value) use ($places) { return number_format($value, $places, '.', ','); }; From 141f40755d9fea1424b1a02cb22dc90966de0766 Mon Sep 17 00:00:00 2001 From: Chris Allen Date: Thu, 9 Dec 2021 22:36:30 +0000 Subject: [PATCH 118/217] Move highlight call before export callback calls. The highlight call is currently executed after the export callback, making it impossible to strip out the highlighting markup that is added for search results. Moving the highlighting before the export callbacks resolves this. --- src/Http/Livewire/LivewireDatatable.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 6d76e41d..08f5f5f3 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1380,6 +1380,10 @@ public function mapCallbacks($paginatedCollection, $export = false) { $paginatedCollection->collect()->map(function ($row, $i) use ($export) { foreach ($row as $name => $value) { + if ($this->search && ! config('livewire-datatables.suppress_search_highlights') && $this->searchableColumns()->firstWhere('name', $name)) { + $row->$name = $this->highlight($row->$name, $this->search); + } + if ($export && isset($this->export_callbacks[$name])) { $values = Str::contains($value, static::SEPARATOR) ? explode(static::SEPARATOR, $value) : [$value, $row]; $row->$name = $this->export_callbacks[$name](...$values); @@ -1399,10 +1403,6 @@ public function mapCallbacks($paginatedCollection, $export = false) } elseif (isset($this->callbacks[$name]) && is_callable($this->callbacks[$name])) { $row->$name = $this->callbacks[$name]($value, $row); } - - if ($this->search && ! config('livewire-datatables.suppress_search_highlights') && $this->searchableColumns()->firstWhere('name', $name)) { - $row->$name = $this->highlight($row->$name, $this->search); - } } return $row; From 19abc3579d85a23359078ab10213dc8cc6631555 Mon Sep 17 00:00:00 2001 From: Chris Allen Date: Thu, 9 Dec 2021 22:36:30 +0000 Subject: [PATCH 119/217] Move highlight call before export callback calls. The highlight call is currently executed after the export callback, making it impossible to strip out the highlighting markup that is added for search results. Moving the highlighting before the export callbacks resolves this. --- src/Http/Livewire/LivewireDatatable.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 08f5f5f3..3c3f19e2 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -1383,7 +1383,6 @@ public function mapCallbacks($paginatedCollection, $export = false) if ($this->search && ! config('livewire-datatables.suppress_search_highlights') && $this->searchableColumns()->firstWhere('name', $name)) { $row->$name = $this->highlight($row->$name, $this->search); } - if ($export && isset($this->export_callbacks[$name])) { $values = Str::contains($value, static::SEPARATOR) ? explode(static::SEPARATOR, $value) : [$value, $row]; $row->$name = $this->export_callbacks[$name](...$values); From f2e93740a14fa91fc48335d609db32517bc9b948 Mon Sep 17 00:00:00 2001 From: Aghits Nidallah Date: Wed, 5 Jan 2022 21:07:07 +0700 Subject: [PATCH 120/217] Add "Row Index" column type (#363) * feat: row index column * fix: style * Apply fixes from StyleCI Co-authored-by: NikarashiHatsu Co-authored-by: StyleCI Bot --- src/Column.php | 13 +++++++++++++ src/Http/Livewire/LivewireDatatable.php | 3 +++ 2 files changed, 16 insertions(+) diff --git a/src/Column.php b/src/Column.php index 8578111e..976ede08 100644 --- a/src/Column.php +++ b/src/Column.php @@ -4,6 +4,7 @@ use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; +use Mediconesystems\LivewireDatatables\Http\Livewire\LivewireDatatable; class Column { @@ -57,6 +58,18 @@ public static function name($name) return $column; } + public static function index(LivewireDatatable $datatable, $attribute = 'id') + { + $column = new static; + $column->name = $attribute; + $column->label = '#'; + $column->callback = function () use ($datatable) { + return $datatable->page * $datatable->perPage - $datatable->perPage + $datatable->row++; + }; + + return $column; + } + public static function raw($raw) { $column = new static; diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 6d76e41d..63b36ed3 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -66,6 +66,7 @@ class LivewireDatatable extends Component public $persistSort = true; public $persistPerPage = true; public $persistFilters = true; + public $row = 1; /** * @var array List your groups and the corresponding label (or translation) here. @@ -941,6 +942,8 @@ public function getPaginationControlsProperty() public function getResultsProperty() { + $this->row = 1; + return $this->mapCallbacks( $this->getQuery()->paginate($this->perPage) ); From 95f25bf6454de07d8857cf8a924b148f7e7a01e3 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Wed, 5 Jan 2022 15:18:23 +0100 Subject: [PATCH 121/217] introduce possibility to persist search string in session (#360) Co-authored-by: Herbert Maschke --- README.md | 6 +- src/Http/Livewire/LivewireDatatable.php | 82 ++++++++++++++++++++----- 2 files changed, 71 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index d905b1f7..58ccb9ed 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ somewhere in your CSS ```html ... - + ... ``` @@ -62,11 +62,14 @@ somewhere in your CSS ```html ``` +- *Attention*: Please note that having multiple datatables on the same page _or_ more than one datatable of the same type on different pages needs to have a unique `name` attribute assigned to each one so they do not conflict with each other as in the example above. + ### Props | Property | Arguments | Result | Example | |----|----|----|----| @@ -100,7 +103,6 @@ somewhere in your CSS ### Declare a public method ```columns``` that returns an array containing one or more ```Mediconesystems\LivewireDatatables\Column``` - ## Columns Columns can be built using any of the static methods below, and then their attributes assigned using fluent method chains. There are additional specific types of Column; ```NumberColumn```, ```DateColumn```, ```TimeColumn```, using the correct one for your datatype will enable type-specific formatting and filtering: diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 63b36ed3..072bfd0b 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -61,7 +61,8 @@ class LivewireDatatable extends Component public $name; public $columnGroups = []; public $userFilter; - public $persistComplexQuery; + public $persistSearch = true; + public $persistComplexQuery = true; public $persistHiddenColumns = true; public $persistSort = true; public $persistPerPage = true; @@ -128,7 +129,18 @@ public function applyToTable($options) } } - foreach (['perPage', 'search', 'activeSelectFilters', 'activeDateFilters', 'activeTimeFilters', 'activeBooleanFilters', 'activeTextFilters', 'activeNumberFilters', 'hide', 'selected'] as $property) { + foreach ([ + 'perPage', + 'search', + 'activeSelectFilters', + 'activeDateFilters', + 'activeTimeFilters', + 'activeBooleanFilters', + 'activeTextFilters', + 'activeNumberFilters', + 'hide', + 'selected', + ] as $property) { if (isset($options[$property])) { $this->$property = $options[$property]; } @@ -176,7 +188,22 @@ public function mount( $afterTableSlot = false, $params = [] ) { - foreach (['model', 'include', 'exclude', 'hide', 'dates', 'times', 'searchable', 'sort', 'hideHeader', 'hidePagination', 'exportable', 'hideable', 'beforeTableSlot', 'afterTableSlot'] as $property) { + foreach ([ + 'model', + 'include', + 'exclude', + 'hide', + 'dates', + 'times', + 'searchable', + 'sort', + 'hideHeader', + 'hidePagination', + 'exportable', + 'hideable', + 'beforeTableSlot', + 'afterTableSlot', + ] as $property) { $this->$property = $this->$property ?? $$property; } @@ -184,6 +211,7 @@ public function mount( $this->columns = $this->getViewColumns(); + $this->initialiseSearch(); $this->initialiseSort(); $this->initialiseHiddenColumns(); $this->initialiseFilters(); @@ -191,6 +219,16 @@ public function mount( $this->initialiseColumnGroups(); } + // save settings + public function dehydrate() + { + if ($this->persistSearch) { + session()->put($this->sessionStorageKey() . '_search', $this->search); + } + + return parent::dehydrate(); // @phpstan-ignore-line + } + public function columns() { return $this->modelInstance; @@ -466,7 +504,7 @@ public function getFreshColumnsProperty() public function sessionStorageKey() { - return Str::snake(Str::afterLast(get_called_class(), '\\')); + return Str::snake(Str::afterLast(get_called_class(), '\\')) . $this->name; } public function getSessionStoredSort() @@ -475,8 +513,8 @@ public function getSessionStoredSort() return; } - $this->sort = session()->get($this->sessionStorageKey() . $this->name . '_sort', $this->sort); - $this->direction = session()->get($this->sessionStorageKey() . $this->name . '_direction', $this->direction); + $this->sort = session()->get($this->sessionStorageKey() . '_sort', $this->sort); + $this->direction = session()->get($this->sessionStorageKey() . '_direction', $this->direction); } public function getSessionStoredPerPage() @@ -494,7 +532,10 @@ public function setSessionStoredSort() return; } - session()->put([$this->sessionStorageKey() . $this->name . '_sort' => $this->sort, $this->sessionStorageKey() . $this->name . '_direction' => $this->direction]); + session()->put([ + $this->sessionStorageKey() . '_sort' => $this->sort, + $this->sessionStorageKey() . '_direction' => $this->direction, + ]); } public function setSessionStoredFilters() @@ -504,7 +545,7 @@ public function setSessionStoredFilters() } session()->put([ - $this->sessionStorageKey() . $this->name . '_filter' => [ + $this->sessionStorageKey() . '_filter' => [ 'text' => $this->activeTextFilters, 'boolean' => $this->activeBooleanFilters, 'select' => $this->activeSelectFilters, @@ -515,6 +556,15 @@ public function setSessionStoredFilters() ]); } + public function initialiseSearch() + { + if (! $this->persistSearch) { + return; + } + + $this->search = session()->get($this->sessionStorageKey() . '_search', $this->search); + } + public function initialiseSort() { $this->sort = $this->defaultSort() @@ -533,9 +583,9 @@ public function initialiseHiddenColumns() return; } - if (session()->has($this->sessionStorageKey() . $this->name . '_hidden_columns')) { + if (session()->has($this->sessionStorageKey() . '_hidden_columns')) { $this->columns = collect($this->columns)->map(function ($column, $index) { - $column['hidden'] = in_array($index, session()->get($this->sessionStorageKey() . $this->name . '_hidden_columns')); + $column['hidden'] = in_array($index, session()->get($this->sessionStorageKey() . '_hidden_columns')); return $column; })->toArray(); @@ -566,7 +616,7 @@ public function initialiseFilters() return; } - $filters = session()->get($this->sessionStorageKey() . $this->name . '_filter'); + $filters = session()->get($this->sessionStorageKey() . '_filter'); $this->activeBooleanFilters = $filters['boolean'] ?? []; $this->activeSelectFilters = $filters['select'] ?? []; @@ -652,8 +702,10 @@ public function sort($index, $direction = null) } $this->page = 1; - $key = Str::snake(Str::afterLast(get_called_class(), '\\')); - session()->put([$key . $this->name . '_sort' => $this->sort, $key . $this->name . '_direction' => $this->direction]); + session()->put([ + $this->sessionStorageKey() . '_sort' => $this->sort, + $this->sessionStorageKey() . '_direction' => $this->direction, + ]); } public function toggle($index) @@ -671,7 +723,7 @@ public function toggle($index) if ($this->persistHiddenColumns) { $hidden = collect($this->columns)->filter->hidden->keys()->toArray(); - session()->put([$this->sessionStorageKey() . $this->name . '_hidden_columns' => $hidden]); + session()->put([$this->sessionStorageKey() . '_hidden_columns' => $hidden]); } } @@ -1475,7 +1527,7 @@ public function render() $this->emit('refreshDynamic'); if ($this->persistPerPage) { - session()->put([$this->sessionStorageKey() . $this->name . '_perpage' => $this->perPage]); + session()->put([$this->sessionStorageKey() . '_perpage' => $this->perPage]); } return view('datatables::datatable')->layoutData(['title' => $this->title]); From f1873c5e7ad05fdd391b73612db2bcac619074d1 Mon Sep 17 00:00:00 2001 From: Dimas Galih Date: Wed, 5 Jan 2022 21:20:29 +0700 Subject: [PATCH 122/217] Rename export file (#341) * Rename export file * Update LivewireDatatable.php Co-authored-by: dimas --- src/Http/Livewire/LivewireDatatable.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 072bfd0b..52fdbb90 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -50,6 +50,7 @@ class LivewireDatatable extends Component public $times; public $searchable; public $exportable; + public $export_name; public $hideable; public $params; public $selected = []; @@ -183,6 +184,7 @@ public function mount( $hidePagination = null, $perPage = null, $exportable = false, + $export_name = null, $hideable = false, $beforeTableSlot = false, $afterTableSlot = false, @@ -1550,7 +1552,7 @@ public function export() })->all(); }); - return Excel::download(new DatatableExport($results), 'DatatableExport.xlsx'); + return Excel::download(new DatatableExport($results), $this->export_name ? $this->export_name . '.xlsx' : 'DatatableExport.xlsx'); } public function getQuery($export = false) From 955dd929dde804d4677be56def634d1218f480d5 Mon Sep 17 00:00:00 2001 From: Marion <80384302+marionfromfrance@users.noreply.github.com> Date: Wed, 5 Jan 2022 15:24:50 +0100 Subject: [PATCH 123/217] [contribution-issue-315] Fix column filtering while on page > 1 (marionfromfrance) (#319) Co-authored-by: Marion MJI --- src/Http/Livewire/LivewireDatatable.php | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Http/Livewire/LivewireDatatable.php b/src/Http/Livewire/LivewireDatatable.php index 52fdbb90..d12b5e61 100644 --- a/src/Http/Livewire/LivewireDatatable.php +++ b/src/Http/Livewire/LivewireDatatable.php @@ -155,7 +155,7 @@ public function resetTable() { $this->perPage = config('livewire-datatables.default_per_page', 10); $this->search = null; - $this->page = 1; + $this->setPage(1); $this->activeSelectFilters = []; $this->activeDateFilters = []; $this->activeTimeFilters = []; @@ -168,7 +168,7 @@ public function resetTable() public function updatedSearch() { - $this->page = 1; + $this->setPage(1); } public function mount( @@ -677,7 +677,7 @@ public function updatingPerPage() public function refreshLivewireDatatable() { - $this->page = 1; + $this->setPage(1); } /** @@ -702,7 +702,7 @@ public function sort($index, $direction = null) } else { $this->sort = (int) $index; } - $this->page = 1; + $this->setPage(1); session()->put([ $this->sessionStorageKey() . '_sort' => $this->sort, @@ -769,14 +769,14 @@ public function isGroupHidden($group) public function doBooleanFilter($index, $value) { $this->activeBooleanFilters[$index] = $value; - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } public function doSelectFilter($index, $value) { $this->activeSelectFilters[$index][] = $value; - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } @@ -786,35 +786,35 @@ public function doTextFilter($index, $value) $this->activeTextFilters[$index][] = $val; } - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } public function doDateFilterStart($index, $start) { $this->activeDateFilters[$index]['start'] = $start; - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } public function doDateFilterEnd($index, $end) { $this->activeDateFilters[$index]['end'] = $end; - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } public function doTimeFilterStart($index, $start) { $this->activeTimeFilters[$index]['start'] = $start; - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } public function doTimeFilterEnd($index, $end) { $this->activeTimeFilters[$index]['end'] = $end; - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } @@ -822,7 +822,7 @@ public function doNumberFilterStart($index, $start) { $this->activeNumberFilters[$index]['start'] = ($start != '') ? (int) $start : null; $this->clearEmptyNumberFilter($index); - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } @@ -830,7 +830,7 @@ public function doNumberFilterEnd($index, $end) { $this->activeNumberFilters[$index]['end'] = ($end != '') ? (int) $end : null; $this->clearEmptyNumberFilter($index); - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } @@ -839,7 +839,7 @@ public function clearEmptyNumberFilter($index) if ((! isset($this->activeNumberFilters[$index]['start']) || $this->activeNumberFilters[$index]['start'] == '') && (! isset($this->activeNumberFilters[$index]['end']) || $this->activeNumberFilters[$index]['end'] == '')) { $this->removeNumberFilter($index); } - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } @@ -849,7 +849,7 @@ public function removeSelectFilter($column, $key = null) if (count($this->activeSelectFilters[$column]) < 1) { unset($this->activeSelectFilters[$column]); } - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); } @@ -863,7 +863,7 @@ public function clearAllFilters() $this->activeNumberFilters = []; $this->complexQuery = null; $this->userFilter = null; - $this->page = 1; + $this->setPage(1); $this->setSessionStoredFilters(); $this->emitTo('complex-query', 'resetQuery'); @@ -1099,7 +1099,7 @@ public function addComplexQuery() $this->processNested($this->complexQuery, $query); }); - $this->page = 1; + $this->setPage(1); return $this; } From c07ed81e1859a55349976767dcfddba8d54d4814 Mon Sep 17 00:00:00 2001 From: Herbert Maschke Date: Wed, 5 Jan 2022 15:26:20 +0100 Subject: [PATCH 124/217] introduce min-width and max-width (#310) Co-authored-by: Herbert Maschke --- .../datatables/header-inline-hide.blade.php | 4 +-- .../datatables/header-no-hide.blade.php | 2 +- .../livewire/datatables/style-width.blade.php | 3 ++ src/Column.php | 32 +++++++++++++++++++ src/Http/Livewire/LivewireDatatable.php | 2 ++ 5 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 resources/views/livewire/datatables/style-width.blade.php diff --git a/resources/views/livewire/datatables/header-inline-hide.blade.php b/resources/views/livewire/datatables/header-inline-hide.blade.php index 14b86c83..59cf268c 100644 --- a/resources/views/livewire/datatables/header-inline-hide.blade.php +++ b/resources/views/livewire/datatables/header-inline-hide.blade.php @@ -13,8 +13,8 @@ class="w-32 hidden group-hover:inline-block absolute z-10 top-0 left-0 ml-3 bg-b
-