From 2675c649b75b14b2f6e920a6a9e04582539082de Mon Sep 17 00:00:00 2001 From: Simon Barrett Date: Thu, 19 Oct 2023 10:09:12 +0200 Subject: [PATCH 1/5] :add table class --- resources/views/table.blade.php | 83 +++++++++++++++++++++++++++++++++ src/Table.php | 82 ++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 resources/views/table.blade.php create mode 100755 src/Table.php diff --git a/resources/views/table.blade.php b/resources/views/table.blade.php new file mode 100644 index 0000000..45b907e --- /dev/null +++ b/resources/views/table.blade.php @@ -0,0 +1,83 @@ +
+ + @if($this->rows->count()) + +
+ + + + + @foreach ($this->columns() as $column) + + @endforeach + + + + + @foreach ($this->rows as $row) + isClickable()) + wire:click="rowClick('{{ $row->id }}')" + @endif + wire:key="row-{{ $row->id }}" + @class([ + 'bg-white border-b', + 'hover:bg-gray-50 cursor-pointer' => $this->isClickable(), + ])> + + @foreach ($this->columns() as $column) + + @endforeach + + @endforeach + +
isSortable()) wire:click="sort('{{ $column->key }}')" @endif> + @if ($column->showHeader) +
justify, + 'cursor-pointer' => $column->isSortable(), + ])> + {{ $column->label }} + + @if ($sortBy === $column->key) + @if ($sortDirection === 'asc') + + + + @else + + + + @endif + @endif + +
+ @endif +
+
+ + +
+
+
+ + @if($this->rows->hasPages()) +
+
{{ $this->rows->links() }}
+
+ @endif + @endif + +
diff --git a/src/Table.php b/src/Table.php new file mode 100755 index 0000000..cafa4b0 --- /dev/null +++ b/src/Table.php @@ -0,0 +1,82 @@ + '$refresh', + ]; + + protected $queryString = ['perPage']; + + abstract public function query(): Builder; + + public function booted(): void + { + $this->config(); + + } + + public function config(): void + { + // + } + + + public function getRowsQueryProperty() + { + return $this->query()->when($this->sortBy !== '', function ($query) { + $query->orderBy($this->sortBy, $this->sortDirection); + }); + } + + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function getRowsProperty() + { + return $this->applyPagination($this->rowsQuery); + } + + protected function model(): Model + { + $model = $this->model; + + return app($model); + } + + public function render(): Factory|View + { + return view('query-builder::table'); + } +} From c23f647e4593fc93550e3c1adbb90a38dc102c8c Mon Sep 17 00:00:00 2001 From: SimonBarrettACT Date: Thu, 19 Oct 2023 08:09:54 +0000 Subject: [PATCH 2/5] Fix styling --- src/Table.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Table.php b/src/Table.php index cafa4b0..f194e58 100755 --- a/src/Table.php +++ b/src/Table.php @@ -4,17 +4,10 @@ namespace ACTTraining\QueryBuilder; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Collection\CriteriaCollection; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithActions; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithCaching; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithColumns; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithPagination; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithQueryBuilder; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithRowClick; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithSearch; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithSelecting; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithSorting; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithToolbar; use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Builder; @@ -51,10 +44,9 @@ public function config(): void // } - public function getRowsQueryProperty() { - return $this->query()->when($this->sortBy !== '', function ($query) { + return $this->query()->when($this->sortBy !== '', function ($query) { $query->orderBy($this->sortBy, $this->sortDirection); }); } From 08c70e52df2d90de99fabd7354107bda5fc183e4 Mon Sep 17 00:00:00 2001 From: Simon Barrett Date: Thu, 19 Oct 2023 16:21:40 +0200 Subject: [PATCH 3/5] :construction: add filters --- resources/views/editor.blade.php | 3 +- resources/views/filters.blade.php | 11 ++ resources/views/filters/boolean.blade.php | 8 + resources/views/filters/date.blade.php | 10 ++ resources/views/filters/text.blade.php | 4 + resources/views/table.blade.php | 143 ++++++++++-------- .../QueryBuilder/Concerns/WithFilters.php | 40 +++++ .../QueryBuilder/Concerns/WithPagination.php | 2 +- .../QueryBuilder/Filters/BaseFilter.php | 80 ++++++++++ .../QueryBuilder/Filters/BooleanFilter.php | 21 +++ .../QueryBuilder/Filters/DateFilter.php | 15 ++ .../QueryBuilder/Filters/NumberFilter.php | 7 + .../QueryBuilder/Filters/SelectFilter.php | 7 + .../QueryBuilder/Filters/TextFilter.php | 15 ++ src/QueryBuilder.php | 2 + src/Table.php | 38 +++-- 16 files changed, 325 insertions(+), 81 deletions(-) create mode 100644 resources/views/filters.blade.php create mode 100644 resources/views/filters/boolean.blade.php create mode 100644 resources/views/filters/date.blade.php create mode 100644 resources/views/filters/text.blade.php create mode 100644 src/Http/Livewire/QueryBuilder/Concerns/WithFilters.php create mode 100644 src/Http/Livewire/QueryBuilder/Filters/BaseFilter.php create mode 100644 src/Http/Livewire/QueryBuilder/Filters/BooleanFilter.php create mode 100644 src/Http/Livewire/QueryBuilder/Filters/DateFilter.php create mode 100644 src/Http/Livewire/QueryBuilder/Filters/NumberFilter.php create mode 100644 src/Http/Livewire/QueryBuilder/Filters/SelectFilter.php create mode 100644 src/Http/Livewire/QueryBuilder/Filters/TextFilter.php diff --git a/resources/views/editor.blade.php b/resources/views/editor.blade.php index 2df66a5..70c87aa 100644 --- a/resources/views/editor.blade.php +++ b/resources/views/editor.blade.php @@ -1,8 +1,7 @@
@if (! count($criteria)) -
+
Add a new condition diff --git a/resources/views/filters.blade.php b/resources/views/filters.blade.php new file mode 100644 index 0000000..33a94da --- /dev/null +++ b/resources/views/filters.blade.php @@ -0,0 +1,11 @@ +
+ @foreach($this->filters() as $filter) + @include('query-builder::filters.' . $filter->component()) + @endforeach +
+
+ +
\ No newline at end of file diff --git a/resources/views/filters/boolean.blade.php b/resources/views/filters/boolean.blade.php new file mode 100644 index 0000000..ddab435 --- /dev/null +++ b/resources/views/filters/boolean.blade.php @@ -0,0 +1,8 @@ +
+ + +
\ No newline at end of file diff --git a/resources/views/filters/date.blade.php b/resources/views/filters/date.blade.php new file mode 100644 index 0000000..9f0b91b --- /dev/null +++ b/resources/views/filters/date.blade.php @@ -0,0 +1,10 @@ +
+ + +
+ diff --git a/resources/views/filters/text.blade.php b/resources/views/filters/text.blade.php new file mode 100644 index 0000000..0b1b73f --- /dev/null +++ b/resources/views/filters/text.blade.php @@ -0,0 +1,4 @@ +
+ + +
\ No newline at end of file diff --git a/resources/views/table.blade.php b/resources/views/table.blade.php index 45b907e..f014caa 100644 --- a/resources/views/table.blade.php +++ b/resources/views/table.blade.php @@ -1,83 +1,92 @@
- @if($this->rows->count()) +
+ @if ($this->areFiltersAvailable()) +
+ @include('query-builder::filters') +
+ @endif +
-
- - - +
+ @if($this->rows->count()) - @foreach ($this->columns() as $column) -
+ + + @foreach ($this->rows as $row) + isClickable()) + wire:click="rowClick('{{ $row->id }}')" + @endif + wire:key="row-{{ $row->id }}" + @class([ + 'bg-white border-b', + 'hover:bg-gray-50 cursor-pointer' => $this->isClickable(), + ])> - @if($this->rows->hasPages()) -
-
{{ $this->rows->links() }}
+ @foreach ($this->columns() as $column) +
+ @endforeach + + @endforeach + +
isSortable()) wire:click="sort('{{ $column->key }}')" @endif> - @if ($column->showHeader) -
+ + + + + @foreach ($this->columns() as $column) + - @endforeach - - - - @foreach ($this->rows as $row) - isClickable()) - wire:click="rowClick('{{ $row->id }}')" - @endif - wire:key="row-{{ $row->id }}" - @class([ - 'bg-white border-b', - 'hover:bg-gray-50 cursor-pointer' => $this->isClickable(), - ])> - - @foreach ($this->columns() as $column) - + + @endif + @endforeach - @endforeach - -
isSortable()) wire:click="sort('{{ $column->key }}')" @endif> + @if ($column->showHeader) +
justify, 'cursor-pointer' => $column->isSortable(), ])> - {{ $column->label }} + {{ $column->label }} - @if ($sortBy === $column->key) - @if ($sortDirection === 'asc') - - - - @else - - - + @if ($sortBy === $column->key) + @if ($sortDirection === 'asc') + + + + @else + + + + @endif @endif - @endif - -
- @endif -
-
- - -
-
-
+
+
+ + +
+
- @endif - @endif + @if($this->rows->hasPages()) +
+
{{ $this->rows->links() }}
+
+ @endif + @endif +
diff --git a/src/Http/Livewire/QueryBuilder/Concerns/WithFilters.php b/src/Http/Livewire/QueryBuilder/Concerns/WithFilters.php new file mode 100644 index 0000000..4c16959 --- /dev/null +++ b/src/Http/Livewire/QueryBuilder/Concerns/WithFilters.php @@ -0,0 +1,40 @@ +displayFilters && count($this->filters()) > 0; + } + + public function displayFilters(bool $displayFilters = true): static + { + $this->displayFilters = $displayFilters; + + return $this; + } + + public function filters(): array + { + return [ + TextFilter::make('Name', 'full_name')->useOperator('like'), + BooleanFilter::make('Line Manager', 'contract.line_manager'), + DateFilter::make('Start Date', 'contract.start_date')->useOperator('<='), + ]; + } + + public function resetFilters(): void + { + $this->filterValues = []; + } +} diff --git a/src/Http/Livewire/QueryBuilder/Concerns/WithPagination.php b/src/Http/Livewire/QueryBuilder/Concerns/WithPagination.php index d541310..0388ded 100644 --- a/src/Http/Livewire/QueryBuilder/Concerns/WithPagination.php +++ b/src/Http/Livewire/QueryBuilder/Concerns/WithPagination.php @@ -13,7 +13,7 @@ trait WithPagination public function applyPagination($query) { if ($this->paginate) { - return $query->paginate($this->perPage); + return $query->ray()->paginate($this->perPage); } else { return $query->get(); } diff --git a/src/Http/Livewire/QueryBuilder/Filters/BaseFilter.php b/src/Http/Livewire/QueryBuilder/Filters/BaseFilter.php new file mode 100644 index 0000000..ebcf556 --- /dev/null +++ b/src/Http/Livewire/QueryBuilder/Filters/BaseFilter.php @@ -0,0 +1,80 @@ +key = $key; + $this->label = $label; + $this->code = $label.':'.$this->operator; + } + + public static function make($label, $key = null): static + { + if (is_null($key)) { + $key = Str::snake($label); + } + + return new static($key, $label); + } + + public function label(): string + { + return $this->label; + } + + public function key(): string + { + return $this->key; + } + + public function operator(): string + { + return $this->operator; + } + + public function code(): string + { + return $this->code; + } + + public function component(): string + { + return $this->component; + } + + public function useOperator(string $operator): static + { + $this->operator = $operator; + $this->code = $this->label.':'.$this->operator; + + return $this; + } + + public function useComponent(string $component): static + { + $this->component = $component; + + return $this; + } + + public function parseValue($value) + { + return $value; + } +} diff --git a/src/Http/Livewire/QueryBuilder/Filters/BooleanFilter.php b/src/Http/Livewire/QueryBuilder/Filters/BooleanFilter.php new file mode 100644 index 0000000..b4b23c3 --- /dev/null +++ b/src/Http/Livewire/QueryBuilder/Filters/BooleanFilter.php @@ -0,0 +1,21 @@ +startOfDay(); + } +} diff --git a/src/Http/Livewire/QueryBuilder/Filters/NumberFilter.php b/src/Http/Livewire/QueryBuilder/Filters/NumberFilter.php new file mode 100644 index 0000000..1acaa4b --- /dev/null +++ b/src/Http/Livewire/QueryBuilder/Filters/NumberFilter.php @@ -0,0 +1,7 @@ +operator() === 'like') { + return "%{$value}%"; + } + + return $value; + } +} diff --git a/src/QueryBuilder.php b/src/QueryBuilder.php index d91609d..3ed8281 100755 --- a/src/QueryBuilder.php +++ b/src/QueryBuilder.php @@ -8,6 +8,7 @@ use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithActions; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithCaching; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithColumns; +use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithFilters; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithPagination; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithQueryBuilder; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithRowClick; @@ -28,6 +29,7 @@ abstract class QueryBuilder extends Component use WithActions; use WithCaching; use WithColumns; + use WithFilters; use WithPagination; use WithQueryBuilder; use WithRowClick; diff --git a/src/Table.php b/src/Table.php index cafa4b0..9cfc0b9 100755 --- a/src/Table.php +++ b/src/Table.php @@ -4,21 +4,17 @@ namespace ACTTraining\QueryBuilder; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Collection\CriteriaCollection; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithActions; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithCaching; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithColumns; +use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithFilters; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithPagination; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithQueryBuilder; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithRowClick; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithSearch; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithSelecting; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithSorting; -use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithToolbar; use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Arr; +use Illuminate\Support\Str; use Livewire\Component; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; @@ -26,6 +22,7 @@ abstract class Table extends Component { use WithColumns; + use WithFilters; use WithPagination; use WithRowClick; use WithSorting; @@ -36,8 +33,6 @@ abstract class Table extends Component 'refreshTable' => '$refresh', ]; - protected $queryString = ['perPage']; - abstract public function query(): Builder; public function booted(): void @@ -51,12 +46,33 @@ public function config(): void // } - public function getRowsQueryProperty() { - return $this->query()->when($this->sortBy !== '', function ($query) { + $query = $this->query()->when($this->sortBy !== '', function ($query) { $query->orderBy($this->sortBy, $this->sortDirection); }); + + $dottedFilterValue = Arr::dot($this->filterValues); + + foreach ($this->filters() as $filter) { + $value = $dottedFilterValue[$filter->code()] ?? null; + + $query->when($value !== null, function ($query) use ($filter, $value) { + $value = $filter->parseValue($value); + if (Str::contains($filter->key(), '.')) { + $relation = Str::beforeLast($filter->key(), '.'); + $column = Str::afterLast($filter->key(), '.'); + + $query->whereHas($relation, function ($query) use ($filter, $value, $column) { + $query->where($column, $filter->operator(), $value); + }); + } else { + $query->where($filter->key(), $filter->operator(), $value); + } + }); + } + + return $query; } /** From fb5e69e065dd0bc2d8cee18e19edeacd67afaf04 Mon Sep 17 00:00:00 2001 From: Simon Barrett Date: Thu, 19 Oct 2023 16:43:01 +0200 Subject: [PATCH 4/5] :sparkles: add filters --- resources/views/filters/select.blade.php | 11 +++++++++++ .../QueryBuilder/Concerns/WithFilters.php | 14 +++++++++++++- .../QueryBuilder/Filters/SelectFilter.php | 15 +++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 resources/views/filters/select.blade.php diff --git a/resources/views/filters/select.blade.php b/resources/views/filters/select.blade.php new file mode 100644 index 0000000..63ead61 --- /dev/null +++ b/resources/views/filters/select.blade.php @@ -0,0 +1,11 @@ +
+ + +
\ No newline at end of file diff --git a/src/Http/Livewire/QueryBuilder/Concerns/WithFilters.php b/src/Http/Livewire/QueryBuilder/Concerns/WithFilters.php index 4c16959..0e32984 100644 --- a/src/Http/Livewire/QueryBuilder/Concerns/WithFilters.php +++ b/src/Http/Livewire/QueryBuilder/Concerns/WithFilters.php @@ -4,6 +4,7 @@ use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters\BooleanFilter; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters\DateFilter; +use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters\SelectFilter; use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters\TextFilter; trait WithFilters @@ -28,13 +29,24 @@ public function filters(): array { return [ TextFilter::make('Name', 'full_name')->useOperator('like'), + SelectFilter::make('Location', 'contract.location.name')->withOptions([ + 'ACT Skills Centre, Caerphilly' => 'ACT Skills Centre, Caerphilly', + 'Home Based' => 'Home Based', + ]), BooleanFilter::make('Line Manager', 'contract.line_manager'), - DateFilter::make('Start Date', 'contract.start_date')->useOperator('<='), + DateFilter::make('Started on or after', 'contract.start_date')->useOperator('>='), + DateFilter::make('Started on or before', 'contract.start_date')->useOperator('<='), ]; } public function resetFilters(): void { $this->filterValues = []; + $this->resetPage(); + } + + public function updatedFilterValues(): void + { + $this->resetPage(); } } diff --git a/src/Http/Livewire/QueryBuilder/Filters/SelectFilter.php b/src/Http/Livewire/QueryBuilder/Filters/SelectFilter.php index d6e8db0..a28c69d 100644 --- a/src/Http/Livewire/QueryBuilder/Filters/SelectFilter.php +++ b/src/Http/Livewire/QueryBuilder/Filters/SelectFilter.php @@ -4,4 +4,19 @@ class SelectFilter extends BaseFilter { + public $options = []; + + public string $component = 'select'; + + public function options() + { + return $this->options; + } + + public function withOptions(array $options = []): static + { + $this->options = $options; + + return $this; + } } From 56ac8922d48b9ef9ff94bf3841351caf223ada8a Mon Sep 17 00:00:00 2001 From: Simon Barrett Date: Thu, 19 Oct 2023 17:36:03 +0200 Subject: [PATCH 5/5] :sparkles: add loading indicator --- resources/views/table.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/table.blade.php b/resources/views/table.blade.php index f014caa..079a5f6 100644 --- a/resources/views/table.blade.php +++ b/resources/views/table.blade.php @@ -51,7 +51,7 @@ @endforeach - + @foreach ($this->rows as $row) isClickable())