$component->isBootstrap(),
'w-full md:w-auto mb-4 md:mb-0' => $component->isTailwind(),
From ce95a70af99ba2cd36063c04ca44eae6d8c7a2a1 Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Mon, 1 Jul 2024 13:25:08 +0100
Subject: [PATCH 06/21] Change Return Type for attributes() to static (#1749)
---
src/Views/Traits/Core/HasAttributes.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Views/Traits/Core/HasAttributes.php b/src/Views/Traits/Core/HasAttributes.php
index 2707b8671..2978d5822 100644
--- a/src/Views/Traits/Core/HasAttributes.php
+++ b/src/Views/Traits/Core/HasAttributes.php
@@ -11,7 +11,7 @@ trait HasAttributes
{
protected ?Closure $attributesCallback = null;
- public function attributes(Closure $callback): self
+ public function attributes(Closure $callback): static
{
$this->attributesCallback = $callback;
From 5c404729e9e28e991bb807fd4b0d104d48d7feca Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Mon, 1 Jul 2024 13:25:22 +0100
Subject: [PATCH 07/21] Switch to using Composer\InstalledVersions for
AboutCommand to reduce necessity to update ServiceProvider with each update
(#1748)
---
src/LaravelLivewireTablesServiceProvider.php | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/LaravelLivewireTablesServiceProvider.php b/src/LaravelLivewireTablesServiceProvider.php
index f0a50ed70..c3c32fe2d 100644
--- a/src/LaravelLivewireTablesServiceProvider.php
+++ b/src/LaravelLivewireTablesServiceProvider.php
@@ -14,7 +14,11 @@ class LaravelLivewireTablesServiceProvider extends ServiceProvider
public function boot(): void
{
- AboutCommand::add('Rappasoft Laravel Livewire Tables', fn () => ['Version' => '3.2.7']);
+ if (class_exists(AboutCommand::class) && class_exists(\Composer\InstalledVersions::class)) {
+ AboutCommand::add('Rappasoft Laravel Livewire Tables', [
+ 'Version' => \Composer\InstalledVersions::getPrettyVersion('rappasoft/laravel-livewire-tables'),
+ ]);
+ }
$this->mergeConfigFrom(
__DIR__.'/../config/livewire-tables.php', 'livewire-tables'
From 119401b2f609bac3ce6549e8f7a4ed701a03a2da Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Mon, 1 Jul 2024 13:48:18 +0100
Subject: [PATCH 08/21] Two improvements to improve typehinting, migrate to
larastan/larastan, cleanup of test (#1750)
---
composer.json | 2 +-
phpstan.neon | 6 +++---
src/LaravelLivewireTablesServiceProvider.php | 2 +-
src/Traits/Helpers/TableAttributeHelpers.php | 4 ++--
tests/Views/Columns/LinkColumnTest.php | 6 ++----
5 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/composer.json b/composer.json
index d3e9e6372..bda267c29 100644
--- a/composer.json
+++ b/composer.json
@@ -35,7 +35,7 @@
"laravel/pint": "^1.10",
"monolog/monolog": "*",
"nunomaduro/collision": "^6.0|^7.0|^8.0",
- "nunomaduro/larastan": "^2.6",
+ "larastan/larastan": "^2.6",
"orchestra/testbench": "^7.0|^8.0|^9.0",
"phpunit/phpunit": "^9.0|^10.0|^11.0"
},
diff --git a/phpstan.neon b/phpstan.neon
index 7ed8f5027..a0324459d 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,5 +1,5 @@
includes:
- - vendor/nunomaduro/larastan/extension.neon
+ - vendor/larastan/larastan/extension.neon
parameters:
paths:
@@ -10,11 +10,11 @@ parameters:
tmpDir: build/phpstan
checkOctaneCompatibility: true
checkModelProperties: true
- checkMissingIterableValueType: false
treatPhpDocTypesAsCertain: false
reportUnmatchedIgnoredErrors: false
- checkGenericClassInNonGenericObjectType: false
ignoreErrors:
+ - identifier: missingType.generics
+ - identifier: missingType.iterableValue
- '#Access to an undefined property Rappasoft\\LaravelLivewireTables\\Views\\Column\:\:\$view#'
- "#Unsafe usage of new static#"
- '#on array\
, mixed\>\> in empty\(\) does not exist.#'
diff --git a/src/LaravelLivewireTablesServiceProvider.php b/src/LaravelLivewireTablesServiceProvider.php
index c3c32fe2d..e10027b51 100644
--- a/src/LaravelLivewireTablesServiceProvider.php
+++ b/src/LaravelLivewireTablesServiceProvider.php
@@ -44,7 +44,7 @@ public function boot(): void
}
- public function consoleCommands()
+ public function consoleCommands(): void
{
if ($this->app->runningInConsole()) {
diff --git a/src/Traits/Helpers/TableAttributeHelpers.php b/src/Traits/Helpers/TableAttributeHelpers.php
index 3da2da12e..866e72526 100644
--- a/src/Traits/Helpers/TableAttributeHelpers.php
+++ b/src/Traits/Helpers/TableAttributeHelpers.php
@@ -84,12 +84,12 @@ public function hasTableRowUrl(): bool
return $this->trUrlCallback !== null;
}
- public function getTableRowUrl($row): ?string
+ public function getTableRowUrl(int|Model $row): ?string
{
return $this->trUrlCallback ? call_user_func($this->trUrlCallback, $row) : null;
}
- public function getTableRowUrlTarget($row): ?string
+ public function getTableRowUrlTarget(int|Model $row): ?string
{
return $this->trUrlTargetCallback ? call_user_func($this->trUrlTargetCallback, $row) : null;
}
diff --git a/tests/Views/Columns/LinkColumnTest.php b/tests/Views/Columns/LinkColumnTest.php
index 4a204c0ff..d981d7aad 100644
--- a/tests/Views/Columns/LinkColumnTest.php
+++ b/tests/Views/Columns/LinkColumnTest.php
@@ -44,8 +44,7 @@ public function test_can_render_field_if_title_and_location_callback(): void
$this->assertNotEmpty($column);
}
- /** @test */
- public function can_check_ishtml_from_html_column(): void
+ public function test_can_check_ishtml_from_html_column(): void
{
$column = LinkColumn::make('Name', 'name')
->title(fn ($row) => 'Title')
@@ -55,8 +54,7 @@ public function can_check_ishtml_from_html_column(): void
$this->assertTrue($column->isHtml());
}
- /** @test */
- public function can_get_html_from_html_label_column(): void
+ public function test_can_get_html_from_html_label_column(): void
{
$column = LinkColumn::make('Name', 'name')
->title(fn ($row) => 'My Label ')
From ea2c8fc3cfa6e8c2bb808946d349147b9589bffe Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Mon, 1 Jul 2024 13:48:45 +0100
Subject: [PATCH 09/21] Add ArrayColumn (BETA) (#1751)
* Add ArrayColumn
* Fix styling
---------
Co-authored-by: lrljoe
---
src/Views/Columns/ArrayColumn.php | 31 +++++++++
.../ArrayColumnConfiguration.php | 29 ++++++++
.../Traits/Helpers/ArrayColumnHelpers.php | 69 +++++++++++++++++++
3 files changed, 129 insertions(+)
create mode 100644 src/Views/Columns/ArrayColumn.php
create mode 100644 src/Views/Traits/Configuration/ArrayColumnConfiguration.php
create mode 100644 src/Views/Traits/Helpers/ArrayColumnHelpers.php
diff --git a/src/Views/Columns/ArrayColumn.php b/src/Views/Columns/ArrayColumn.php
new file mode 100644
index 000000000..be9366db0
--- /dev/null
+++ b/src/Views/Columns/ArrayColumn.php
@@ -0,0 +1,31 @@
+';
+
+ public string $emptyValue = '';
+
+ protected mixed $dataCallback = null;
+
+ protected mixed $outputFormat = null;
+
+ public function __construct(string $title, ?string $from = null)
+ {
+ parent::__construct($title, $from);
+ if (! isset($from)) {
+ $this->label(fn () => null);
+ }
+ }
+}
diff --git a/src/Views/Traits/Configuration/ArrayColumnConfiguration.php b/src/Views/Traits/Configuration/ArrayColumnConfiguration.php
new file mode 100644
index 000000000..72188fd79
--- /dev/null
+++ b/src/Views/Traits/Configuration/ArrayColumnConfiguration.php
@@ -0,0 +1,29 @@
+separator = $value;
+
+ return $this;
+ }
+
+ public function data(callable $callable): self
+ {
+ $this->dataCallback = $callable;
+
+ return $this;
+ }
+
+ public function outputFormat(callable $callable): self
+ {
+ $this->outputFormat = $callable;
+
+ return $this;
+ }
+}
diff --git a/src/Views/Traits/Helpers/ArrayColumnHelpers.php b/src/Views/Traits/Helpers/ArrayColumnHelpers.php
new file mode 100644
index 000000000..7c32f7c70
--- /dev/null
+++ b/src/Views/Traits/Helpers/ArrayColumnHelpers.php
@@ -0,0 +1,69 @@
+separator !== null && is_string($this->separator);
+ }
+
+ public function getSeparator(): string
+ {
+ return $this->separator;
+ }
+
+ public function getEmptyValue(): string
+ {
+ return $this->emptyValue;
+ }
+
+ public function hasDataCallback(): bool
+ {
+ return isset($this->dataCallback) && is_callable($this->dataCallback);
+ }
+
+ public function getDataCallback(): ?callable
+ {
+ return $this->dataCallback;
+ }
+
+ public function hasOutputFormatCallback(): bool
+ {
+ return isset($this->outputFormat) && is_callable($this->outputFormat);
+ }
+
+ public function getOutputFormatCallback(): ?callable
+ {
+ return $this->outputFormat;
+ }
+
+ public function getContents(Model $row): null|string|\BackedEnum|HtmlString|DataTableConfigurationException|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
+ {
+ $outputValues = [];
+ $value = $this->getValue($row);
+
+ if (! $this->hasSeparator()) {
+ throw new DataTableConfigurationException('You must set a valid separator on an ArrayColumn');
+ }
+
+ if (! $this->hasDataCallback()) {
+ throw new DataTableConfigurationException('You must set a data() method on an ArrayColumn');
+ }
+
+ if (! $this->hasOutputFormatCallback()) {
+ throw new DataTableConfigurationException('You must set an outputFormat() method on an ArrayColumn');
+ }
+
+ foreach (call_user_func($this->getDataCallback(), $value, $row) as $i => $v) {
+ $outputValues[] = call_user_func($this->getOutputFormatCallback(), $i, $v);
+ }
+
+ return new HtmlString((! empty($outputValues) ? implode($this->getSeparator(), $outputValues) : $this->getEmptyValue()));
+ }
+}
From 2acac1b70c041218bf4893670ee973bca219f5c8 Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Mon, 1 Jul 2024 14:09:05 +0100
Subject: [PATCH 10/21] Always hide bulk actions option (#1752)
* Add option to "Always Hide Bulk Actions"
* Fix styling
* Fix test function name clash
---------
Co-authored-by: lrljoe
---
docs/bulk-actions/available-methods.md | 35 ++++++
.../views/components/tools/toolbar.blade.php | 2 +-
.../BulkActionsConfiguration.php | 21 ++++
src/Traits/Helpers/BulkActionsHelpers.php | 8 ++
src/Traits/WithBulkActions.php | 2 +
.../Traits/Visuals/BulkActionsVisualsTest.php | 109 ++++++++++++++++++
6 files changed, 176 insertions(+), 1 deletion(-)
diff --git a/docs/bulk-actions/available-methods.md b/docs/bulk-actions/available-methods.md
index 22b8210ee..ad98e1999 100644
--- a/docs/bulk-actions/available-methods.md
+++ b/docs/bulk-actions/available-methods.md
@@ -239,3 +239,38 @@ public function configure(): void
]);
}
```
+
+## setShouldAlwaysHideBulkActionsDropdownOption
+
+Allows hiding the Bulk Actions button & menu, regardless of whether there are any items selected, or hideBulkActionsWhenEmptyEnabled behaviour
+
+```php
+public function configure(): void
+{
+ $this->setShouldAlwaysHideBulkActionsDropdownOption(true);
+}
+```
+
+
+## setShouldAlwaysHideBulkActionsDropdownOptionEnabled
+
+Allows hiding the Bulk Actions button & menu, regardless of whether there are any items selected, or hideBulkActionsWhenEmptyEnabled behaviour
+
+```php
+public function configure(): void
+{
+ $this->setShouldAlwaysHideBulkActionsDropdownOptionEnabled();
+}
+```
+
+
+## setShouldAlwaysHideBulkActionsDropdownOptionDisabled
+
+Restores the Bulk Actions to default functionality, so it will respect the hideBulkActionsWhenEmptyEnabled behaviour
+
+```php
+public function configure(): void
+{
+ $this->setShouldAlwaysHideBulkActionsDropdownOptionDisabled();
+}
+```
diff --git a/resources/views/components/tools/toolbar.blade.php b/resources/views/components/tools/toolbar.blade.php
index a753403c6..84bb061e8 100644
--- a/resources/views/components/tools/toolbar.blade.php
+++ b/resources/views/components/tools/toolbar.blade.php
@@ -56,7 +56,7 @@
@include($component->getConfigurableAreaFor('toolbar-right-start'), $component->getParametersForConfigurableArea('toolbar-right-start'))
@endif
- @if ($component->showBulkActionsDropdownAlpine())
+ @if ($component->showBulkActionsDropdownAlpine() && $this->shouldAlwaysHideBulkActionsDropdownOption != true)
@endif
diff --git a/src/Traits/Configuration/BulkActionsConfiguration.php b/src/Traits/Configuration/BulkActionsConfiguration.php
index 813d46f42..d0d5e17f3 100644
--- a/src/Traits/Configuration/BulkActionsConfiguration.php
+++ b/src/Traits/Configuration/BulkActionsConfiguration.php
@@ -150,4 +150,25 @@ public function setBulkActionsTdCheckboxAttributes(array $bulkActionsTdCheckboxA
return $this;
}
+
+ public function setShouldAlwaysHideBulkActionsDropdownOption(bool $status = false): self
+ {
+ $this->alwaysHideBulkActionsDropdownOption = $status;
+
+ return $this;
+ }
+
+ public function setShouldAlwaysHideBulkActionsDropdownOptionEnabled(): self
+ {
+ $this->setShouldAlwaysHideBulkActionsDropdownOption(true);
+
+ return $this;
+ }
+
+ public function setShouldAlwaysHideBulkActionsDropdownOptionDisabled(): self
+ {
+ $this->setShouldAlwaysHideBulkActionsDropdownOption(false);
+
+ return $this;
+ }
}
diff --git a/src/Traits/Helpers/BulkActionsHelpers.php b/src/Traits/Helpers/BulkActionsHelpers.php
index 29f162bb6..70ea427a5 100644
--- a/src/Traits/Helpers/BulkActionsHelpers.php
+++ b/src/Traits/Helpers/BulkActionsHelpers.php
@@ -2,6 +2,8 @@
namespace Rappasoft\LaravelLivewireTables\Traits\Helpers;
+use Livewire\Attributes\Computed;
+
trait BulkActionsHelpers
{
public function getBulkActionsStatus(): bool
@@ -212,4 +214,10 @@ public function getBulkActionsTdCheckboxAttributes(): array
{
return $this->bulkActionsTdCheckboxAttributes ?? ['default' => true];
}
+
+ #[Computed]
+ public function shouldAlwaysHideBulkActionsDropdownOption(): bool
+ {
+ return $this->alwaysHideBulkActionsDropdownOption ?? false;
+ }
}
diff --git a/src/Traits/WithBulkActions.php b/src/Traits/WithBulkActions.php
index e05175733..08f69197b 100644
--- a/src/Traits/WithBulkActions.php
+++ b/src/Traits/WithBulkActions.php
@@ -34,6 +34,8 @@ trait WithBulkActions
protected array $bulkActionsTdCheckboxAttributes = ['default' => true];
+ protected bool $alwaysHideBulkActionsDropdownOption = false;
+
public function bulkActions(): array
{
return property_exists($this, 'bulkActions') ? $this->bulkActions : [];
diff --git a/tests/Traits/Visuals/BulkActionsVisualsTest.php b/tests/Traits/Visuals/BulkActionsVisualsTest.php
index 5447891da..91f73c177 100644
--- a/tests/Traits/Visuals/BulkActionsVisualsTest.php
+++ b/tests/Traits/Visuals/BulkActionsVisualsTest.php
@@ -80,4 +80,113 @@ public function test_bulk_actions_row_shows_correct_for_select_some(): void
->assertSee('do you want to select all')
->assertDontSee('You are currently selecting all');
}*/
+
+ public function test_bulk_dropdown_shows_when_necessary_extended(): void
+ {
+ Livewire::test(new class extends PetsTable
+ {
+ public function configure(): void
+ {
+ $this->setPrimaryKey('id');
+ }
+
+ public function bulkActions(): array
+ {
+ return ['exportBulk' => 'exportBulk'];
+ }
+
+ public function exportBulk($items)
+ {
+ return $items;
+ }
+ })->assertSee('Bulk Actions');
+ }
+
+ public function test_bulk_dropdown_shows_when_not_permanently_hidden(): void
+ {
+ Livewire::test(new class extends PetsTable
+ {
+ public function configure(): void
+ {
+ $this->setPrimaryKey('id')
+ ->setShouldAlwaysHideBulkActionsDropdownOption(false);
+ }
+
+ public function bulkActions(): array
+ {
+ return ['exportBulk' => 'exportBulk'];
+ }
+
+ public function exportBulk($items)
+ {
+ return $items;
+ }
+ })->assertSee('Bulk Actions');
+ }
+
+ public function test_bulk_dropdown_hides_when_permanently_hidden(): void
+ {
+ Livewire::test(new class extends PetsTable
+ {
+ public function configure(): void
+ {
+ $this->setPrimaryKey('id')
+ ->setShouldAlwaysHideBulkActionsDropdownOption(true);
+ }
+
+ public function bulkActions(): array
+ {
+ return ['exportBulk' => 'exportBulk'];
+ }
+
+ public function exportBulk($items)
+ {
+ return $items;
+ }
+ })->assertDontSee('Bulk Actions');
+ }
+
+ public function test_bulk_dropdown_shows_when_not_permanently_hidden_disabled(): void
+ {
+ Livewire::test(new class extends PetsTable
+ {
+ public function configure(): void
+ {
+ $this->setPrimaryKey('id')
+ ->setShouldAlwaysHideBulkActionsDropdownOptionDisabled();
+ }
+
+ public function bulkActions(): array
+ {
+ return ['exportBulk' => 'exportBulk'];
+ }
+
+ public function exportBulk($items)
+ {
+ return $items;
+ }
+ })->assertSee('Bulk Actions');
+ }
+
+ public function test_bulk_dropdown_hides_when_permanently_hidden_enabled(): void
+ {
+ Livewire::test(new class extends PetsTable
+ {
+ public function configure(): void
+ {
+ $this->setPrimaryKey('id')
+ ->setShouldAlwaysHideBulkActionsDropdownOptionEnabled();
+ }
+
+ public function bulkActions(): array
+ {
+ return ['exportBulk' => 'exportBulk'];
+ }
+
+ public function exportBulk($items)
+ {
+ return $items;
+ }
+ })->assertDontSee('Bulk Actions');
+ }
}
From 363374370e9c5d261a50a94bf2c53606033b004f Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Mon, 1 Jul 2024 15:29:33 +0100
Subject: [PATCH 11/21] Optionally disable count for simple pagination (#1755)
* Add option for setShouldRetrieveTotalItemCountStatus
* Fix styling
---------
Co-authored-by: lrljoe
---
docs/pagination/available-methods.md | 33 +++++++++++++++++++
.../Configuration/PaginationConfiguration.php | 22 +++++++++++++
src/Traits/Helpers/PaginationHelpers.php | 6 ++++
src/Traits/WithData.php | 18 ++++++----
src/Traits/WithPagination.php | 2 ++
.../Traits/Helpers/PaginationHelpersTest.php | 30 +++++++++++++++++
6 files changed, 104 insertions(+), 7 deletions(-)
diff --git a/docs/pagination/available-methods.md b/docs/pagination/available-methods.md
index d1b60a375..638e58a4b 100644
--- a/docs/pagination/available-methods.md
+++ b/docs/pagination/available-methods.md
@@ -263,3 +263,36 @@ public function configure(): void
]);
}
```
+
+## setShouldRetrieveTotalItemCountStatus
+
+Used when "simple" pagination is being used, allows the enabling/disabling of the "total records" count. This may be desirable to disable in larger data sets. This is enabled by default.
+
+```php
+public function configure(): void
+{
+ $this->setShouldRetrieveTotalItemCountStatus(false);
+}
+```
+
+## setShouldRetrieveTotalItemCountEnabled
+
+Used when "simple" pagination is being used, enables the "total records" count.
+
+```php
+public function configure(): void
+{
+ $this->setShouldRetrieveTotalItemCountEnabled();
+}
+```
+
+## setShouldRetrieveTotalItemCountDisabled
+
+Used when "simple" pagination is being used, disables the "total records" count.
+
+```php
+public function configure(): void
+{
+ $this->setShouldRetrieveTotalItemCountDisabled();
+}
+```
diff --git a/src/Traits/Configuration/PaginationConfiguration.php b/src/Traits/Configuration/PaginationConfiguration.php
index d7ffa5c34..a8877653a 100644
--- a/src/Traits/Configuration/PaginationConfiguration.php
+++ b/src/Traits/Configuration/PaginationConfiguration.php
@@ -155,4 +155,26 @@ public function setPerPageFieldAttributes(array $attributes = []): self
return $this;
}
+
+ public function setShouldRetrieveTotalItemCountStatus(bool $status): self
+ {
+ $this->shouldRetrieveTotalItemCount = $status;
+
+ return $this;
+
+ }
+
+ public function setShouldRetrieveTotalItemCountEnabled(): self
+ {
+ $this->setShouldRetrieveTotalItemCountStatus(true);
+
+ return $this;
+ }
+
+ public function setShouldRetrieveTotalItemCountDisabled(): self
+ {
+ $this->setShouldRetrieveTotalItemCountStatus(false);
+
+ return $this;
+ }
}
diff --git a/src/Traits/Helpers/PaginationHelpers.php b/src/Traits/Helpers/PaginationHelpers.php
index 7a744f225..717af7c12 100644
--- a/src/Traits/Helpers/PaginationHelpers.php
+++ b/src/Traits/Helpers/PaginationHelpers.php
@@ -149,4 +149,10 @@ public function getPerPageFieldAttributes(): array
{
return $this->perPageFieldAttributes;
}
+
+ #[Computed]
+ public function getShouldRetrieveTotalItemCount(): bool
+ {
+ return $this->shouldRetrieveTotalItemCount;
+ }
}
diff --git a/src/Traits/WithData.php b/src/Traits/WithData.php
index 9dcd44a4c..6d3261c93 100644
--- a/src/Traits/WithData.php
+++ b/src/Traits/WithData.php
@@ -80,21 +80,25 @@ protected function executeQuery(): Collection|CursorPaginator|Paginator|LengthAw
$this->paginationTotalItemCount = $paginatedResults->total() ?? 0;
return $paginatedResults;
- }
-
- if ($this->isPaginationMethod('simple')) {
+ } elseif ($this->isPaginationMethod('simple')) {
- $this->paginationTotalItemCount = $this->getBuilder()->count();
+ if ($this->getShouldRetrieveTotalItemCount()) {
+ $this->paginationTotalItemCount = $this->getBuilder()->count();
- return $this->getBuilder()->simplePaginate($this->getPerPage() === -1 ? $this->paginationTotalItemCount : $this->getPerPage(), ['*'], $this->getComputedPageName());
+ return $this->getBuilder()->simplePaginate($this->getPerPage() === -1 ? $this->paginationTotalItemCount : $this->getPerPage(), ['*'], $this->getComputedPageName());
+ } else {
+ $this->paginationTotalItemCount = -1;
- }
+ return $this->getBuilder()->simplePaginate($this->getPerPage() === -1 ? 10 : $this->getPerPage(), ['*'], $this->getComputedPageName());
+ }
- if ($this->isPaginationMethod('cursor')) {
+ } elseif ($this->isPaginationMethod('cursor')) {
$this->paginationTotalItemCount = $this->getBuilder()->count();
return $this->getBuilder()->cursorPaginate($this->getPerPage() === -1 ? $this->paginationTotalItemCount : $this->getPerPage(), ['*'], $this->getComputedPageName());
+ } else {
+ throw new DataTableConfigurationException('Pagination method must be either simple, standard or cursor');
}
}
diff --git a/src/Traits/WithPagination.php b/src/Traits/WithPagination.php
index 676d034b6..6f022a9fb 100644
--- a/src/Traits/WithPagination.php
+++ b/src/Traits/WithPagination.php
@@ -41,6 +41,8 @@ trait WithPagination
protected array $perPageFieldAttributes = ['default-styling' => true, 'default-colors' => true, 'class' => ''];
+ protected bool $shouldRetrieveTotalItemCount = true;
+
public function mountWithPagination(): void
{
$sessionPerPage = session()->get($this->getPerPagePaginationSessionKey(), $this->getPerPageAccepted()[0] ?? 10);
diff --git a/tests/Traits/Helpers/PaginationHelpersTest.php b/tests/Traits/Helpers/PaginationHelpersTest.php
index 471ee0d7f..0ec6557a4 100644
--- a/tests/Traits/Helpers/PaginationHelpersTest.php
+++ b/tests/Traits/Helpers/PaginationHelpersTest.php
@@ -141,4 +141,34 @@ public function test_can_get_pagination_field_attributes(): void
$this->assertSame(['default-styling' => false, 'default-colors' => true, 'class' => 'bg-blue-500 dark:bg-red-500'], $this->basicTable->getPerPageFieldAttributes());
}
+
+ public function test_can_toggle_total_item_count_retrieval(): void
+ {
+
+ $this->assertTrue($this->basicTable->getShouldRetrieveTotalItemCount());
+
+ $this->basicTable->setShouldRetrieveTotalItemCountDisabled();
+
+ $this->assertFalse($this->basicTable->getShouldRetrieveTotalItemCount());
+
+ $this->basicTable->setShouldRetrieveTotalItemCountEnabled();
+
+ $this->assertTrue($this->basicTable->getShouldRetrieveTotalItemCount());
+
+ }
+
+ public function test_can_toggle_total_item_count_retrieval_via_status(): void
+ {
+
+ $this->assertTrue($this->basicTable->getShouldRetrieveTotalItemCount());
+
+ $this->basicTable->setShouldRetrieveTotalItemCountStatus(false);
+
+ $this->assertFalse($this->basicTable->getShouldRetrieveTotalItemCount());
+
+ $this->basicTable->setShouldRetrieveTotalItemCountStatus(true);
+
+ $this->assertTrue($this->basicTable->getShouldRetrieveTotalItemCount());
+
+ }
}
From f0cfe568f32e7b1d98040f5a6986ce45eb3c852d Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Tue, 2 Jul 2024 01:50:30 +0100
Subject: [PATCH 12/21] Update ChangeLog For 3.2.8 Release (#1754)
* Update ChangeLog for 3.2.8
---
CHANGELOG.md | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7060f51c2..1add18837 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,21 @@
All notable changes to `laravel-livewire-tables` will be documented in this file
+## [v3.2.8] - UNRELEASED
+### Bug Fixes
+- Fix hide bulk actions when empty not reflecting in frontend by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1747
+- Apply cursor pointer only on clickable columns when using Bootstrap by @MP70 in https://github.com/rappasoft/laravel-livewire-tables/pull/1742
+
+### New Features
+- Always hide bulk actions option by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1752
+- Add ArrayColumn (BETA) by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1751
+- Optionally disable total item count for simple pagination by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1755
+
+### Tweaks
+- TypeHint fixes by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1750
+- Change Return Type for attributes() to static by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1749
+- Switch to using Composer\InstalledVersions for AboutCommand by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1748
+
## [v3.2.7] - 2024-06-05
### Bug Fixes
- Ensure HTML Columns return HTML correctly by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1737
From 1adebfb04828d65a5d91a004e751fe9adf97752a Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Wed, 3 Jul 2024 22:02:49 +0100
Subject: [PATCH 13/21] Add release date
---
CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1add18837..6993a50e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,7 @@
All notable changes to `laravel-livewire-tables` will be documented in this file
-## [v3.2.8] - UNRELEASED
+## [v3.2.8] - 2024-07-03
### Bug Fixes
- Fix hide bulk actions when empty not reflecting in frontend by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1747
- Apply cursor pointer only on clickable columns when using Bootstrap by @MP70 in https://github.com/rappasoft/laravel-livewire-tables/pull/1742
From 13fe6a5addba0f7dc6a0f224ddc023b42ca5fb11 Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Wed, 3 Jul 2024 22:04:12 +0100
Subject: [PATCH 14/21] Fix phpstan unescaped |
---
phpstan.neon | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/phpstan.neon b/phpstan.neon
index a0324459d..25867a7d5 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -19,6 +19,6 @@ parameters:
- "#Unsafe usage of new static#"
- '#on array\, mixed\>\> in empty\(\) does not exist.#'
- '#on array, mixed>> in isset\(\) does not exist#'
- - '#on non-empty-array<1|string, array, mixed>> in isset\(\) does not exist.#'
+ - '#on non-empty-array<1\|string, array, mixed>> in isset\(\) does not exist.#'
- '#\$callback of method Illuminate\\Support\\Collection::filter\(\) expects \(callable\(string, int\): bool\)\|null, Closure\(mixed\): int<0, max> given.#'
- '#Property Illuminate\\Database\\Query\\Builder\:\:\$joins \(array\) on left side of \?\? is not nullable.#'
From 51f4c945948a057e65f550cfbc6109eb41e7a864 Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Wed, 3 Jul 2024 23:14:24 +0100
Subject: [PATCH 15/21] Fix missing typehints (#1757)
* Add additional typehints
* Fix styling
* Add filterCollection typehint
* Fix styling
* trUrlCallback fixes
* Use Collection rather than collect() helper
* Fix styling
* Add ignore for "Unable to resolve the template type" for Illuminate Collection, add typehint for empty
* Add ignore for $model has no defined type (allows for non Eloquent Model to be used longer term)
* Adjust concurrency
* Adjust Test
* Adjust Again
* Adjust PHPStan
* Add Max Parallel
* Use v4 of checkout/cache
* Run one at a time
* Add Clear Cache Workflow
* Fix
* Migrate to v4 and adjust workflows
* Adjust workflow run rules
* Adjust Run-Tests to separate L10 and L11 jobs
* Adjust run-tests
* Adjust Test
* Add Laravel matrix
* Adjust Concurrency
* Adjust
* Adjust Pull Jobs to Match Push jobs
---------
Co-authored-by: lrljoe
---
.github/workflows/discord-releases.yml | 2 +-
.github/workflows/pint.yml | 7 +-
.github/workflows/run-phpstan.yml | 18 ++-
.github/workflows/run-tests-pcov-pull.yml | 6 +-
.github/workflows/run-tests-pull.yml | 111 +++++++++++++++---
.github/workflows/run-tests.yml | 105 +++++++++++++++--
phpstan.neon | 3 +
src/Commands/MakeCommand.php | 12 +-
src/Mechanisms/RappasoftFrontendAssets.php | 2 +-
.../Configuration/FilterConfiguration.php | 2 +-
src/Traits/Helpers/FilterHelpers.php | 2 +-
src/Traits/Helpers/FooterHelpers.php | 4 +-
src/Traits/Helpers/SecondaryHeaderHelpers.php | 4 +-
src/Traits/Helpers/TableAttributeHelpers.php | 14 +--
src/Traits/WithData.php | 2 +-
src/Traits/WithEvents.php | 4 +-
src/Traits/WithFilters.php | 3 +-
src/Traits/WithFooter.php | 4 +-
src/Traits/WithPagination.php | 2 +-
src/Traits/WithSecondaryHeader.php | 4 +-
src/Traits/WithTableAttributes.php | 12 +-
src/Traits/WithTableHooks.php | 4 +-
.../Filters/MultiSelectDropdownFilter.php | 5 +-
src/Views/Filters/SelectFilter.php | 8 +-
.../Traits/Helpers/ColorColumnHelpers.php | 3 +-
src/Views/Traits/Helpers/ColumnHelpers.php | 2 +-
26 files changed, 265 insertions(+), 80 deletions(-)
diff --git a/.github/workflows/discord-releases.yml b/.github/workflows/discord-releases.yml
index c75bedd41..84ea5b888 100644
--- a/.github/workflows/discord-releases.yml
+++ b/.github/workflows/discord-releases.yml
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Package Releases
uses: SethCohen/github-releases-to-discord@v1.13.1
with:
diff --git a/.github/workflows/pint.yml b/.github/workflows/pint.yml
index 097689b83..230a58799 100644
--- a/.github/workflows/pint.yml
+++ b/.github/workflows/pint.yml
@@ -2,6 +2,11 @@ name: Fix PHP code style issues
on:
push:
+ branches:
+ - '*' # matches every branch that doesn't contain a '/'
+ - '*/*' # matches every branch containing a single '/'
+ - '**' # matches every branch
+ - '!master'
paths:
- '**.php'
@@ -14,7 +19,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
diff --git a/.github/workflows/run-phpstan.yml b/.github/workflows/run-phpstan.yml
index a94ed2a24..4faf52718 100644
--- a/.github/workflows/run-phpstan.yml
+++ b/.github/workflows/run-phpstan.yml
@@ -1,6 +1,16 @@
name: run-phpstan
-on: [push, pull_request]
+on:
+ pull_request:
+ branches:
+ - 'master'
+ - 'development'
+ push:
+ branches:
+ - '*' # matches every branch that doesn't contain a '/'
+ - '*/*' # matches every branch containing a single '/'
+ - '**' # matches every branch
+ - '!master'
jobs:
test:
@@ -20,7 +30,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup cache environment
id: extcache
@@ -31,7 +41,7 @@ jobs:
key: ${{ env.extensionKey }}
- name: Cache extensions
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ${{ steps.extcache.outputs.dir }}
key: ${{ steps.extcache.outputs.key }}
@@ -55,7 +65,7 @@ jobs:
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- - uses: actions/cache@v3
+ - uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-PHPStan-P${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }}
diff --git a/.github/workflows/run-tests-pcov-pull.yml b/.github/workflows/run-tests-pcov-pull.yml
index 0a5f52d3e..3a24a91ba 100644
--- a/.github/workflows/run-tests-pcov-pull.yml
+++ b/.github/workflows/run-tests-pcov-pull.yml
@@ -25,7 +25,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup cache environment
id: extcache
@@ -47,7 +47,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Cache extensions
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ${{ steps.extcache.outputs.dir }}
key: ${{ steps.extcache.outputs.key }}
@@ -61,7 +61,7 @@ jobs:
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- - uses: actions/cache@v3
+ - uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-PCOV-PULL-PHP${{ matrix.php }}-Laravel${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }}
diff --git a/.github/workflows/run-tests-pull.yml b/.github/workflows/run-tests-pull.yml
index 1abeaeee8..38f635f9c 100644
--- a/.github/workflows/run-tests-pull.yml
+++ b/.github/workflows/run-tests-pull.yml
@@ -8,27 +8,25 @@ on:
- 'master'
jobs:
- test:
+ test-laravel10:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
+ max-parallel: 3
matrix:
os: [ubuntu-latest]
php: [8.1, 8.2, 8.3]
- laravel: [10.*,11.*]
+ laravel: [10.*]
stability: [prefer-dist]
- exclude:
- - laravel: 11.*
- php: 8.1
- name: STD-PULL - ${{ matrix.os }} - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }}
+ name: PULL PHP-${{ matrix.php }} - Laravel-10
env:
- extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}
+ extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}-L{{ matrix.laravel }}
extensions: dom, curl, libxml, mbstring, zip, pcntl, pcov, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, :psr
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup cache environment
id: extcache
@@ -36,14 +34,14 @@ jobs:
with:
php-version: ${{ matrix.php }}
extensions: ${{ env.extensions }}
- key: ${{ runner.os }}-${{ env.extensionKey }}
+ key: ${{ env.extensionKey }}
- name: Cache extensions
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ${{ steps.extcache.outputs.dir }}
- key: ${{ steps.extcache.outputs.key }}
- restore-keys: ${{ steps.extcache.outputs.key }}
+ key: ${{ runner.os }}-${{ steps.extcache.outputs.key }}
+ restore-keys: ${{ runner.os }}-${{ steps.extcache.outputs.key }}
- name: Setup PHP
uses: shivammathur/setup-php@v2
@@ -64,11 +62,11 @@ jobs:
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- - uses: actions/cache@v3
+ - uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
- key: ${{ runner.os }}-STDPULL-PHP-${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }}
- restore-keys: ${{ runner.os }}-STDPULL-PHP-${{ matrix.php }}-L${{ matrix.laravel }}-composer-
+ key: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }}
+ restore-keys: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-
- name: Add token
run: |
@@ -79,7 +77,90 @@ jobs:
run: composer require "laravel/framework:${{ matrix.laravel }}.*" --no-interaction --no-update
- name: Update dependencies
+ if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer update --${{ matrix.stability }} --no-interaction
+ - name: Setup problem matchers for PHPUnit
+ run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
+
+ - name: Run Unit Tests
+ run: php ./vendor/bin/paratest --no-coverage --processes=4
+
+
+ test-laravel11:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ max-parallel: 2
+ matrix:
+ os: [ubuntu-latest]
+ php: [8.2, 8.3]
+ laravel: [11.*]
+ stability: [prefer-dist]
+
+ name: PULL PHP-${{ matrix.php }} - Laravel-11
+ env:
+ extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}-L{{ matrix.laravel }}
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pcov, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, :psr
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup cache environment
+ id: extcache
+ uses: shivammathur/cache-extensions@v1
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: ${{ env.extensions }}
+ key: ${{ env.extensionKey }}
+
+ - name: Cache extensions
+ uses: actions/cache@v4
+ with:
+ path: ${{ steps.extcache.outputs.dir }}
+ key: ${{ runner.os }}-${{ steps.extcache.outputs.key }}
+ restore-keys: ${{ runner.os }}-${{ steps.extcache.outputs.key }}
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: ${{ env.extensions }}
+ tools: phpunit:latest
+ ini-values: memory_limit=512M
+ coverage: none
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Setup problem matchers for PHP
+ run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: |
+ echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
+
+ - uses: actions/cache@v4
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }}
+ restore-keys: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-
+
+ - name: Add token
+ run: |
+ composer config github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Install dependencies
+ if: steps.composer-cache.outputs.cache-hit != 'true'
+ run: composer require "laravel/framework:${{ matrix.laravel }}.*" --no-interaction --no-update
+
+ - name: Update dependencies
+ if: steps.composer-cache.outputs.cache-hit != 'true'
+ run: composer update --${{ matrix.stability }} --no-interaction
+
+ - name: Setup problem matchers for PHPUnit
+ run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
+
- name: Run Unit Tests
run: php ./vendor/bin/paratest --no-coverage --processes=4
diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
index ce258214d..9f6997a6c 100644
--- a/.github/workflows/run-tests.yml
+++ b/.github/workflows/run-tests.yml
@@ -1,29 +1,33 @@
name: run-tests
-on: [push]
+on:
+ push:
+ branches:
+ - '*' # matches every branch that doesn't contain a '/'
+ - '*/*' # matches every branch containing a single '/'
+ - '**' # matches every branch
+ - '!master'
jobs:
- test:
+ test-laravel10:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
+ max-parallel: 3
matrix:
os: [ubuntu-latest]
php: [8.1, 8.2, 8.3]
- laravel: [10.*,11.*]
+ laravel: [10.*]
stability: [prefer-dist]
- exclude:
- - laravel: 11.*
- php: 8.1
- name: STD-PUSH - ${{ matrix.os }} - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }}
+ name: PHP-${{ matrix.php }} - Laravel-10
env:
- extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}
+ extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}-L{{ matrix.laravel }}
extensions: dom, curl, libxml, mbstring, zip, pcntl, pcov, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, :psr
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup cache environment
id: extcache
@@ -34,7 +38,7 @@ jobs:
key: ${{ env.extensionKey }}
- name: Cache extensions
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ${{ steps.extcache.outputs.dir }}
key: ${{ runner.os }}-${{ steps.extcache.outputs.key }}
@@ -59,7 +63,86 @@ jobs:
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- - uses: actions/cache@v3
+ - uses: actions/cache@v4
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }}
+ restore-keys: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-
+
+ - name: Add token
+ run: |
+ composer config github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Install dependencies
+ if: steps.composer-cache.outputs.cache-hit != 'true'
+ run: composer require "laravel/framework:${{ matrix.laravel }}.*" --no-interaction --no-update
+
+ - name: Update dependencies
+ if: steps.composer-cache.outputs.cache-hit != 'true'
+ run: composer update --${{ matrix.stability }} --no-interaction
+
+ - name: Setup problem matchers for PHPUnit
+ run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
+
+ - name: Run Unit Tests
+ run: php ./vendor/bin/paratest --no-coverage --processes=4
+
+
+ test-laravel11:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ max-parallel: 2
+ matrix:
+ os: [ubuntu-latest]
+ php: [8.2, 8.3]
+ laravel: [11.*]
+ stability: [prefer-dist]
+
+ name: PHP-${{ matrix.php }} - Laravel-11
+ env:
+ extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}-L{{ matrix.laravel }}
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pcov, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, :psr
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup cache environment
+ id: extcache
+ uses: shivammathur/cache-extensions@v1
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: ${{ env.extensions }}
+ key: ${{ env.extensionKey }}
+
+ - name: Cache extensions
+ uses: actions/cache@v4
+ with:
+ path: ${{ steps.extcache.outputs.dir }}
+ key: ${{ runner.os }}-${{ steps.extcache.outputs.key }}
+ restore-keys: ${{ runner.os }}-${{ steps.extcache.outputs.key }}
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: ${{ env.extensions }}
+ tools: phpunit:latest
+ ini-values: memory_limit=512M
+ coverage: none
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Setup problem matchers for PHP
+ run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: |
+ echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
+
+ - uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }}
diff --git a/phpstan.neon b/phpstan.neon
index 25867a7d5..7ff21a707 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -15,6 +15,9 @@ parameters:
ignoreErrors:
- identifier: missingType.generics
- identifier: missingType.iterableValue
+ - '#Property Rappasoft\\LaravelLivewireTables\\DataTableComponent\:\:\$model has no type specified#'
+ - '#Unable to resolve the template type TMapWithKeysKey in call to method Illuminate\\Support\\Collection#'
+ - '#Unable to resolve the template type TMapWithKeysValue in call to method Illuminate\\Support\\Collection#'
- '#Access to an undefined property Rappasoft\\LaravelLivewireTables\\Views\\Column\:\:\$view#'
- "#Unsafe usage of new static#"
- '#on array\, mixed\>\> in empty\(\) does not exist.#'
diff --git a/src/Commands/MakeCommand.php b/src/Commands/MakeCommand.php
index cdaa67130..8338a1216 100644
--- a/src/Commands/MakeCommand.php
+++ b/src/Commands/MakeCommand.php
@@ -5,6 +5,7 @@
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Livewire\Features\SupportConsoleCommands\Commands\ComponentParser;
@@ -97,10 +98,7 @@ protected function createClass(bool $force = false): bool
return $classPath;
}
- /**
- * @param mixed $path
- */
- protected function ensureDirectoryExists($path): void
+ protected function ensureDirectoryExists(string $path): void
{
if (! File::isDirectory(dirname($path))) {
File::makeDirectory(dirname($path), 0777, true, true);
@@ -147,7 +145,7 @@ public function getModelImport(): string
/*
* Credits to Harm Smits: https://stackoverflow.com/a/67099502/2263114
*/
- private function getClassesList($file): array
+ private function getClassesList(string $file): array
{
$classes = [];
$namespace = '';
@@ -215,7 +213,7 @@ private function generateColumns(string $modelName): string
return $columns;
}
- protected function possibleModels()
+ protected function possibleModels(): array
{
$modelPath = is_dir(app_path('Models')) ? app_path('Models') : app_path();
@@ -226,7 +224,7 @@ protected function possibleModels()
->all();
}
- protected function promptForMissingArguments(InputInterface $input, OutputInterface $output)
+ protected function promptForMissingArguments(InputInterface $input, OutputInterface $output): void
{
if ($this->didReceiveOptions($input)) {
diff --git a/src/Mechanisms/RappasoftFrontendAssets.php b/src/Mechanisms/RappasoftFrontendAssets.php
index 62889d0ff..d460f5431 100644
--- a/src/Mechanisms/RappasoftFrontendAssets.php
+++ b/src/Mechanisms/RappasoftFrontendAssets.php
@@ -56,7 +56,7 @@ public function boot(): void
}
- protected function registerBladeDirectives()
+ protected function registerBladeDirectives(): void
{
Blade::directive('rappasoftTableScripts', [static::class, 'rappasoftTableScripts']);
Blade::directive('rappasoftTableStyles', [static::class, 'rappasoftTableStyles']);
diff --git a/src/Traits/Configuration/FilterConfiguration.php b/src/Traits/Configuration/FilterConfiguration.php
index 9eac5d75f..3367c9168 100644
--- a/src/Traits/Configuration/FilterConfiguration.php
+++ b/src/Traits/Configuration/FilterConfiguration.php
@@ -121,7 +121,7 @@ public function generateFilterGenericData(): array
return (new FilterGenericData($this))->toArray();
}
- public function setFilterGenericData(array $filterGenericData = [])
+ public function setFilterGenericData(array $filterGenericData = []): void
{
$this->filterGenericData = $filterGenericData;
}
diff --git a/src/Traits/Helpers/FilterHelpers.php b/src/Traits/Helpers/FilterHelpers.php
index 55c824fad..d4c043531 100644
--- a/src/Traits/Helpers/FilterHelpers.php
+++ b/src/Traits/Helpers/FilterHelpers.php
@@ -312,7 +312,7 @@ public function hasFilterGenericData(): bool
return ! empty($this->filterGenericData);
}
- public function getFilterGenericData()
+ public function getFilterGenericData(): array
{
if (! $this->hasFilterGenericData()) {
$this->setFilterGenericData($this->generateFilterGenericData());
diff --git a/src/Traits/Helpers/FooterHelpers.php b/src/Traits/Helpers/FooterHelpers.php
index 37e8276bd..df220e3c0 100644
--- a/src/Traits/Helpers/FooterHelpers.php
+++ b/src/Traits/Helpers/FooterHelpers.php
@@ -47,7 +47,7 @@ public function useHeaderAsFooterIsDisabled(): bool
*/
public function getFooterTrAttributes($rows): array
{
- return $this->footerTrAttributesCallback ? call_user_func($this->footerTrAttributesCallback, $rows) : ['default' => true];
+ return isset($this->footerTrAttributesCallback) ? call_user_func($this->footerTrAttributesCallback, $rows) : ['default' => true];
}
/**
@@ -56,6 +56,6 @@ public function getFooterTrAttributes($rows): array
*/
public function getFooterTdAttributes(Column $column, $rows, int $index): array
{
- return $this->footerTdAttributesCallback ? call_user_func($this->footerTdAttributesCallback, $column, $rows, $index) : ['default' => true];
+ return isset($this->footerTdAttributesCallback) ? call_user_func($this->footerTdAttributesCallback, $column, $rows, $index) : ['default' => true];
}
}
diff --git a/src/Traits/Helpers/SecondaryHeaderHelpers.php b/src/Traits/Helpers/SecondaryHeaderHelpers.php
index cc7694002..6af852483 100644
--- a/src/Traits/Helpers/SecondaryHeaderHelpers.php
+++ b/src/Traits/Helpers/SecondaryHeaderHelpers.php
@@ -32,7 +32,7 @@ public function secondaryHeaderIsDisabled(): bool
*/
public function getSecondaryHeaderTrAttributes($rows): array
{
- return $this->secondaryHeaderTrAttributesCallback ? call_user_func($this->secondaryHeaderTrAttributesCallback, $rows) : ['default' => true];
+ return isset($this->secondaryHeaderTrAttributesCallback) ? call_user_func($this->secondaryHeaderTrAttributesCallback, $rows) : ['default' => true];
}
/**
@@ -41,6 +41,6 @@ public function getSecondaryHeaderTrAttributes($rows): array
*/
public function getSecondaryHeaderTdAttributes(Column $column, $rows, int $index): array
{
- return $this->secondaryHeaderTdAttributesCallback ? call_user_func($this->secondaryHeaderTdAttributesCallback, $column, $rows, $index) : ['default' => true];
+ return isset($this->secondaryHeaderTdAttributesCallback) ? call_user_func($this->secondaryHeaderTdAttributesCallback, $column, $rows, $index) : ['default' => true];
}
}
diff --git a/src/Traits/Helpers/TableAttributeHelpers.php b/src/Traits/Helpers/TableAttributeHelpers.php
index 866e72526..ffebab51c 100644
--- a/src/Traits/Helpers/TableAttributeHelpers.php
+++ b/src/Traits/Helpers/TableAttributeHelpers.php
@@ -52,7 +52,7 @@ public function getTbodyAttributes(): array
*/
public function getThAttributes(Column $column): array
{
- return $this->thAttributesCallback ? call_user_func($this->thAttributesCallback, $column) : ['default' => true];
+ return isset($this->thAttributesCallback) ? call_user_func($this->thAttributesCallback, $column) : ['default' => true];
}
/**
@@ -60,7 +60,7 @@ public function getThAttributes(Column $column): array
*/
public function getThSortButtonAttributes(Column $column): array
{
- return $this->thSortButtonAttributesCallback ? call_user_func($this->thSortButtonAttributesCallback, $column) : ['default' => true];
+ return isset($this->thSortButtonAttributesCallback) ? call_user_func($this->thSortButtonAttributesCallback, $column) : ['default' => true];
}
/**
@@ -68,7 +68,7 @@ public function getThSortButtonAttributes(Column $column): array
*/
public function getTrAttributes(Model $row, int $index): array
{
- return $this->trAttributesCallback ? call_user_func($this->trAttributesCallback, $row, $index) : ['default' => true];
+ return isset($this->trAttributesCallback) ? call_user_func($this->trAttributesCallback, $row, $index) : ['default' => true];
}
/**
@@ -76,21 +76,21 @@ public function getTrAttributes(Model $row, int $index): array
*/
public function getTdAttributes(Column $column, Model $row, int $colIndex, int $rowIndex): array
{
- return $this->tdAttributesCallback ? call_user_func($this->tdAttributesCallback, $column, $row, $colIndex, $rowIndex) : ['default' => true];
+ return isset($this->tdAttributesCallback) ? call_user_func($this->tdAttributesCallback, $column, $row, $colIndex, $rowIndex) : ['default' => true];
}
public function hasTableRowUrl(): bool
{
- return $this->trUrlCallback !== null;
+ return isset($this->trUrlCallback);
}
public function getTableRowUrl(int|Model $row): ?string
{
- return $this->trUrlCallback ? call_user_func($this->trUrlCallback, $row) : null;
+ return isset($this->trUrlCallback) ? call_user_func($this->trUrlCallback, $row) : null;
}
public function getTableRowUrlTarget(int|Model $row): ?string
{
- return $this->trUrlTargetCallback ? call_user_func($this->trUrlTargetCallback, $row) : null;
+ return isset($this->trUrlTargetCallback) ? call_user_func($this->trUrlTargetCallback, $row) : null;
}
}
diff --git a/src/Traits/WithData.php b/src/Traits/WithData.php
index 6d3261c93..5e1ca3298 100644
--- a/src/Traits/WithData.php
+++ b/src/Traits/WithData.php
@@ -175,7 +175,7 @@ protected function joinRelation(Column $column): Builder
return $this->getBuilder();
}
- protected function performJoin($table, $foreign, $other, $type = 'left'): Builder
+ protected function performJoin(string $table, string $foreign, string $other, string $type = 'left'): Builder
{
$joins = [];
diff --git a/src/Traits/WithEvents.php b/src/Traits/WithEvents.php
index 448dcc69f..dca549f2a 100644
--- a/src/Traits/WithEvents.php
+++ b/src/Traits/WithEvents.php
@@ -4,7 +4,7 @@
trait WithEvents
{
- public function setSortEvent($field, $direction): void
+ public function setSortEvent(string $field, string $direction): void
{
$this->setSort($field, $direction);
}
@@ -14,7 +14,7 @@ public function clearSortEvent(): void
$this->clearSorts();
}
- public function setFilterEvent($filter, $value): void
+ public function setFilterEvent(string $filter, string $value): void
{
$this->setFilter($filter, $value);
}
diff --git a/src/Traits/WithFilters.php b/src/Traits/WithFilters.php
index ec6c7aac2..878c660ce 100644
--- a/src/Traits/WithFilters.php
+++ b/src/Traits/WithFilters.php
@@ -3,6 +3,7 @@
namespace Rappasoft\LaravelLivewireTables\Traits;
use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Support\Collection;
use Rappasoft\LaravelLivewireTables\Traits\Configuration\FilterConfiguration;
use Rappasoft\LaravelLivewireTables\Traits\Helpers\FilterHelpers;
@@ -23,7 +24,7 @@ trait WithFilters
public int $filterCount;
- protected $filterCollection;
+ protected ?Collection $filterCollection;
public array $filterComponents = [];
diff --git a/src/Traits/WithFooter.php b/src/Traits/WithFooter.php
index 376f2340b..b1035cf29 100644
--- a/src/Traits/WithFooter.php
+++ b/src/Traits/WithFooter.php
@@ -16,9 +16,9 @@ trait WithFooter
protected bool $columnsWithFooter = false;
- protected $footerTrAttributesCallback;
+ protected ?object $footerTrAttributesCallback;
- protected $footerTdAttributesCallback;
+ protected ?object $footerTdAttributesCallback;
public function setupFooter(): void
{
diff --git a/src/Traits/WithPagination.php b/src/Traits/WithPagination.php
index 6f022a9fb..946bed2cb 100644
--- a/src/Traits/WithPagination.php
+++ b/src/Traits/WithPagination.php
@@ -53,7 +53,7 @@ public function mountWithPagination(): void
}
// TODO: Test
- public function updatedPerPage($value): void
+ public function updatedPerPage(int|string $value): void
{
if (! in_array((int) $value, $this->getPerPageAccepted(), false)) {
$value = $this->getPerPageAccepted()[0] ?? 10;
diff --git a/src/Traits/WithSecondaryHeader.php b/src/Traits/WithSecondaryHeader.php
index 94022b5f1..875d0ae03 100644
--- a/src/Traits/WithSecondaryHeader.php
+++ b/src/Traits/WithSecondaryHeader.php
@@ -14,9 +14,9 @@ trait WithSecondaryHeader
protected bool $columnsWithSecondaryHeader = false;
- protected $secondaryHeaderTrAttributesCallback;
+ protected ?object $secondaryHeaderTrAttributesCallback;
- protected $secondaryHeaderTdAttributesCallback;
+ protected ?object $secondaryHeaderTdAttributesCallback;
public function bootedWithSecondaryHeader(): void
{
diff --git a/src/Traits/WithTableAttributes.php b/src/Traits/WithTableAttributes.php
index f75f75f9e..b58c6baf0 100644
--- a/src/Traits/WithTableAttributes.php
+++ b/src/Traits/WithTableAttributes.php
@@ -21,15 +21,15 @@ trait WithTableAttributes
protected array $tbodyAttributes = [];
- protected $thAttributesCallback;
+ protected ?object $thAttributesCallback;
- protected $thSortButtonAttributesCallback;
+ protected ?object $thSortButtonAttributesCallback;
- protected $trAttributesCallback;
+ protected ?object $trAttributesCallback;
- protected $tdAttributesCallback;
+ protected ?object $tdAttributesCallback;
- protected $trUrlCallback;
+ protected ?object $trUrlCallback;
- protected $trUrlTargetCallback;
+ protected ?object $trUrlTargetCallback;
}
diff --git a/src/Traits/WithTableHooks.php b/src/Traits/WithTableHooks.php
index 160713e56..eb0f18fd8 100644
--- a/src/Traits/WithTableHooks.php
+++ b/src/Traits/WithTableHooks.php
@@ -6,14 +6,14 @@
trait WithTableHooks
{
- public function callHook($name, $params = [])
+ public function callHook(string $name, array $params = []): void
{
if (method_exists($this, $name)) {
wrap($this)->__call($name, $params);
}
}
- public function callTraitHook($name, $params = [])
+ public function callTraitHook(string $name, array $params = []): void
{
foreach (class_uses_recursive($this) as $trait) {
$method = $name.class_basename($trait);
diff --git a/src/Views/Filters/MultiSelectDropdownFilter.php b/src/Views/Filters/MultiSelectDropdownFilter.php
index ae784b58c..3022ddba5 100644
--- a/src/Views/Filters/MultiSelectDropdownFilter.php
+++ b/src/Views/Filters/MultiSelectDropdownFilter.php
@@ -2,6 +2,7 @@
namespace Rappasoft\LaravelLivewireTables\Views\Filters;
+use Illuminate\Support\Collection;
use Rappasoft\LaravelLivewireTables\Views\Filter;
use Rappasoft\LaravelLivewireTables\Views\Traits\Core\HasWireables;
use Rappasoft\LaravelLivewireTables\Views\Traits\Filters\{HasOptions,IsArrayFilter};
@@ -42,7 +43,7 @@ public function getFilterPillValue($value): ?string
foreach ($value as $item) {
$found = $this->getCustomFilterPillValue($item)
- ?? collect($this->getOptions())
+ ?? (new Collection($this->getOptions()))
->mapWithKeys(fn ($options, $optgroupLabel) => is_iterable($options) ? $options : [$optgroupLabel => $options])[$item]
?? null;
@@ -54,7 +55,7 @@ public function getFilterPillValue($value): ?string
return implode(', ', $values);
}
- public function isEmpty($value): bool
+ public function isEmpty(mixed $value): bool
{
if (! is_array($value)) {
return true;
diff --git a/src/Views/Filters/SelectFilter.php b/src/Views/Filters/SelectFilter.php
index a62260dd9..0f247ada4 100644
--- a/src/Views/Filters/SelectFilter.php
+++ b/src/Views/Filters/SelectFilter.php
@@ -2,6 +2,7 @@
namespace Rappasoft\LaravelLivewireTables\Views\Filters;
+use Illuminate\Support\Collection;
use Rappasoft\LaravelLivewireTables\Views\Filter;
use Rappasoft\LaravelLivewireTables\Views\Traits\Core\HasWireables;
use Rappasoft\LaravelLivewireTables\Views\Traits\Filters\{HasOptions,IsStringFilter};
@@ -22,8 +23,8 @@ class SelectFilter extends Filter
public function getKeys(): array
{
- return collect($this->getOptions())
- ->map(fn ($value, $key) => is_iterable($value) ? collect($value)->keys() : $key)
+ return (new Collection($this->getOptions()))
+ ->map(fn ($value, $key) => is_iterable($value) ? (new Collection($value))->keys() : $key)
->flatten()
->map(fn ($value) => (string) $value)
->filter(fn ($value) => strlen($value) > 0)
@@ -42,8 +43,9 @@ public function validate(string $value): array|string|bool
public function getFilterPillValue($value): ?string
{
+
return $this->getCustomFilterPillValue($value)
- ?? collect($this->getOptions())
+ ?? (new Collection($this->getOptions()))
->mapWithKeys(fn ($options, $optgroupLabel) => is_iterable($options) ? $options : [$optgroupLabel => $options])[$value]
?? null;
}
diff --git a/src/Views/Traits/Helpers/ColorColumnHelpers.php b/src/Views/Traits/Helpers/ColorColumnHelpers.php
index 00f017e9e..d437243e7 100644
--- a/src/Views/Traits/Helpers/ColorColumnHelpers.php
+++ b/src/Views/Traits/Helpers/ColorColumnHelpers.php
@@ -2,12 +2,13 @@
namespace Rappasoft\LaravelLivewireTables\Views\Traits\Helpers;
+use Illuminate\Database\Eloquent\Model;
use Illuminate\View\ComponentAttributeBag;
trait ColorColumnHelpers
{
// TODO: Test
- public function getColor($row): string
+ public function getColor(Model|int $row): string
{
return $this->hasColorCallback() ? app()->call($this->getColorCallback(), ['row' => $row]) : ($this->getValue($row));
}
diff --git a/src/Views/Traits/Helpers/ColumnHelpers.php b/src/Views/Traits/Helpers/ColumnHelpers.php
index a43d21681..fb2fbfb38 100644
--- a/src/Views/Traits/Helpers/ColumnHelpers.php
+++ b/src/Views/Traits/Helpers/ColumnHelpers.php
@@ -131,7 +131,7 @@ public function getContents(Model $row): null|string|\BackedEnum|HtmlString|Data
}
// TODO: Test
- public function getValue(Model $row)
+ public function getValue(Model $row): mixed
{
if ($this->isBaseColumn()) {
return $row->{$this->getField()};
From 37691f9d3d621a49ae2a9c53619eb0bf60be05ee Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Thu, 11 Jul 2024 00:28:33 +0100
Subject: [PATCH 16/21] Add CountColumn, simpler adding of WithCounts, With
(#1761)
* Initial Commit
* Adjust CountColumn
* Add ExtraWiths
* Add AggregateColumn
* Add SumColumn
* Update Docs - Add Column Types Section
* Add exceptions for empty data source, add standard tests
* Ensure pcov runs on push to master/development/develop
* Update to use codecov v4
---------
Co-authored-by: lrljoe
---
.github/workflows/run-tests-pcov-pull.yml | 9 +-
.gitignore | 4 +-
CHANGELOG.md | 4 +
coverage.xml | 2894 -----------------
docs/bulk-actions/_index.md | 2 +-
docs/column-types/_index.md | 4 +
docs/column-types/array_column.md | 22 +
docs/column-types/avg_column.md | 14 +
docs/column-types/boolean_columns.md | 81 +
docs/column-types/button_group_column.md | 34 +
docs/column-types/color_columns.md | 41 +
docs/column-types/component_column.md | 28 +
docs/column-types/count_column.md | 14 +
docs/column-types/date_columns.md | 28 +
docs/column-types/image_columns.md | 26 +
docs/column-types/link_columns.md | 24 +
.../column-types/livewire_component_column.md | 5 +
docs/column-types/sum_column.md | 14 +
docs/columns/other-column-types.md | 241 +-
docs/examples/_index.md | 2 +-
docs/filter-types/_index.md | 2 +-
docs/filters/_index.md | 2 +-
docs/footer/_index.md | 2 +-
docs/misc/_index.md | 2 +-
docs/pagination/_index.md | 2 +-
docs/reordering/_index.md | 2 +-
docs/rows/_index.md | 2 +-
docs/search/_index.md | 2 +-
docs/secondary-header/_index.md | 2 +-
docs/sorting/_index.md | 2 +-
src/Traits/ComponentUtilities.php | 8 +
.../Configuration/ComponentConfiguration.php | 56 +
src/Traits/Helpers/ColumnHelpers.php | 28 +
src/Traits/Helpers/ComponentHelpers.php | 40 +
src/Traits/WithData.php | 26 +-
src/Views/Columns/AggregateColumn.php | 23 +
src/Views/Columns/AvgColumn.php | 18 +
src/Views/Columns/CountColumn.php | 18 +
src/Views/Columns/SumColumn.php | 18 +
.../AggregateColumnConfiguration.php | 59 +
.../ArrayColumnConfiguration.php | 10 +
.../Traits/Helpers/AggregateColumnHelpers.php | 46 +
.../Traits/Helpers/ArrayColumnHelpers.php | 4 -
src/Views/Traits/IsAggregateColumn.php | 14 +
tests/Attributes/AggregateColumnProvider.php | 13 +
tests/Http/Livewire/SpeciesTable.php | 38 +
tests/TestCase.php | 22 +-
.../ComponentConfigurationTest.php | 102 +
tests/Views/Columns/ArrayColumnTest.php | 87 +
tests/Views/Columns/AvgColumnTest.php | 111 +
tests/Views/Columns/CountColumnTest.php | 50 +
tests/Views/Columns/SumColumnTest.php | 111 +
52 files changed, 1260 insertions(+), 3153 deletions(-)
delete mode 100644 coverage.xml
create mode 100644 docs/column-types/_index.md
create mode 100644 docs/column-types/array_column.md
create mode 100644 docs/column-types/avg_column.md
create mode 100644 docs/column-types/boolean_columns.md
create mode 100644 docs/column-types/button_group_column.md
create mode 100644 docs/column-types/color_columns.md
create mode 100644 docs/column-types/component_column.md
create mode 100644 docs/column-types/count_column.md
create mode 100644 docs/column-types/date_columns.md
create mode 100644 docs/column-types/image_columns.md
create mode 100644 docs/column-types/link_columns.md
create mode 100644 docs/column-types/livewire_component_column.md
create mode 100644 docs/column-types/sum_column.md
create mode 100644 src/Views/Columns/AggregateColumn.php
create mode 100644 src/Views/Columns/AvgColumn.php
create mode 100644 src/Views/Columns/CountColumn.php
create mode 100644 src/Views/Columns/SumColumn.php
create mode 100644 src/Views/Traits/Configuration/AggregateColumnConfiguration.php
create mode 100644 src/Views/Traits/Helpers/AggregateColumnHelpers.php
create mode 100644 src/Views/Traits/IsAggregateColumn.php
create mode 100644 tests/Attributes/AggregateColumnProvider.php
create mode 100644 tests/Http/Livewire/SpeciesTable.php
create mode 100644 tests/Views/Columns/ArrayColumnTest.php
create mode 100644 tests/Views/Columns/AvgColumnTest.php
create mode 100644 tests/Views/Columns/CountColumnTest.php
create mode 100644 tests/Views/Columns/SumColumnTest.php
diff --git a/.github/workflows/run-tests-pcov-pull.yml b/.github/workflows/run-tests-pcov-pull.yml
index 3a24a91ba..ef73e4b42 100644
--- a/.github/workflows/run-tests-pcov-pull.yml
+++ b/.github/workflows/run-tests-pcov-pull.yml
@@ -1,6 +1,11 @@
name: run-tests-pcov-pull
on:
+ push:
+ branches:
+ - 'develop'
+ - 'development'
+ - 'master'
pull_request:
branches:
- 'develop'
@@ -18,7 +23,7 @@ jobs:
laravel: [10]
stability: [prefer-dist]
- name: PCOV-PULL - ${{ matrix.os }} - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }}
+ name: PCOV - ${{ matrix.os }} - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }}
env:
extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}-withpcov
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pcov,pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
@@ -86,7 +91,7 @@ jobs:
run: php ./vendor/bin/paratest --cache-directory=".phpunit.cache/code-coverage" --strict-coverage --coverage-clover ./coverage.xml --processes=4
- name: Upload coverage reports to Codecov
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
diff --git a/.gitignore b/.gitignore
index a36981422..d3e4b8ca4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,4 +18,6 @@ phpunit.xml.dist.dev
.history/*
.env
phpunit.xml.bak
-phpstan.txt
\ No newline at end of file
+phpstan.txt
+coverage.xml
+./tmp/**
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6993a50e3..7b13aa903 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
All notable changes to `laravel-livewire-tables` will be documented in this file
+## UNRELEASED
+### New Features
+- Add new columns (ArrayColumn, AvgColumn, CountColumn, SumColumn) by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1761
+
## [v3.2.8] - 2024-07-03
### Bug Fixes
- Fix hide bulk actions when empty not reflecting in frontend by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1747
diff --git a/coverage.xml b/coverage.xml
deleted file mode 100644
index 7428459d2..000000000
--- a/coverage.xml
+++ /dev/null
@@ -1,2894 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/docs/bulk-actions/_index.md b/docs/bulk-actions/_index.md
index f76ab3244..48cb71a17 100644
--- a/docs/bulk-actions/_index.md
+++ b/docs/bulk-actions/_index.md
@@ -1,4 +1,4 @@
---
title: Bulk Actions
-weight: 9
+weight: 10
---
diff --git a/docs/column-types/_index.md b/docs/column-types/_index.md
new file mode 100644
index 000000000..821c869a2
--- /dev/null
+++ b/docs/column-types/_index.md
@@ -0,0 +1,4 @@
+---
+title: Column Types
+weight: 5
+---
diff --git a/docs/column-types/array_column.md b/docs/column-types/array_column.md
new file mode 100644
index 000000000..1571da2b9
--- /dev/null
+++ b/docs/column-types/array_column.md
@@ -0,0 +1,22 @@
+---
+title: Array Columns (beta)
+weight: 1
+---
+
+Array columns provide an easy way to work with and display an array of data from a field.
+
+```
+ArrayColumn::make('notes', 'name')
+ ->data(fn($value, $row) => ($row->notes))
+ ->outputFormat(fn($index, $value) => "".$value->name." ")
+ ->separator(' ')
+ ->sortable(),
+```
+
+### Empty Value
+You may define the default/empty value using the "emptyValue" method
+
+```
+ArrayColumn::make('notes', 'name')
+ ->emptyValue('Unknown'),
+```
\ No newline at end of file
diff --git a/docs/column-types/avg_column.md b/docs/column-types/avg_column.md
new file mode 100644
index 000000000..faa653ca2
--- /dev/null
+++ b/docs/column-types/avg_column.md
@@ -0,0 +1,14 @@
+---
+title: Avg Columns (beta)
+weight: 2
+---
+
+Avg columns provide an easy way to display the "Average" of a field on a relation.
+
+```
+ AvgColumn::make('Average Related User Age')
+ ->setDataSource('users','age')
+ ->sortable(),
+```
+
+The "sortable()" callback can accept a callback, or you can use the default behaviour, which calculates the correct field to sort on.
\ No newline at end of file
diff --git a/docs/column-types/boolean_columns.md b/docs/column-types/boolean_columns.md
new file mode 100644
index 000000000..32a759918
--- /dev/null
+++ b/docs/column-types/boolean_columns.md
@@ -0,0 +1,81 @@
+---
+title: Boolean Columns
+weight: 3
+---
+
+Boolean columns are good if you have a column type that is a true/false, or 0/1 value.
+
+For example:
+
+```php
+BooleanColumn::make('Active')
+```
+
+Would yield:
+
+![Boolean Column](https://imgur.com/LAk6gHY.png)
+
+### Using your own view
+
+If you don't want to use the default view and icons you can set your own:
+
+```php
+BooleanColumn::make('Active')
+ ->setView('my.active.view')
+```
+
+You will have access to `$component`, `$status`, and `$successValue`.
+
+To help you better understand, this is the Tailwind implementation of BooleanColumn:
+
+```html
+@if ($status)
+
+
+
+@else
+
+
+
+@endif
+```
+
+### Setting the truthy value
+
+If you want the false value to be the green option, you can set:
+
+```php
+BooleanColumn::make('Active')
+ ->setSuccessValue(false); // Makes false the 'successful' option
+```
+
+That would swap the colors of the icons in the image above.
+
+### Setting the status value
+
+By default, the `$status` is set to:
+
+```php
+(bool)$value === true
+```
+
+You can override this functionality:
+
+```php
+BooleanColumn::make('Active')
+ // Note: Parameter `$row` available as of v2.4
+ ->setCallback(function(string $value, $row) {
+ // Figure out what makes $value true
+ }),
+```
+
+### Different types of boolean display
+
+By default, the BooleanColumn displays icons.
+
+If you would like the BooleanColumn to display a plain Yes/No, you can set:
+
+```php
+BooleanColumn::make('Active')
+ ->yesNo()
+```
diff --git a/docs/column-types/button_group_column.md b/docs/column-types/button_group_column.md
new file mode 100644
index 000000000..5a3390049
--- /dev/null
+++ b/docs/column-types/button_group_column.md
@@ -0,0 +1,34 @@
+---
+title: Button Group Columns
+weight: 4
+---
+
+Button group columns let you provide an array of LinkColumns to display in a single cell.
+
+```php
+ButtonGroupColumn::make('Actions')
+ ->attributes(function($row) {
+ return [
+ 'class' => 'space-x-2',
+ ];
+ })
+ ->buttons([
+ LinkColumn::make('View') // make() has no effect in this case but needs to be set anyway
+ ->title(fn($row) => 'View ' . $row->name)
+ ->location(fn($row) => route('user.show', $row))
+ ->attributes(function($row) {
+ return [
+ 'class' => 'underline text-blue-500 hover:no-underline',
+ ];
+ }),
+ LinkColumn::make('Edit')
+ ->title(fn($row) => 'Edit ' . $row->name)
+ ->location(fn($row) => route('user.edit', $row))
+ ->attributes(function($row) {
+ return [
+ 'target' => '_blank',
+ 'class' => 'underline text-blue-500 hover:no-underline',
+ ];
+ }),
+ ]),
+```
diff --git a/docs/column-types/color_columns.md b/docs/column-types/color_columns.md
new file mode 100644
index 000000000..e4920144d
--- /dev/null
+++ b/docs/column-types/color_columns.md
@@ -0,0 +1,41 @@
+---
+title: Color Columns
+weight: 5
+---
+
+Color columns provide an easy way to a Color in a Column
+
+You may pass either pass a CSS-compliant colour as a field
+```php
+ColorColumn::make('Favourite Colour', 'favourite_color'),
+```
+
+Or you may use a Callback
+```php
+ColorColumn::make('Favourite Colour')
+ ->color(
+ function ($row) {
+ if ($row->success_rate < 40)
+ {
+ return '#ff0000';
+ }
+ else if ($row->success_rate > 90)
+ {
+ return '#008000';
+ }
+ else return '#ffa500';
+
+ }
+ ),
+```
+
+You may also specify attributes to use on the div displaying the color, to adjust the size or appearance, this receives the full row. By default, this will replace the standard classes, to retain them, set "default" to true. To then over-ride, you should prefix your classes with "!" to signify importance.
+```php
+ ColorColumn::make('Favourite Colour')
+ ->attributes(function ($row) {
+ return [
+ 'class' => '!rounded-lg self-center',
+ 'default' => true,
+ ];
+ }),
+```
diff --git a/docs/column-types/component_column.md b/docs/column-types/component_column.md
new file mode 100644
index 000000000..0db9c9483
--- /dev/null
+++ b/docs/column-types/component_column.md
@@ -0,0 +1,28 @@
+---
+title: Component Columns
+weight: 6
+---
+
+Component columns let you specify a component name and attributes and provides the column value to the slot.
+
+```php
+// Before
+Column::make("Email", "email")
+ ->format(function ($value) {
+ return view('components.alert')
+ ->with('attributes', new ComponentAttributeBag([
+ 'type' => Str::endsWith($value, 'example.org') ? 'success' : 'danger',
+ 'dismissible' => true,
+ ]))
+ ->with('slot', $value);
+ }),
+
+// After
+ComponentColumn::make('E-mail', 'email')
+ ->component('email')
+ ->attributes(fn ($value, $row, Column $column) => [
+ 'type' => Str::endsWith($value, 'example.org') ? 'success' : 'danger',
+ 'dismissible' => true,
+ ]),
+```
+
diff --git a/docs/column-types/count_column.md b/docs/column-types/count_column.md
new file mode 100644
index 000000000..d33cf5df9
--- /dev/null
+++ b/docs/column-types/count_column.md
@@ -0,0 +1,14 @@
+---
+title: Count Columns (beta)
+weight: 7
+---
+
+Count columns provide an easy way to display the "Count" of a relation.
+
+```
+ CountColumn::make('Related Users')
+ ->setDataSource('users')
+ ->sortable(),
+```
+
+The "sortable()" callback can accept a callback, or you can use the default behaviour, which calculates the correct field to sort on.
\ No newline at end of file
diff --git a/docs/column-types/date_columns.md b/docs/column-types/date_columns.md
new file mode 100644
index 000000000..abc8bbb42
--- /dev/null
+++ b/docs/column-types/date_columns.md
@@ -0,0 +1,28 @@
+---
+title: Date Columns
+weight: 8
+---
+
+Date columns provide an easy way to display dates in a given format, without having to use repetitive format() methods or partial views.
+
+You may pass either a DateTime object, in which you can define an "outputFormat"
+```php
+DateColumn::make('Updated At', 'updated_at')
+ ->outputFormat('Y-m-d H:i:s),
+```
+
+Or you may pass a string, in which case you can define an "inputFormat" in addition to the outputFormat:
+```php
+DateColumn::make('Last Charged', 'last_charged_at')
+ ->inputFormat('Y-m-d H:i:s')
+ ->outputFormat('Y-m-d'),
+```
+
+You may also set an "emptyValue" to use when there is no value from the database:
+```php
+DateColumn::make('Last Charged', 'last_charged_at')
+ ->inputFormat('Y-m-d H:i:s')
+ ->outputFormat('Y-m-d')
+ ->emptyValue('Not Found'),
+```
+
diff --git a/docs/column-types/image_columns.md b/docs/column-types/image_columns.md
new file mode 100644
index 000000000..f816280af
--- /dev/null
+++ b/docs/column-types/image_columns.md
@@ -0,0 +1,26 @@
+---
+title: Image Columns
+weight: 9
+---
+
+Image columns provide a way to display images in your table without having to use `format()` or partial views:
+
+```php
+ImageColumn::make('Avatar')
+ ->location(
+ fn($row) => storage_path('app/public/avatars/' . $row->id . '.jpg')
+ ),
+```
+
+You may also pass an array of attributes to apply to the image tag:
+
+```php
+ImageColumn::make('Avatar')
+ ->location(
+ fn($row) => storage_path('app/public/avatars/' . $row->id . '.jpg')
+ )
+ ->attributes(fn($row) => [
+ 'class' => 'rounded-full',
+ 'alt' => $row->name . ' Avatar',
+ ]),
+```
diff --git a/docs/column-types/link_columns.md b/docs/column-types/link_columns.md
new file mode 100644
index 000000000..cba4bc887
--- /dev/null
+++ b/docs/column-types/link_columns.md
@@ -0,0 +1,24 @@
+---
+title: Link Columns
+weight: 10
+---
+
+Link columns provide a way to display HTML links in your table without having to use `format()` or partial views:
+
+```php
+LinkColumn::make('Action')
+ ->title(fn($row) => 'Edit')
+ ->location(fn($row) => route('admin.users.edit', $row)),
+```
+
+You may also pass an array of attributes to apply to the `a` tag:
+
+```php
+LinkColumn::make('Action')
+ ->title(fn($row) => 'Edit')
+ ->location(fn($row) => route('admin.users.edit', $row))
+ ->attributes(fn($row) => [
+ 'class' => 'rounded-full',
+ 'alt' => $row->name . ' Avatar',
+ ]),
+```
diff --git a/docs/column-types/livewire_component_column.md b/docs/column-types/livewire_component_column.md
new file mode 100644
index 000000000..b75172881
--- /dev/null
+++ b/docs/column-types/livewire_component_column.md
@@ -0,0 +1,5 @@
+---
+title: Livewire Component (beta)
+weight: 11
+---
+
diff --git a/docs/column-types/sum_column.md b/docs/column-types/sum_column.md
new file mode 100644
index 000000000..7f99f7cab
--- /dev/null
+++ b/docs/column-types/sum_column.md
@@ -0,0 +1,14 @@
+---
+title: Sum Columns (beta)
+weight: 12
+---
+
+Sum columns provide an easy way to display the "Sum" of a field on a relation.
+
+```
+ SumColumn::make('Total Age of Related Users')
+ ->setDataSource('users','age')
+ ->sortable(),
+```
+
+The "sortable()" callback can accept a callback, or you can use the default behaviour, which calculates the correct field to sort on.
\ No newline at end of file
diff --git a/docs/columns/other-column-types.md b/docs/columns/other-column-types.md
index dc80da449..2e515eedf 100644
--- a/docs/columns/other-column-types.md
+++ b/docs/columns/other-column-types.md
@@ -3,247 +3,14 @@ title: Other Column Types
weight: 4
---
-## Boolean Columns
-Boolean columns are good if you have a column type that is a true/false, or 0/1 value.
-For example:
-```php
-BooleanColumn::make('Active')
-```
-Would yield:
+## Aggregate Columns
-![Boolean Column](https://imgur.com/LAk6gHY.png)
+### AvgColumn
-### Using your own view
+### CountColumn
-If you don't want to use the default view and icons you can set your own:
-
-```php
-BooleanColumn::make('Active')
- ->setView('my.active.view')
-```
-
-You will have access to `$component`, `$status`, and `$successValue`.
-
-To help you better understand, this is the Tailwind implementation of BooleanColumn:
-
-```html
-@if ($status)
-
-
-
-@else
-
-
-
-@endif
-```
-
-### Setting the truthy value
-
-If you want the false value to be the green option, you can set:
-
-```php
-BooleanColumn::make('Active')
- ->setSuccessValue(false); // Makes false the 'successful' option
-```
-
-That would swap the colors of the icons in the image above.
-
-### Setting the status value
-
-By default, the `$status` is set to:
-
-```php
-(bool)$value === true
-```
-
-You can override this functionality:
-
-```php
-BooleanColumn::make('Active')
- // Note: Parameter `$row` available as of v2.4
- ->setCallback(function(string $value, $row) {
- // Figure out what makes $value true
- }),
-```
-
-### Different types of boolean display
-
-By default, the BooleanColumn displays icons.
-
-If you would like the BooleanColumn to display a plain Yes/No, you can set:
-
-```php
-BooleanColumn::make('Active')
- ->yesNo()
-```
-## Color Columns
-
-Color columns provide an easy way to a Color in a Column
-
-You may pass either pass a CSS-compliant colour as a field
-```php
-ColorColumn::make('Favourite Colour', 'favourite_color'),
-```
-
-Or you may use a Callback
-```php
-ColorColumn::make('Favourite Colour')
- ->color(
- function ($row) {
- if ($row->success_rate < 40)
- {
- return '#ff0000';
- }
- else if ($row->success_rate > 90)
- {
- return '#008000';
- }
- else return '#ffa500';
-
- }
- ),
-```
-
-You may also specify attributes to use on the div displaying the color, to adjust the size or appearance, this receives the full row. By default, this will replace the standard classes, to retain them, set "default" to true. To then over-ride, you should prefix your classes with "!" to signify importance.
-```php
- ColorColumn::make('Favourite Colour')
- ->attributes(function ($row) {
- return [
- 'class' => '!rounded-lg self-center',
- 'default' => true,
- ];
- }),
-```
-
-## Date Columns
-
-Date columns provide an easy way to display dates in a given format, without having to use repetitive format() methods or partial views.
-
-You may pass either a DateTime object, in which you can define an "outputFormat"
-```php
-DateColumn::make('Updated At', 'updated_at')
- ->outputFormat('Y-m-d H:i:s),
-```
-
-Or you may pass a string, in which case you can define an "inputFormat" in addition to the outputFormat:
-```php
-DateColumn::make('Last Charged', 'last_charged_at')
- ->inputFormat('Y-m-d H:i:s')
- ->outputFormat('Y-m-d'),
-```
-
-You may also set an "emptyValue" to use when there is no value from the database:
-```php
-DateColumn::make('Last Charged', 'last_charged_at')
- ->inputFormat('Y-m-d H:i:s')
- ->outputFormat('Y-m-d')
- ->emptyValue('Not Found'),
-```
-
-## Image Columns
-
-Image columns provide a way to display images in your table without having to use `format()` or partial views:
-
-```php
-ImageColumn::make('Avatar')
- ->location(
- fn($row) => storage_path('app/public/avatars/' . $row->id . '.jpg')
- ),
-```
-
-You may also pass an array of attributes to apply to the image tag:
-
-```php
-ImageColumn::make('Avatar')
- ->location(
- fn($row) => storage_path('app/public/avatars/' . $row->id . '.jpg')
- )
- ->attributes(fn($row) => [
- 'class' => 'rounded-full',
- 'alt' => $row->name . ' Avatar',
- ]),
-```
-
-## Link Columns
-
-Link columns provide a way to display HTML links in your table without having to use `format()` or partial views:
-
-```php
-LinkColumn::make('Action')
- ->title(fn($row) => 'Edit')
- ->location(fn($row) => route('admin.users.edit', $row)),
-```
-
-You may also pass an array of attributes to apply to the `a` tag:
-
-```php
-LinkColumn::make('Action')
- ->title(fn($row) => 'Edit')
- ->location(fn($row) => route('admin.users.edit', $row))
- ->attributes(fn($row) => [
- 'class' => 'rounded-full',
- 'alt' => $row->name . ' Avatar',
- ]),
-```
-
-## Button Group Columns
-
-Button group columns let you provide an array of LinkColumns to display in a single cell.
-
-```php
-ButtonGroupColumn::make('Actions')
- ->attributes(function($row) {
- return [
- 'class' => 'space-x-2',
- ];
- })
- ->buttons([
- LinkColumn::make('View') // make() has no effect in this case but needs to be set anyway
- ->title(fn($row) => 'View ' . $row->name)
- ->location(fn($row) => route('user.show', $row))
- ->attributes(function($row) {
- return [
- 'class' => 'underline text-blue-500 hover:no-underline',
- ];
- }),
- LinkColumn::make('Edit')
- ->title(fn($row) => 'Edit ' . $row->name)
- ->location(fn($row) => route('user.edit', $row))
- ->attributes(function($row) {
- return [
- 'target' => '_blank',
- 'class' => 'underline text-blue-500 hover:no-underline',
- ];
- }),
- ]),
-```
-
-## Component Columns
-
-Component columns let you specify a component name and attributes and provides the column value to the slot.
-
-```php
-// Before
-Column::make("Email", "email")
- ->format(function ($value) {
- return view('components.alert')
- ->with('attributes', new ComponentAttributeBag([
- 'type' => Str::endsWith($value, 'example.org') ? 'success' : 'danger',
- 'dismissible' => true,
- ]))
- ->with('slot', $value);
- }),
-
-// After
-ComponentColumn::make('E-mail', 'email')
- ->component('email')
- ->attributes(fn ($value, $row, Column $column) => [
- 'type' => Str::endsWith($value, 'example.org') ? 'success' : 'danger',
- 'dismissible' => true,
- ]),
-```
+### SumColumn
\ No newline at end of file
diff --git a/docs/examples/_index.md b/docs/examples/_index.md
index a831d1a26..03b1d982b 100644
--- a/docs/examples/_index.md
+++ b/docs/examples/_index.md
@@ -1,4 +1,4 @@
---
title: Examples
-weight: 14
+weight: 16
---
diff --git a/docs/filter-types/_index.md b/docs/filter-types/_index.md
index 6c6d8ccf4..3631183ba 100644
--- a/docs/filter-types/_index.md
+++ b/docs/filter-types/_index.md
@@ -1,4 +1,4 @@
---
title: Filter Types
-weight: 11
+weight: 12
---
diff --git a/docs/filters/_index.md b/docs/filters/_index.md
index 43af373bd..e0ac299f1 100644
--- a/docs/filters/_index.md
+++ b/docs/filters/_index.md
@@ -1,4 +1,4 @@
---
title: Filters
-weight: 10
+weight: 11
---
diff --git a/docs/footer/_index.md b/docs/footer/_index.md
index e16f7efb5..4edcb2460 100644
--- a/docs/footer/_index.md
+++ b/docs/footer/_index.md
@@ -1,4 +1,4 @@
---
title: Footer
-weight: 13
+weight: 15
---
diff --git a/docs/misc/_index.md b/docs/misc/_index.md
index 9f806b32e..193fabdf4 100644
--- a/docs/misc/_index.md
+++ b/docs/misc/_index.md
@@ -1,4 +1,4 @@
---
title: Misc.
-weight: 15
+weight: 17
---
diff --git a/docs/pagination/_index.md b/docs/pagination/_index.md
index 723cb0c11..50491640d 100644
--- a/docs/pagination/_index.md
+++ b/docs/pagination/_index.md
@@ -1,4 +1,4 @@
---
title: Pagination
-weight: 7
+weight: 8
---
diff --git a/docs/reordering/_index.md b/docs/reordering/_index.md
index bc21a450b..e66081c28 100644
--- a/docs/reordering/_index.md
+++ b/docs/reordering/_index.md
@@ -1,4 +1,4 @@
---
title: Reordering
-weight: 11
+weight: 13
---
diff --git a/docs/rows/_index.md b/docs/rows/_index.md
index f731c19d2..7d5ebba99 100644
--- a/docs/rows/_index.md
+++ b/docs/rows/_index.md
@@ -1,4 +1,4 @@
---
title: Rows
-weight: 5
+weight: 6
---
diff --git a/docs/search/_index.md b/docs/search/_index.md
index edb174fde..4aac1542b 100644
--- a/docs/search/_index.md
+++ b/docs/search/_index.md
@@ -1,4 +1,4 @@
---
title: Search
-weight: 8
+weight: 9
---
diff --git a/docs/secondary-header/_index.md b/docs/secondary-header/_index.md
index 5e2b9aba5..f334c9e68 100644
--- a/docs/secondary-header/_index.md
+++ b/docs/secondary-header/_index.md
@@ -1,4 +1,4 @@
---
title: Secondary Header
-weight: 12
+weight: 14
---
diff --git a/docs/sorting/_index.md b/docs/sorting/_index.md
index a99eabf1d..422739fb6 100644
--- a/docs/sorting/_index.md
+++ b/docs/sorting/_index.md
@@ -1,4 +1,4 @@
---
title: Sorting
-weight: 6
+weight: 7
---
diff --git a/src/Traits/ComponentUtilities.php b/src/Traits/ComponentUtilities.php
index 1e421e0b6..8ec4bd8b6 100644
--- a/src/Traits/ComponentUtilities.php
+++ b/src/Traits/ComponentUtilities.php
@@ -37,6 +37,14 @@ trait ComponentUtilities
protected array $additionalSelects = [];
+ protected array $extraWiths = [];
+
+ protected array $extraWithCounts = [];
+
+ protected array $extraWithSums = [];
+
+ protected array $extraWithAvgs = [];
+
/**
* Set any configuration options
*/
diff --git a/src/Traits/Configuration/ComponentConfiguration.php b/src/Traits/Configuration/ComponentConfiguration.php
index 90611185a..044f5655e 100644
--- a/src/Traits/Configuration/ComponentConfiguration.php
+++ b/src/Traits/Configuration/ComponentConfiguration.php
@@ -96,4 +96,60 @@ public function setDataTableFingerprint(string $dataTableFingerprint): self
return $this;
}
+
+ public function setExtraWiths(array $extraWiths): self
+ {
+ $this->extraWiths = $extraWiths;
+
+ return $this;
+ }
+
+ public function addExtraWith(string $extraWith): self
+ {
+ $this->extraWiths[] = $extraWith;
+
+ return $this;
+ }
+
+ public function addExtraWiths(array $extraWiths): self
+ {
+ $this->extraWiths = [...$this->extraWiths, ...$extraWiths];
+
+ return $this;
+ }
+
+ public function setExtraWithCounts(array $extraWithCounts): self
+ {
+ $this->extraWithCounts = $extraWithCounts;
+
+ return $this;
+ }
+
+ public function addExtraWithCount(string $extraWithCount): self
+ {
+ $this->extraWithCounts[] = $extraWithCount;
+
+ return $this;
+ }
+
+ public function addExtraWithCounts(array $extraWithCounts): self
+ {
+ $this->extraWithCounts = [...$this->extraWithCounts, ...$extraWithCounts];
+
+ return $this;
+ }
+
+ public function addExtraWithSum(string $relationship, string $column): self
+ {
+ $this->extraWithSums[] = ['table' => $relationship, 'field' => $column];
+
+ return $this;
+ }
+
+ public function addExtraWithAvg(string $relationship, string $column): self
+ {
+ $this->extraWithAvgs[] = ['table' => $relationship, 'field' => $column];
+
+ return $this;
+ }
}
diff --git a/src/Traits/Helpers/ColumnHelpers.php b/src/Traits/Helpers/ColumnHelpers.php
index 009a6f4bd..920d63fe6 100644
--- a/src/Traits/Helpers/ColumnHelpers.php
+++ b/src/Traits/Helpers/ColumnHelpers.php
@@ -4,6 +4,7 @@
use Illuminate\Support\Collection;
use Rappasoft\LaravelLivewireTables\Views\Column;
+use Rappasoft\LaravelLivewireTables\Views\Columns\AggregateColumn;
trait ColumnHelpers
{
@@ -18,6 +19,15 @@ public function setColumns(): void
->filter(fn ($column) => $column instanceof Column)
->map(function (Column $column) {
$column->setComponent($this);
+ if ($column instanceof AggregateColumn) {
+ if ($column->getAggregateMethod() == 'count' && $column->hasDataSource()) {
+ $this->addExtraWithCount($column->getDataSource());
+ } elseif ($column->getAggregateMethod() == 'sum' && $column->hasDataSource() && $column->hasForeignColumn()) {
+ $this->addExtraWithSum($column->getDataSource(), $column->getForeignColumn());
+ } elseif ($column->getAggregateMethod() == 'avg' && $column->hasDataSource() && $column->hasForeignColumn()) {
+ $this->addExtraWithAvg($column->getDataSource(), $column->getForeignColumn());
+ }
+ }
if ($column->hasField()) {
if ($column->isBaseColumn()) {
@@ -198,6 +208,15 @@ public function getPrependedColumns(): Collection
->filter(fn ($column) => $column instanceof Column)
->map(function (Column $column) {
$column->setComponent($this);
+ if ($column instanceof AggregateColumn) {
+ if ($column->getAggregateMethod() == 'count' && $column->hasDataSource()) {
+ $this->addExtraWithCount($column->getDataSource());
+ } elseif ($column->getAggregateMethod() == 'sum' && $column->hasDataSource() && $column->hasForeignColumn()) {
+ $this->addExtraWithSum($column->getDataSource(), $column->getForeignColumn());
+ } elseif ($column->getAggregateMethod() == 'avg' && $column->hasDataSource() && $column->hasForeignColumn()) {
+ $this->addExtraWithAvg($column->getDataSource(), $column->getForeignColumn());
+ }
+ }
if ($column->hasField()) {
if ($column->isBaseColumn()) {
@@ -217,6 +236,15 @@ public function getAppendedColumns(): Collection
->filter(fn ($column) => $column instanceof Column)
->map(function (Column $column) {
$column->setComponent($this);
+ if ($column instanceof AggregateColumn) {
+ if ($column->getAggregateMethod() == 'count' && $column->hasDataSource()) {
+ $this->addExtraWithCount($column->getDataSource());
+ } elseif ($column->getAggregateMethod() == 'sum' && $column->hasDataSource() && $column->hasForeignColumn()) {
+ $this->addExtraWithSum($column->getDataSource(), $column->getForeignColumn());
+ } elseif ($column->getAggregateMethod() == 'avg' && $column->hasDataSource() && $column->hasForeignColumn()) {
+ $this->addExtraWithAvg($column->getDataSource(), $column->getForeignColumn());
+ }
+ }
if ($column->hasField()) {
if ($column->isBaseColumn()) {
diff --git a/src/Traits/Helpers/ComponentHelpers.php b/src/Traits/Helpers/ComponentHelpers.php
index c600200b5..96eae35f8 100644
--- a/src/Traits/Helpers/ComponentHelpers.php
+++ b/src/Traits/Helpers/ComponentHelpers.php
@@ -149,4 +149,44 @@ public function getAdditionalSelects(): array
{
return $this->additionalSelects;
}
+
+ public function hasExtraWiths(): bool
+ {
+ return ! empty($this->extraWiths);
+ }
+
+ public function getExtraWiths(): array
+ {
+ return $this->extraWiths;
+ }
+
+ public function hasExtraWithCounts(): bool
+ {
+ return ! empty($this->extraWithCounts);
+ }
+
+ public function getExtraWithCounts(): array
+ {
+ return $this->extraWithCounts;
+ }
+
+ public function hasExtraWithSums(): bool
+ {
+ return ! empty($this->extraWithSums);
+ }
+
+ public function getExtraWithSums(): array
+ {
+ return $this->extraWithSums;
+ }
+
+ public function hasExtraWithAvgs(): bool
+ {
+ return ! empty($this->extraWithAvgs);
+ }
+
+ public function getExtraWithAvgs(): array
+ {
+ return $this->extraWithAvgs;
+ }
}
diff --git a/src/Traits/WithData.php b/src/Traits/WithData.php
index 5e1ca3298..23d1055bb 100644
--- a/src/Traits/WithData.php
+++ b/src/Traits/WithData.php
@@ -56,6 +56,29 @@ protected function baseQuery(): Builder
$this->setBuilder($this->applyFilters());
+ $builder = $this->getBuilder();
+
+ if ($this->hasExtraWiths()) {
+ $builder->with($this->getExtraWiths());
+ }
+
+ if ($this->hasExtraWithSums()) {
+ foreach ($this->getExtraWithSums() as $extraSum) {
+ $builder->withSum($extraSum['table'], $extraSum['field']);
+ }
+ }
+ if ($this->hasExtraWithAvgs()) {
+ foreach ($this->getExtraWithAvgs() as $extraAvg) {
+ $builder->withAvg($extraAvg['table'], $extraAvg['field']);
+ }
+ }
+
+ if ($this->hasExtraWithCounts()) {
+ $builder->withCount($this->getExtraWithCounts());
+ }
+
+ $this->setBuilder($builder);
+
return $this->getBuilder();
}
@@ -249,7 +272,8 @@ protected function getTableAlias(?string $currentTableAlias, string $relationPar
public function builder(): Builder
{
if ($this->hasModel()) {
- return $this->getModel()::query()->with($this->getRelationships());
+ return $this->getModel()::query()
+ ->with($this->getRelationships());
}
// If model does not exist
diff --git a/src/Views/Columns/AggregateColumn.php b/src/Views/Columns/AggregateColumn.php
new file mode 100644
index 000000000..a284b08ff
--- /dev/null
+++ b/src/Views/Columns/AggregateColumn.php
@@ -0,0 +1,23 @@
+label(fn () => null);
+ }
+}
diff --git a/src/Views/Columns/AvgColumn.php b/src/Views/Columns/AvgColumn.php
new file mode 100644
index 000000000..3af197873
--- /dev/null
+++ b/src/Views/Columns/AvgColumn.php
@@ -0,0 +1,18 @@
+label(fn () => null);
+ }
+}
diff --git a/src/Views/Columns/CountColumn.php b/src/Views/Columns/CountColumn.php
new file mode 100644
index 000000000..4a1ffd812
--- /dev/null
+++ b/src/Views/Columns/CountColumn.php
@@ -0,0 +1,18 @@
+label(fn () => null);
+ }
+}
diff --git a/src/Views/Columns/SumColumn.php b/src/Views/Columns/SumColumn.php
new file mode 100644
index 000000000..a01822d7b
--- /dev/null
+++ b/src/Views/Columns/SumColumn.php
@@ -0,0 +1,18 @@
+label(fn () => null);
+ }
+}
diff --git a/src/Views/Traits/Configuration/AggregateColumnConfiguration.php b/src/Views/Traits/Configuration/AggregateColumnConfiguration.php
new file mode 100644
index 000000000..2f181ed2f
--- /dev/null
+++ b/src/Views/Traits/Configuration/AggregateColumnConfiguration.php
@@ -0,0 +1,59 @@
+dataSource = $dataSource;
+
+ if (isset($foreignColumn)) {
+ $this->setForeignColumn($foreignColumn);
+ }
+
+ $this->setDefaultLabel();
+
+ return $this;
+ }
+
+ public function setAggregateMethod(string $aggregateMethod): self
+ {
+ $this->aggregateMethod = $aggregateMethod;
+ $this->setDefaultLabel();
+
+ return $this;
+ }
+
+ public function setForeignColumn(string $foreignColumn): self
+ {
+ $this->foreignColumn = $foreignColumn;
+ $this->setDefaultLabel();
+
+ return $this;
+ }
+
+ public function setDefaultLabel(): void
+ {
+ $this->label(function ($row, Column $column) {
+ if ($this->hasForeignColumn()) {
+ return $row->{$this->getDataSource().'_'.$this->getAggregateMethod().'_'.$this->getForeignColumn()};
+ }
+
+ return $row->{$this->getDataSource().'_'.$this->getAggregateMethod()};
+ });
+
+ }
+
+ public function sortable(?callable $callback = null): self
+ {
+ $this->sortable = true;
+
+ $this->sortCallback = ($callback === null) ? ($this->hasForeignColumn() ? fn (Builder $query, string $direction) => $query->orderBy($this->getDataSource().'_'.$this->getAggregateMethod().'_'.$this->getForeignColumn(), $direction) : fn (Builder $query, string $direction) => $query->orderBy($this->dataSource.'_count', $direction)) : $callback;
+
+ return $this;
+ }
+}
diff --git a/src/Views/Traits/Configuration/ArrayColumnConfiguration.php b/src/Views/Traits/Configuration/ArrayColumnConfiguration.php
index 72188fd79..c0f7657b7 100644
--- a/src/Views/Traits/Configuration/ArrayColumnConfiguration.php
+++ b/src/Views/Traits/Configuration/ArrayColumnConfiguration.php
@@ -26,4 +26,14 @@ public function outputFormat(callable $callable): self
return $this;
}
+
+ /**
+ * Define the Empty Value to use for the Column
+ */
+ public function emptyValue(string $emptyValue): self
+ {
+ $this->emptyValue = $emptyValue;
+
+ return $this;
+ }
}
diff --git a/src/Views/Traits/Helpers/AggregateColumnHelpers.php b/src/Views/Traits/Helpers/AggregateColumnHelpers.php
new file mode 100644
index 000000000..1748b8091
--- /dev/null
+++ b/src/Views/Traits/Helpers/AggregateColumnHelpers.php
@@ -0,0 +1,46 @@
+dataSource;
+ }
+
+ public function hasDataSource(): bool
+ {
+ return isset($this->dataSource);
+ }
+
+ public function getAggregateMethod(): string
+ {
+ return $this->aggregateMethod;
+ }
+
+ public function hasForeignColumn(): bool
+ {
+ return isset($this->foreignColumn);
+ }
+
+ public function getForeignColumn(): string
+ {
+ return $this->foreignColumn;
+ }
+
+ public function getContents(Model $row): null|string|\BackedEnum|HtmlString|DataTableConfigurationException|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
+ {
+ if (! isset($this->dataSource)) {
+ throw new DataTableConfigurationException('You must specify a data source');
+ } else {
+ return parent::getContents($row);
+ }
+ }
+}
diff --git a/src/Views/Traits/Helpers/ArrayColumnHelpers.php b/src/Views/Traits/Helpers/ArrayColumnHelpers.php
index 7c32f7c70..8289038e4 100644
--- a/src/Views/Traits/Helpers/ArrayColumnHelpers.php
+++ b/src/Views/Traits/Helpers/ArrayColumnHelpers.php
@@ -48,10 +48,6 @@ public function getContents(Model $row): null|string|\BackedEnum|HtmlString|Data
$outputValues = [];
$value = $this->getValue($row);
- if (! $this->hasSeparator()) {
- throw new DataTableConfigurationException('You must set a valid separator on an ArrayColumn');
- }
-
if (! $this->hasDataCallback()) {
throw new DataTableConfigurationException('You must set a data() method on an ArrayColumn');
}
diff --git a/src/Views/Traits/IsAggregateColumn.php b/src/Views/Traits/IsAggregateColumn.php
new file mode 100644
index 000000000..1824118b9
--- /dev/null
+++ b/src/Views/Traits/IsAggregateColumn.php
@@ -0,0 +1,14 @@
+setPrimaryKey('id');
+ }
+
+ public function columns(): array
+ {
+ return [
+ Column::make('ID', 'id')
+ ->sortable()
+ ->setSortingPillTitle('Key')
+ ->setSortingPillDirections('0-9', '9-0'),
+ Column::make('Name')
+ ->sortable()
+ ->searchable(),
+ AvgColumn::make('Average Age')
+ ->setDataSource('pets', 'age'),
+ CountColumn::make('Number of Pets')
+ ->setDataSource('pets'),
+ SumColumn::make('Total Age')
+ ->setDataSource('pets', 'age'),
+
+ ];
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
index fdcbd44a6..ab22227bd 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -9,7 +9,7 @@
use Livewire\LivewireServiceProvider;
use Orchestra\Testbench\TestCase as Orchestra;
use Rappasoft\LaravelLivewireTables\LaravelLivewireTablesServiceProvider;
-use Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\{PetsTable,PetsTableUnpaginated};
+use Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\{PetsTable,PetsTableUnpaginated,SpeciesTable};
use Rappasoft\LaravelLivewireTables\Tests\Models\Breed;
use Rappasoft\LaravelLivewireTables\Tests\Models\Pet;
use Rappasoft\LaravelLivewireTables\Tests\Models\Species;
@@ -19,6 +19,8 @@ class TestCase extends Orchestra
{
public PetsTable $basicTable;
+ public SpeciesTable $speciesTable;
+
public PetsTableUnpaginated $unpaginatedTable;
/**
@@ -76,7 +78,7 @@ protected function setUp(): void
}
$this->setupBasicTable();
$this->setupUnpaginatedTable();
-
+ $this->setupSpeciesTable();
}
protected function setupBasicTable()
@@ -95,6 +97,22 @@ protected function setupBasicTable()
$this->basicTable->render();
}
+ protected function setupSpeciesTable()
+ {
+ $view = view('livewire-tables::datatable');
+ $this->speciesTable = new SpeciesTable();
+ $this->speciesTable->boot();
+ $this->speciesTable->bootedComponentUtilities();
+ $this->speciesTable->bootedWithData();
+ $this->speciesTable->bootedWithColumns();
+ $this->speciesTable->bootedWithColumnSelect();
+ $this->speciesTable->bootedWithSecondaryHeader();
+ $this->speciesTable->booted();
+ $this->speciesTable->renderingWithData($view, []);
+ $this->speciesTable->renderingWithPagination($view, []);
+ $this->speciesTable->render();
+ }
+
protected function setupUnpaginatedTable()
{
diff --git a/tests/Traits/Configuration/ComponentConfigurationTest.php b/tests/Traits/Configuration/ComponentConfigurationTest.php
index 001cea2a0..3bed87443 100644
--- a/tests/Traits/Configuration/ComponentConfigurationTest.php
+++ b/tests/Traits/Configuration/ComponentConfigurationTest.php
@@ -300,4 +300,106 @@ public function test_can_set_hide_configurable_areas_when_reordering_status(): v
$this->basicTable->setHideConfigurableAreasWhenReorderingStatus(true);
}
+
+ public function test_no_extra_withs_by_default(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWiths());
+ $this->assertEmpty($this->basicTable->getExtraWiths());
+ }
+
+ public function test_can_add_extra_with(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWiths());
+ $this->assertEmpty($this->basicTable->getExtraWiths());
+ $this->basicTable->addExtraWith('user');
+ $this->assertTrue($this->basicTable->hasExtraWiths());
+ $this->assertSame(['user'], $this->basicTable->getExtraWiths());
+ }
+
+ public function test_can_add_extra_withs(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWiths());
+ $this->assertEmpty($this->basicTable->getExtraWiths());
+ $this->basicTable->addExtraWiths(['user', 'pets']);
+ $this->assertTrue($this->basicTable->hasExtraWiths());
+ $this->assertSame(['user', 'pets'], $this->basicTable->getExtraWiths());
+ }
+
+ public function test_can_set_extra_withs(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWiths());
+ $this->assertEmpty($this->basicTable->getExtraWiths());
+ $this->basicTable->addExtraWith('test');
+ $this->assertSame(['test'], $this->basicTable->getExtraWiths());
+ $this->assertTrue($this->basicTable->hasExtraWiths());
+ $this->basicTable->setExtraWiths(['user', 'pets']);
+ $this->assertTrue($this->basicTable->hasExtraWiths());
+ $this->assertSame(['user', 'pets'], $this->basicTable->getExtraWiths());
+ }
+
+ public function test_no_extra_with_counts_by_default(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWithCounts());
+ $this->assertEmpty($this->basicTable->getExtraWithCounts());
+ }
+
+ public function test_can_add_extra_with_count(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWithCounts());
+ $this->assertEmpty($this->basicTable->getExtraWithCounts());
+ $this->basicTable->addExtraWithCount('users');
+ $this->assertTrue($this->basicTable->hasExtraWithCounts());
+ $this->assertSame(['users'], $this->basicTable->getExtraWithCounts());
+ }
+
+ public function test_can_add_extra_with_counts(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWithCounts());
+ $this->assertEmpty($this->basicTable->getExtraWithCounts());
+ $this->basicTable->addExtraWithCounts(['user', 'pets']);
+ $this->assertTrue($this->basicTable->hasExtraWithCounts());
+ $this->assertSame(['user', 'pets'], $this->basicTable->getExtraWithCounts());
+ }
+
+ public function test_can_set_extra_with_counts(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWithCounts());
+ $this->assertEmpty($this->basicTable->getExtraWithCounts());
+ $this->basicTable->addExtraWithCount('test');
+ $this->assertSame(['test'], $this->basicTable->getExtraWithCounts());
+ $this->assertTrue($this->basicTable->hasExtraWithCounts());
+ $this->basicTable->setExtraWithCounts(['user', 'pets']);
+ $this->assertTrue($this->basicTable->hasExtraWithCounts());
+ $this->assertSame(['user', 'pets'], $this->basicTable->getExtraWithCounts());
+ }
+
+ public function test_no_extra_with_sums_by_default(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWithSums());
+ $this->assertEmpty($this->basicTable->getExtraWithSums());
+ }
+
+ public function test_can_add_extra_with_sum(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWithSums());
+ $this->assertEmpty($this->basicTable->getExtraWithSums());
+ $this->basicTable->addExtraWithSum('users', 'age');
+ $this->assertTrue($this->basicTable->hasExtraWithSums());
+ $this->assertSame([['table' => 'users', 'field' => 'age']], $this->basicTable->getExtraWithSums());
+ }
+
+ public function test_no_extra_with_avgs_by_default(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWiths());
+ $this->assertEmpty($this->basicTable->getExtraWiths());
+ }
+
+ public function test_can_add_extra_with_avg(): void
+ {
+ $this->assertFalse($this->basicTable->hasExtraWithAvgs());
+ $this->assertEmpty($this->basicTable->getExtraWithAvgs());
+ $this->basicTable->addExtraWithAvg('user', 'age');
+ $this->assertTrue($this->basicTable->hasExtraWithAvgs());
+ $this->assertSame([['table' => 'user', 'field' => 'age']], $this->basicTable->getExtraWithAvgs());
+ }
}
diff --git a/tests/Views/Columns/ArrayColumnTest.php b/tests/Views/Columns/ArrayColumnTest.php
new file mode 100644
index 000000000..0eff2808b
--- /dev/null
+++ b/tests/Views/Columns/ArrayColumnTest.php
@@ -0,0 +1,87 @@
+assertSame('Array Col', $column->getTitle());
+ }
+
+ public function test_can_set_the_separator(): void
+ {
+ $column = ArrayColumn::make('Array Col');
+
+ $this->assertSame(' ', $column->getSeparator());
+ $column->separator(' ');
+ $this->assertTrue($column->hasSeparator());
+
+ $this->assertSame(' ', $column->getSeparator());
+ }
+
+ public function test_can_set_the_output_format(): void
+ {
+ $column = ArrayColumn::make('Array Col');
+
+ $this->assertNull($column->getOutputFormatCallback());
+ $this->assertFalse($column->hasOutputFormatCallback());
+ $column->outputFormat(fn ($index, $value) => "".$value->name.' ');
+ $this->assertTrue($column->hasOutputFormatCallback());
+ }
+
+ public function test_requires_the_data_callback(): void
+ {
+ $this->expectException(DataTableConfigurationException::class);
+ $column = ArrayColumn::make('Average Age')
+ ->separator(' ')
+ ->sortable();
+ $contents = $column->getContents(Pet::find(1));
+ $this->assertNull($contents);
+ }
+
+ public function test_can_get_the_output_format_callback(): void
+ {
+ $this->expectException(DataTableConfigurationException::class);
+ $column = ArrayColumn::make('Average Age')
+ ->separator(' ')
+ ->data(fn ($value, $row) => ($row->pets))
+ ->sortable();
+ $this->assertNotNull($column->getDataCallback());
+
+ $contents = $column->getContents(Pet::find(1));
+ $this->assertNull($contents);
+ }
+
+ public function test_requires_the_output_format_callback(): void
+ {
+ $this->expectException(DataTableConfigurationException::class);
+ $column = ArrayColumn::make('Average Age')
+ ->separator(' ')
+ ->data(fn ($value, $row) => ($row->pets))
+ ->sortable();
+
+ $contents = $column->getContents(Pet::find(1));
+ $this->assertNull($contents);
+ }
+
+ public function test_can_get_empty_value(): void
+ {
+ $column = ArrayColumn::make('Average Age')
+ ->separator(' ')
+ ->data(fn ($value, $row) => ($row->pets))
+ ->sortable();
+
+ $this->assertSame('', $column->getEmptyValue());
+ $column->emptyValue('Unknown');
+ $this->assertSame('Unknown', $column->getEmptyValue());
+
+ }
+}
diff --git a/tests/Views/Columns/AvgColumnTest.php b/tests/Views/Columns/AvgColumnTest.php
new file mode 100644
index 000000000..f3657c710
--- /dev/null
+++ b/tests/Views/Columns/AvgColumnTest.php
@@ -0,0 +1,111 @@
+assertSame('Average Age', $column->getTitle());
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_setup_column_correctly(string $relation_name, string $foreign_field): void
+ {
+ $column = AvgColumn::make('Average Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+
+ $this->assertNotEmpty($column);
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_not_skip_set_data_source(string $relation_name, string $foreign_field): void
+ {
+ $this->expectException(DataTableConfigurationException::class);
+
+ $column = AvgColumn::make('Average Age')
+ ->sortable();
+ $contents = $column->getContents(Pet::find(1));
+ $this->assertNull($contents);
+
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_get_data_source(string $relation_name, string $foreign_field): void
+ {
+ $column = AvgColumn::make('Average Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+ $this->assertTrue($column->hasDataSource());
+ $this->assertSame($relation_name, $column->getDataSource());
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_get_foreign_column(string $relation_name, string $foreign_field): void
+ {
+ $column = AvgColumn::make('Average Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+ $this->assertTrue($column->hasForeignColumn());
+ $this->assertSame($foreign_field, $column->getForeignColumn());
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_set_foreign_column(string $relation_name, string $foreign_field): void
+ {
+ $column = AvgColumn::make('Average Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+ $this->assertTrue($column->hasForeignColumn());
+ $this->assertSame($foreign_field, $column->getForeignColumn());
+ $column->setForeignColumn('test');
+ $this->assertTrue($column->hasForeignColumn());
+ $this->assertSame('test', $column->getForeignColumn());
+
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_get_data_source_fields(string $relation_name, string $foreign_field): void
+ {
+ $column = AvgColumn::make('Average Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+ $this->assertTrue($column->hasDataSource());
+ $this->assertSame($relation_name, $column->getDataSource());
+ $this->assertTrue($column->hasForeignColumn());
+ $this->assertSame($foreign_field, $column->getForeignColumn());
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_get_aggregate_method(string $relation_name, string $foreign_field): void
+ {
+ $column = AvgColumn::make('Average Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+ $this->assertSame('avg', $column->getAggregateMethod());
+ $column->setAggregateMethod('test_avg');
+ $this->assertSame('test_avg', $column->getAggregateMethod());
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_renders_correctly(string $relation_name, string $foreign_field): void
+ {
+ $rows = $this->speciesTable->getRows();
+ $column = AvgColumn::make('Average Age')
+ ->setDataSource('pets', 'age');
+ $contents = $column->getContents($rows->first());
+ $this->assertSame('15', $contents);
+ $contents = $column->getContents($rows[2]);
+ $this->assertSame('6', $contents);
+ }
+}
diff --git a/tests/Views/Columns/CountColumnTest.php b/tests/Views/Columns/CountColumnTest.php
new file mode 100644
index 000000000..6c3d1e772
--- /dev/null
+++ b/tests/Views/Columns/CountColumnTest.php
@@ -0,0 +1,50 @@
+assertSame('Total Users', $column->getTitle());
+ }
+
+ public function test_can_setup_column_correctly(): void
+ {
+ $column = CountColumn::make('Total Users')
+ ->setDataSource('users')
+ ->sortable();
+
+ $this->assertNotEmpty($column);
+ }
+
+ public function test_can_not_skip_set_data_source(): void
+ {
+ $this->expectException(DataTableConfigurationException::class);
+
+ $column = CountColumn::make('Average Age')
+ ->sortable();
+ $contents = $column->getContents(Pet::find(1));
+ $this->assertNull($contents);
+
+ }
+
+ public function test_renders_correctly(): void
+ {
+ $rows = $this->speciesTable->getRows();
+ $row1 = $rows->first();
+ $column = CountColumn::make('Pets')
+ ->setDataSource('pets');
+ $contents = $column->getContents($rows->first());
+ $this->assertSame('2', $contents);
+ $contents = $column->getContents($rows->last());
+ $this->assertSame('0', $contents);
+ }
+}
diff --git a/tests/Views/Columns/SumColumnTest.php b/tests/Views/Columns/SumColumnTest.php
new file mode 100644
index 000000000..9d5cbff51
--- /dev/null
+++ b/tests/Views/Columns/SumColumnTest.php
@@ -0,0 +1,111 @@
+assertSame('Sum User Age', $column->getTitle());
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_setup_column_correctly(string $relation_name, string $foreign_field): void
+ {
+ $column = SumColumn::make('Sum User Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+
+ $this->assertNotEmpty($column);
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_not_skip_set_data_source(string $relation_name, string $foreign_field): void
+ {
+ $this->expectException(DataTableConfigurationException::class);
+
+ $column = SumColumn::make('Sum User Age')
+ ->sortable();
+ $contents = $column->getContents(Pet::find(1));
+ $this->assertNull($contents);
+
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_set_foreign_column(string $relation_name, string $foreign_field): void
+ {
+ $column = SumColumn::make('Sum User Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+ $this->assertTrue($column->hasForeignColumn());
+ $this->assertSame($foreign_field, $column->getForeignColumn());
+ $column->setForeignColumn('test');
+ $this->assertTrue($column->hasForeignColumn());
+ $this->assertSame('test', $column->getForeignColumn());
+
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_get_data_source(string $relation_name, string $foreign_field): void
+ {
+ $column = SumColumn::make('Sum User Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+ $this->assertTrue($column->hasDataSource());
+ $this->assertSame($relation_name, $column->getDataSource());
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_get_foreign_column(string $relation_name, string $foreign_field): void
+ {
+ $column = SumColumn::make('Sum User Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+ $this->assertTrue($column->hasForeignColumn());
+ $this->assertSame($foreign_field, $column->getForeignColumn());
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_get_data_source_fields(string $relation_name, string $foreign_field): void
+ {
+ $column = SumColumn::make('Sum User Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+ $this->assertTrue($column->hasDataSource());
+ $this->assertSame($relation_name, $column->getDataSource());
+ $this->assertTrue($column->hasForeignColumn());
+ $this->assertSame($foreign_field, $column->getForeignColumn());
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_can_get_aggregate_method(string $relation_name, string $foreign_field): void
+ {
+ $column = SumColumn::make('Sum User Age')
+ ->setDataSource($relation_name, $foreign_field)
+ ->sortable();
+ $this->assertSame('sum', $column->getAggregateMethod());
+ $column->setAggregateMethod('test_sum');
+ $this->assertSame('test_sum', $column->getAggregateMethod());
+ }
+
+ #[DataProviderExternal(AggregateColumnProvider::class, 'relationshipProvider')]
+ public function test_renders_correctly(string $relation_name, string $foreign_field): void
+ {
+ $rows = $this->speciesTable->getRows();
+ $column = SumColumn::make('Total Age')
+ ->setDataSource('pets', 'age');
+ $contents = $column->getContents($rows->first());
+ $this->assertSame('30', $contents);
+ $contents = $column->getContents($rows[2]);
+ $this->assertSame('12', $contents);
+ }
+}
From 799ccfdd19927fe67c608eef163328e7b81a220d Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Thu, 11 Jul 2024 00:50:53 +0100
Subject: [PATCH 17/21] Add Option to Retain Selected when Searching/Filtering
(#1762)
* Initial Commit for Retaining Selected
* Update Test for Search/Filter
---------
Co-authored-by: lrljoe
---
docs/bulk-actions/available-methods.md | 72 +++++++++++++++++++
.../BulkActionsConfiguration.php | 42 +++++++++++
src/Traits/Helpers/BulkActionsHelpers.php | 10 +++
src/Traits/WithBulkActions.php | 4 ++
src/Traits/WithFilters.php | 8 ++-
src/Traits/WithSearch.php | 8 ++-
.../Traits/Helpers/BulkActionsHelpersTest.php | 70 ++++++++++++++++++
7 files changed, 208 insertions(+), 6 deletions(-)
diff --git a/docs/bulk-actions/available-methods.md b/docs/bulk-actions/available-methods.md
index ad98e1999..512394c23 100644
--- a/docs/bulk-actions/available-methods.md
+++ b/docs/bulk-actions/available-methods.md
@@ -274,3 +274,75 @@ public function configure(): void
$this->setShouldAlwaysHideBulkActionsDropdownOptionDisabled();
}
```
+
+
+## setClearSelectedOnSearch
+
+By default, any selected items for Bulk Actions are cleared upon searching. You may configure this behaviour here.
+
+```php
+public function configure(): void
+{
+ $this->setClearSelectedOnSearch(true);
+}
+```
+
+
+## setClearSelectedOnSearchEnabled
+
+By default, any selected items for Bulk Actions are cleared upon searching. This enables this behaviour.
+
+```php
+public function configure(): void
+{
+ $this->setClearSelectedOnSearchEnabled();
+}
+```
+
+
+## setClearSelectedOnSearchDisabled
+
+By default, any selected items for Bulk Actions are cleared upon searching. This disables this behaviour, ensuring that selected items are retained after searching.
+
+```php
+public function configure(): void
+{
+ $this->setClearSelectedOnSearchDisabled();
+}
+```
+
+
+## setClearSelectedOnFilter
+
+By default, any selected items for Bulk Actions are cleared upon filtering. You may configure this behaviour here.
+
+```php
+public function configure(): void
+{
+ $this->setClearSelectedOnFilter(true);
+}
+```
+
+
+## setClearSelectedOnFilterEnabled
+
+By default, any selected items for Bulk Actions are cleared upon filtering. This enables this behaviour.
+
+```php
+public function configure(): void
+{
+ $this->setClearSelectedOnFilterEnabled();
+}
+```
+
+
+## setClearSelectedOnFilterDisabled
+
+By default, any selected items for Bulk Actions are cleared upon filtering. This disables this behaviour, ensuring that selected items are retained after filtering.
+
+```php
+public function configure(): void
+{
+ $this->setClearSelectedOnFilterDisabled();
+}
+```
diff --git a/src/Traits/Configuration/BulkActionsConfiguration.php b/src/Traits/Configuration/BulkActionsConfiguration.php
index d0d5e17f3..6af318f0e 100644
--- a/src/Traits/Configuration/BulkActionsConfiguration.php
+++ b/src/Traits/Configuration/BulkActionsConfiguration.php
@@ -171,4 +171,46 @@ public function setShouldAlwaysHideBulkActionsDropdownOptionDisabled(): self
return $this;
}
+
+ public function setClearSelectedOnSearch(bool $status): self
+ {
+ $this->clearSelectedOnSearch = $status;
+
+ return $this;
+ }
+
+ public function setClearSelectedOnSearchEnabled(): self
+ {
+ $this->setClearSelectedOnSearch(true);
+
+ return $this;
+ }
+
+ public function setClearSelectedOnSearchDisabled(): self
+ {
+ $this->setClearSelectedOnSearch(false);
+
+ return $this;
+ }
+
+ public function setClearSelectedOnFilter(bool $status): self
+ {
+ $this->clearSelectedOnFilter = $status;
+
+ return $this;
+ }
+
+ public function setClearSelectedOnFilterEnabled(): self
+ {
+ $this->setClearSelectedOnFilter(true);
+
+ return $this;
+ }
+
+ public function setClearSelectedOnFilterDisabled(): self
+ {
+ $this->setClearSelectedOnFilter(false);
+
+ return $this;
+ }
}
diff --git a/src/Traits/Helpers/BulkActionsHelpers.php b/src/Traits/Helpers/BulkActionsHelpers.php
index 70ea427a5..77a263635 100644
--- a/src/Traits/Helpers/BulkActionsHelpers.php
+++ b/src/Traits/Helpers/BulkActionsHelpers.php
@@ -220,4 +220,14 @@ public function shouldAlwaysHideBulkActionsDropdownOption(): bool
{
return $this->alwaysHideBulkActionsDropdownOption ?? false;
}
+
+ public function getClearSelectedOnSearch(): bool
+ {
+ return $this->clearSelectedOnSearch ?? true;
+ }
+
+ public function getClearSelectedOnFilter(): bool
+ {
+ return $this->clearSelectedOnFilter ?? true;
+ }
}
diff --git a/src/Traits/WithBulkActions.php b/src/Traits/WithBulkActions.php
index 08f69197b..37a5cd111 100644
--- a/src/Traits/WithBulkActions.php
+++ b/src/Traits/WithBulkActions.php
@@ -36,6 +36,10 @@ trait WithBulkActions
protected bool $alwaysHideBulkActionsDropdownOption = false;
+ public bool $clearSelectedOnSearch = true;
+
+ public bool $clearSelectedOnFilter = true;
+
public function bulkActions(): array
{
return property_exists($this, 'bulkActions') ? $this->bulkActions : [];
diff --git a/src/Traits/WithFilters.php b/src/Traits/WithFilters.php
index 878c660ce..981d0e855 100644
--- a/src/Traits/WithFilters.php
+++ b/src/Traits/WithFilters.php
@@ -74,9 +74,11 @@ public function updatedFilterComponents(string|array|null $value, string $filter
{
$this->resetComputedPage();
- // Clear bulk actions on filter
- $this->clearSelected();
- $this->setSelectAllDisabled();
+ // Clear bulk actions on filter - if enabled
+ if ($this->getClearSelectedOnFilter()) {
+ $this->clearSelected();
+ $this->setSelectAllDisabled();
+ }
// Clear filters on empty value
$filter = $this->getFilterByKey($filterName);
diff --git a/src/Traits/WithSearch.php b/src/Traits/WithSearch.php
index 0ef402573..5d90a991f 100644
--- a/src/Traits/WithSearch.php
+++ b/src/Traits/WithSearch.php
@@ -70,9 +70,11 @@ public function updatedSearch(string|array|null $value): void
{
$this->resetComputedPage();
- // Clear bulk actions on search
- $this->clearSelected();
- $this->setSelectAllDisabled();
+ // Clear bulk actions on search - if enabled
+ if ($this->getClearSelectedOnSearch()) {
+ $this->clearSelected();
+ $this->setSelectAllDisabled();
+ }
if (is_null($value) || $value === '') {
$this->clearSearch();
diff --git a/tests/Traits/Helpers/BulkActionsHelpersTest.php b/tests/Traits/Helpers/BulkActionsHelpersTest.php
index bf4cc9e6e..5506fcb4b 100644
--- a/tests/Traits/Helpers/BulkActionsHelpersTest.php
+++ b/tests/Traits/Helpers/BulkActionsHelpersTest.php
@@ -207,4 +207,74 @@ public function test_bulk_actions_th_checkbox_attributes_returns_default_true_if
{
$this->assertSame(['default' => true], $this->basicTable->getBulkActionsThCheckboxAttributes());
}
+
+ public function test_select_clears_by_default(): void
+ {
+ $this->basicTable->setSelected([1, 2, 3, 4, 5]);
+ $this->assertSame([1, 2, 3, 4, 5], $this->basicTable->getSelected());
+
+ $this->basicTable->setSearch('Anthony');
+ $this->basicTable->updatedSearch('Anthony');
+
+ $this->assertSame([], $this->basicTable->getSelected());
+ }
+
+ public function test_select_does_not_clear_when_disabled(): void
+ {
+ $this->basicTable->setClearSelectedOnSearchDisabled();
+
+ $this->basicTable->setSelected([1, 2, 3, 4, 5]);
+ $this->assertSame([1, 2, 3, 4, 5], $this->basicTable->getSelected());
+
+ $this->basicTable->setSearch('Anthony');
+ $this->basicTable->updatedSearch('Anthony');
+
+ $this->assertSame([1, 2, 3, 4, 5], $this->basicTable->getSelected());
+ }
+
+ public function test_select_does_clear_when_enabled(): void
+ {
+ $this->basicTable->setClearSelectedOnSearchEnabled();
+
+ $this->basicTable->setSelected([1, 2, 3, 4, 5]);
+ $this->assertSame([1, 2, 3, 4, 5], $this->basicTable->getSelected());
+
+ $this->basicTable->setSearch('Anthony');
+ $this->basicTable->updatedSearch('Anthony');
+
+ $this->assertSame([], $this->basicTable->getSelected());
+
+ }
+
+ public function test_select_clears_by_default_when_filtering(): void
+ {
+ $this->basicTable->setSelected([1, 2, 3, 4, 5]);
+
+ $this->assertSame([1, 2, 3, 4, 5], $this->basicTable->getSelected());
+
+ $this->basicTable->setFilter('breed_id_filter', '2');
+ $this->basicTable->updatedFilterComponents('2', 'breed_id_filter');
+
+ $this->assertSame([], $this->basicTable->getSelected());
+ }
+
+ public function test_select_does_clear_when_filtering_when_enabled(): void
+ {
+ $this->basicTable->setSelected([1, 2, 3, 4, 5]);
+ $this->assertSame([1, 2, 3, 4, 5], $this->basicTable->getSelected());
+ $this->basicTable->setClearSelectedOnFilterEnabled();
+ $this->basicTable->setFilter('breed_id_filter', '2');
+ $this->basicTable->updatedFilterComponents('2', 'breed_id_filter');
+ $this->assertSame([], $this->basicTable->getSelected());
+ }
+
+ public function test_select_does_not_clear_when_filtering_when_disabled(): void
+ {
+ $this->basicTable->setSelected([1, 2, 3, 4, 5]);
+ $this->assertSame([1, 2, 3, 4, 5], $this->basicTable->getSelected());
+ $this->basicTable->setClearSelectedOnFilterDisabled();
+ $this->basicTable->setFilter('breed_id_filter', '2');
+ $this->basicTable->updatedFilterComponents('2', 'breed_id_filter');
+ $this->assertSame([1, 2, 3, 4, 5], $this->basicTable->getSelected());
+ }
}
From 220d6da90abd90aef1f8e8aa4512052ba5ebc377 Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Thu, 11 Jul 2024 01:41:24 +0100
Subject: [PATCH 18/21] Add WireLink Column (#1763)
* Add WireLinkColumn
* Add Tests for WireLinkColumn
---------
Co-authored-by: lrljoe
---
docs/column-types/wire_link_column.md | 37 +++++++++++
.../includes/columns/wire-link.blade.php | 9 +++
src/Views/Columns/WireLinkColumn.php | 45 +++++++++++++
.../WireLinkColumnConfiguration.php | 5 ++
src/Views/Traits/Core/HasActionCallback.php | 28 ++++++++
src/Views/Traits/Core/HasConfirmation.php | 28 ++++++++
.../Traits/Helpers/WireLinkColumnHelpers.php | 5 ++
tests/Views/Columns/WireLinkColumnTest.php | 66 +++++++++++++++++++
8 files changed, 223 insertions(+)
create mode 100644 docs/column-types/wire_link_column.md
create mode 100644 resources/views/includes/columns/wire-link.blade.php
create mode 100644 src/Views/Columns/WireLinkColumn.php
create mode 100644 src/Views/Traits/Configuration/WireLinkColumnConfiguration.php
create mode 100644 src/Views/Traits/Core/HasActionCallback.php
create mode 100644 src/Views/Traits/Core/HasConfirmation.php
create mode 100644 src/Views/Traits/Helpers/WireLinkColumnHelpers.php
create mode 100644 tests/Views/Columns/WireLinkColumnTest.php
diff --git a/docs/column-types/wire_link_column.md b/docs/column-types/wire_link_column.md
new file mode 100644
index 000000000..3577ad95b
--- /dev/null
+++ b/docs/column-types/wire_link_column.md
@@ -0,0 +1,37 @@
+---
+title: Wire Link Column (beta)
+weight: 13
+---
+
+WireLink columns provide a way to display Wired Links in your table without having to use `format()` or partial views, with or without a Confirmation Message
+
+WireLinkColumn requires title, and an "action", which must be a valid LiveWire method in the current class, or a global method
+
+Without a Confirmation Message
+```php
+ WireLinkColumn::make("Delete Item")
+ ->title(fn($row) => 'Delete Item')
+ ->action(fn($row) => 'delete("'.$row->id.'")'),
+```
+
+You may also pass a string to "confirmMessage", which will utilise LiveWire 3's "wire:confirm" approach to display a confirmation modal.
+
+```php
+ WireLinkColumn::make("Delete Item")
+ ->title(fn($row) => 'Delete Item')
+ ->confirmMessage('Are you sure you want to delete this item?')
+ ->action(fn($row) => 'delete("'.$row->id.'")')
+ ->attributes(fn($row) => [
+ 'class' => 'btn btn-danger',
+ ]),
+```
+
+And you may also pass an array of attributes, which will be applied to the "button" element used within the Column
+```php
+ WireLinkColumn::make("Delete Item")
+ ->title(fn($row) => 'Delete Item')
+ ->action(fn($row) => 'delete("'.$row->id.'")')
+ ->attributes(fn($row) => [
+ 'class' => 'btn btn-danger',
+ ]),
+```
diff --git a/resources/views/includes/columns/wire-link.blade.php b/resources/views/includes/columns/wire-link.blade.php
new file mode 100644
index 000000000..191ba5f1d
--- /dev/null
+++ b/resources/views/includes/columns/wire-link.blade.php
@@ -0,0 +1,9 @@
+arrayToAttributes($attributes) : '' !!}
+ @if($column->hasConfirmMessage())
+ wire:confirm="{{ $column->getConfirmMessage() }}"
+ @endif
+ @if($column->hasActionCallback())
+ wire:click="{{ $path }}"
+ @endif
+>{{ $title }}
diff --git a/src/Views/Columns/WireLinkColumn.php b/src/Views/Columns/WireLinkColumn.php
new file mode 100644
index 000000000..343f28ef9
--- /dev/null
+++ b/src/Views/Columns/WireLinkColumn.php
@@ -0,0 +1,45 @@
+label(fn () => null);
+ }
+
+ public function getContents(Model $row): null|string|\Illuminate\Support\HtmlString|DataTableConfigurationException|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
+ {
+ if (! $this->hasTitleCallback()) {
+ throw new DataTableConfigurationException('You must specify a title callback for a WireLink column.');
+ }
+
+ if (! $this->hasActionCallback()) {
+ throw new DataTableConfigurationException('You must specify an action callback for a WireLink column.');
+ }
+
+ return view($this->getView())
+ ->withColumn($this)
+ ->withTitle(app()->call($this->getTitleCallback(), ['row' => $row]))
+ ->withPath(app()->call($this->getActionCallback(), ['row' => $row]))
+ ->withAttributes($this->hasAttributesCallback() ? app()->call($this->getAttributesCallback(), ['row' => $row]) : []);
+ }
+}
diff --git a/src/Views/Traits/Configuration/WireLinkColumnConfiguration.php b/src/Views/Traits/Configuration/WireLinkColumnConfiguration.php
new file mode 100644
index 000000000..238b36fbf
--- /dev/null
+++ b/src/Views/Traits/Configuration/WireLinkColumnConfiguration.php
@@ -0,0 +1,5 @@
+actionCallback = $callback;
+
+ return $this;
+ }
+
+ public function getActionCallback(): ?callable
+ {
+ return $this->actionCallback;
+ }
+
+ public function hasActionCallback(): bool
+ {
+ return $this->actionCallback !== null;
+ }
+}
diff --git a/src/Views/Traits/Core/HasConfirmation.php b/src/Views/Traits/Core/HasConfirmation.php
new file mode 100644
index 000000000..9a8597947
--- /dev/null
+++ b/src/Views/Traits/Core/HasConfirmation.php
@@ -0,0 +1,28 @@
+confirmMessage = $confirmMessage;
+
+ return $this;
+ }
+
+ public function hasConfirmMessage(): bool
+ {
+ return isset($this->confirmMessage);
+ }
+
+ public function getConfirmMessage(): string
+ {
+ return $this->confirmMessage;
+ }
+}
diff --git a/src/Views/Traits/Helpers/WireLinkColumnHelpers.php b/src/Views/Traits/Helpers/WireLinkColumnHelpers.php
new file mode 100644
index 000000000..f24c7e460
--- /dev/null
+++ b/src/Views/Traits/Helpers/WireLinkColumnHelpers.php
@@ -0,0 +1,5 @@
+assertSame('Name', $column->getTitle());
+ }
+
+ public function test_can_not_infer_field_name_from_title_if_no_from(): void
+ {
+ $column = WireLinkColumn::make('My Title');
+
+ $this->assertNull($column->getField());
+ }
+
+ public function test_can_not_render_field_if_no_title_callback(): void
+ {
+ $this->expectException(DataTableConfigurationException::class);
+
+ WireLinkColumn::make('Name')->getContents(Pet::find(1));
+ }
+
+ public function test_can_not_render_field_if_no_action_callback(): void
+ {
+ $this->expectException(DataTableConfigurationException::class);
+
+ WireLinkColumn::make('Name')->title(fn ($row) => 'Edit')->getContents(Pet::find(1));
+ }
+
+ public function test_can_render_field_if_title_and_action_callback(): void
+ {
+ $column = WireLinkColumn::make('Name')->title(fn ($row) => 'Edit')->action(fn ($row) => 'delete("'.$row->id.'")')->getContents(Pet::find(1));
+
+ $this->assertNotEmpty($column);
+ }
+
+ public function test_can_render_field_if_confirm_set(): void
+ {
+ $column = WireLinkColumn::make('Name')->title(fn ($row) => 'Edit')->action(fn ($row) => 'delete("'.$row->id.'")')->confirmMessage('Test')->getContents(Pet::find(1));
+
+ $this->assertNotEmpty($column);
+ }
+
+ public function test_can_add_confirm_message(): void
+ {
+ $column = WireLinkColumn::make('Name', 'name');
+
+ $this->assertFalse($column->hasConfirmMessage());
+
+ $column->confirmMessage('Test');
+
+ $this->assertTrue($column->hasConfirmMessage());
+
+ $this->assertSame('Test', $column->getConfirmMessage());
+ }
+}
From 2593615745cf91e9f21b71dc3fd8c0a4f3730259 Mon Sep 17 00:00:00 2001
From: lrljoe
Date: Thu, 11 Jul 2024 00:44:48 +0000
Subject: [PATCH 19/21] Fix styling
---
src/Traits/WithBulkActions.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Traits/WithBulkActions.php b/src/Traits/WithBulkActions.php
index 5411f230a..37a5cd111 100644
--- a/src/Traits/WithBulkActions.php
+++ b/src/Traits/WithBulkActions.php
@@ -40,7 +40,7 @@ trait WithBulkActions
public bool $clearSelectedOnFilter = true;
- public function bulkActions(): array
+ public function bulkActions(): array
{
return property_exists($this, 'bulkActions') ? $this->bulkActions : [];
}
From 16314aca53306cd815f4c89fd8440465dd2e25ca Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Thu, 11 Jul 2024 01:50:46 +0100
Subject: [PATCH 20/21] Update ChangeLog
---
CHANGELOG.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 940323134..f2f5b502f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,9 +2,11 @@
All notable changes to `laravel-livewire-tables` will be documented in this file
-## [v3.3.0] - 2024-07-12
+## [v3.3.0] - 2024-07-11
### New Features
- Add new columns (ArrayColumn, AvgColumn, CountColumn, SumColumn) by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1761
+- Add new column WireLinkColumn by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1763
+- Add Option to Retain Selected when Searching/Filtering by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1762
## [v3.2.8] - 2024-07-03
### Bug Fixes
From 11fbd707eb0806e8862c6d4ea2a944d709edf03a Mon Sep 17 00:00:00 2001
From: Joe <104938042+lrljoe@users.noreply.github.com>
Date: Thu, 11 Jul 2024 03:21:40 +0100
Subject: [PATCH 21/21] Adjust column documentation (#1767)
* Update OtherColumnTypes docs
* Add Links for Additional Docs
---
docs/column-types/array_column.md | 20 ++++++-
docs/column-types/avg_column.md | 20 ++++++-
docs/column-types/boolean_columns.md | 18 ++++++-
docs/column-types/button_group_column.md | 9 +++-
docs/column-types/color_columns.md | 18 ++++++-
docs/column-types/component_column.md | 17 +++++-
docs/column-types/count_column.md | 20 ++++++-
docs/column-types/date_columns.md | 17 +++++-
docs/column-types/image_columns.md | 18 ++++++-
docs/column-types/link_columns.md | 18 ++++++-
.../column-types/livewire_component_column.md | 29 +++++++++-
docs/column-types/standard_column.md | 31 +++++++++++
docs/column-types/sum_column.md | 20 ++++++-
docs/column-types/wire_link_column.md | 18 ++++++-
docs/columns/available-methods.md | 2 +-
docs/columns/footer.md | 2 +-
docs/columns/other-column-types.md | 53 +++++++++++++++----
docs/columns/secondary-header.md | 2 +-
18 files changed, 301 insertions(+), 31 deletions(-)
create mode 100644 docs/column-types/standard_column.md
diff --git a/docs/column-types/array_column.md b/docs/column-types/array_column.md
index 1571da2b9..7802e78aa 100644
--- a/docs/column-types/array_column.md
+++ b/docs/column-types/array_column.md
@@ -1,6 +1,6 @@
---
title: Array Columns (beta)
-weight: 1
+weight: 2
---
Array columns provide an easy way to work with and display an array of data from a field.
@@ -19,4 +19,20 @@ You may define the default/empty value using the "emptyValue" method
```
ArrayColumn::make('notes', 'name')
->emptyValue('Unknown'),
-```
\ No newline at end of file
+```
+
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/avg_column.md b/docs/column-types/avg_column.md
index faa653ca2..d5e4b32fb 100644
--- a/docs/column-types/avg_column.md
+++ b/docs/column-types/avg_column.md
@@ -1,6 +1,6 @@
---
title: Avg Columns (beta)
-weight: 2
+weight: 3
---
Avg columns provide an easy way to display the "Average" of a field on a relation.
@@ -11,4 +11,20 @@ Avg columns provide an easy way to display the "Average" of a field on a relatio
->sortable(),
```
-The "sortable()" callback can accept a callback, or you can use the default behaviour, which calculates the correct field to sort on.
\ No newline at end of file
+The "sortable()" callback can accept a callback, or you can use the default behaviour, which calculates the correct field to sort on.
+
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/boolean_columns.md b/docs/column-types/boolean_columns.md
index 32a759918..8732db839 100644
--- a/docs/column-types/boolean_columns.md
+++ b/docs/column-types/boolean_columns.md
@@ -1,6 +1,6 @@
---
title: Boolean Columns
-weight: 3
+weight: 4
---
Boolean columns are good if you have a column type that is a true/false, or 0/1 value.
@@ -79,3 +79,19 @@ If you would like the BooleanColumn to display a plain Yes/No, you can set:
BooleanColumn::make('Active')
->yesNo()
```
+
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/button_group_column.md b/docs/column-types/button_group_column.md
index 5a3390049..da8ff7399 100644
--- a/docs/column-types/button_group_column.md
+++ b/docs/column-types/button_group_column.md
@@ -1,6 +1,6 @@
---
title: Button Group Columns
-weight: 4
+weight: 5
---
Button group columns let you provide an array of LinkColumns to display in a single cell.
@@ -32,3 +32,10 @@ ButtonGroupColumn::make('Actions')
}),
]),
```
+
+
+Please also see the following for other available methods:
+- [https://rappasoft.com/docs/laravel-livewire-tables/v3/columns/available-methods](Available Methods)
+- [https://rappasoft.com/docs/laravel-livewire-tables/v3/columns/column-selection](Column Selection)
+- [https://rappasoft.com/docs/laravel-livewire-tables/v3/columns/secondary-header](Secondary Header)
+- [https://rappasoft.com/docs/laravel-livewire-tables/v3/columns/footer](Footer)
diff --git a/docs/column-types/color_columns.md b/docs/column-types/color_columns.md
index e4920144d..eeae20b2f 100644
--- a/docs/column-types/color_columns.md
+++ b/docs/column-types/color_columns.md
@@ -1,6 +1,6 @@
---
title: Color Columns
-weight: 5
+weight: 6
---
Color columns provide an easy way to a Color in a Column
@@ -39,3 +39,19 @@ You may also specify attributes to use on the div displaying the color, to adjus
];
}),
```
+
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/component_column.md b/docs/column-types/component_column.md
index 0db9c9483..79611121f 100644
--- a/docs/column-types/component_column.md
+++ b/docs/column-types/component_column.md
@@ -1,6 +1,6 @@
---
title: Component Columns
-weight: 6
+weight: 7
---
Component columns let you specify a component name and attributes and provides the column value to the slot.
@@ -26,3 +26,18 @@ ComponentColumn::make('E-mail', 'email')
]),
```
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/count_column.md b/docs/column-types/count_column.md
index d33cf5df9..4b1fe6c3a 100644
--- a/docs/column-types/count_column.md
+++ b/docs/column-types/count_column.md
@@ -1,6 +1,6 @@
---
title: Count Columns (beta)
-weight: 7
+weight: 8
---
Count columns provide an easy way to display the "Count" of a relation.
@@ -11,4 +11,20 @@ Count columns provide an easy way to display the "Count" of a relation.
->sortable(),
```
-The "sortable()" callback can accept a callback, or you can use the default behaviour, which calculates the correct field to sort on.
\ No newline at end of file
+The "sortable()" callback can accept a callback, or you can use the default behaviour, which calculates the correct field to sort on.
+
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/date_columns.md b/docs/column-types/date_columns.md
index abc8bbb42..3e2e6ca0a 100644
--- a/docs/column-types/date_columns.md
+++ b/docs/column-types/date_columns.md
@@ -1,6 +1,6 @@
---
title: Date Columns
-weight: 8
+weight: 9
---
Date columns provide an easy way to display dates in a given format, without having to use repetitive format() methods or partial views.
@@ -26,3 +26,18 @@ DateColumn::make('Last Charged', 'last_charged_at')
->emptyValue('Not Found'),
```
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/image_columns.md b/docs/column-types/image_columns.md
index f816280af..5e6868792 100644
--- a/docs/column-types/image_columns.md
+++ b/docs/column-types/image_columns.md
@@ -1,6 +1,6 @@
---
title: Image Columns
-weight: 9
+weight: 10
---
Image columns provide a way to display images in your table without having to use `format()` or partial views:
@@ -24,3 +24,19 @@ ImageColumn::make('Avatar')
'alt' => $row->name . ' Avatar',
]),
```
+
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/link_columns.md b/docs/column-types/link_columns.md
index cba4bc887..e3f3120a4 100644
--- a/docs/column-types/link_columns.md
+++ b/docs/column-types/link_columns.md
@@ -1,6 +1,6 @@
---
title: Link Columns
-weight: 10
+weight: 11
---
Link columns provide a way to display HTML links in your table without having to use `format()` or partial views:
@@ -22,3 +22,19 @@ LinkColumn::make('Action')
'alt' => $row->name . ' Avatar',
]),
```
+
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/livewire_component_column.md b/docs/column-types/livewire_component_column.md
index b75172881..b12ada72e 100644
--- a/docs/column-types/livewire_component_column.md
+++ b/docs/column-types/livewire_component_column.md
@@ -1,5 +1,32 @@
---
title: Livewire Component (beta)
-weight: 11
+weight: 12
---
+Livewire Component Columns allow for the use of a Livewire Component as a Column.
+
+This is **not recommended** as due to the nature of Livewire, it becomes inefficient at scale.
+
+## component
+```
+LivewireComponentColumn::make('Action')
+ ->title(fn($row) => 'Edit')
+ ->component('PathToLivewireComponent'),
+
+```
+
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/standard_column.md b/docs/column-types/standard_column.md
new file mode 100644
index 000000000..6f7844982
--- /dev/null
+++ b/docs/column-types/standard_column.md
@@ -0,0 +1,31 @@
+---
+title: Standard Column
+weight: 1
+---
+
+A standard Column has a multitude of different options, making it simple for you to display your data, as documented below:
+
+
diff --git a/docs/column-types/sum_column.md b/docs/column-types/sum_column.md
index 7f99f7cab..c643253a7 100644
--- a/docs/column-types/sum_column.md
+++ b/docs/column-types/sum_column.md
@@ -1,6 +1,6 @@
---
title: Sum Columns (beta)
-weight: 12
+weight: 13
---
Sum columns provide an easy way to display the "Sum" of a field on a relation.
@@ -11,4 +11,20 @@ Sum columns provide an easy way to display the "Sum" of a field on a relation.
->sortable(),
```
-The "sortable()" callback can accept a callback, or you can use the default behaviour, which calculates the correct field to sort on.
\ No newline at end of file
+The "sortable()" callback can accept a callback, or you can use the default behaviour, which calculates the correct field to sort on.
+
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/column-types/wire_link_column.md b/docs/column-types/wire_link_column.md
index 3577ad95b..eaee09537 100644
--- a/docs/column-types/wire_link_column.md
+++ b/docs/column-types/wire_link_column.md
@@ -1,6 +1,6 @@
---
title: Wire Link Column (beta)
-weight: 13
+weight: 14
---
WireLink columns provide a way to display Wired Links in your table without having to use `format()` or partial views, with or without a Confirmation Message
@@ -35,3 +35,19 @@ And you may also pass an array of attributes, which will be applied to the "butt
'class' => 'btn btn-danger',
]),
```
+
+Please also see the following for other available methods:
+
\ No newline at end of file
diff --git a/docs/columns/available-methods.md b/docs/columns/available-methods.md
index ab41c7095..26f34b926 100644
--- a/docs/columns/available-methods.md
+++ b/docs/columns/available-methods.md
@@ -25,7 +25,7 @@ Column::make(__('Address'))
### [Multi-column sorting](../sorting/available-methods#setsinglesortingstatus)
-In v2, multi-column sorting is **disabled by default**. To enable it you can set the `setSingleSortingDisabled()` method on the component.
+Multi-column sorting is **disabled by default**. To enable it you can set the `setSingleSortingDisabled()` method on the component.
```php
public function configure(): void
diff --git a/docs/columns/footer.md b/docs/columns/footer.md
index caf9a45d4..c4b3877e7 100644
--- a/docs/columns/footer.md
+++ b/docs/columns/footer.md
@@ -21,7 +21,7 @@ See also [footer component configuration](../footer/available-methods).
## Using a filter as a footer
-As of version 2.7, you can use a filter as a footer.
+You can use a filter as a footer.
```php
// Example filter
diff --git a/docs/columns/other-column-types.md b/docs/columns/other-column-types.md
index 2e515eedf..c3a8bd154 100644
--- a/docs/columns/other-column-types.md
+++ b/docs/columns/other-column-types.md
@@ -3,14 +3,45 @@ title: Other Column Types
weight: 4
---
-
-
-
-
-## Aggregate Columns
-
-### AvgColumn
-
-### CountColumn
-
-### SumColumn
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/columns/secondary-header.md b/docs/columns/secondary-header.md
index 31790b3e8..258db8d30 100644
--- a/docs/columns/secondary-header.md
+++ b/docs/columns/secondary-header.md
@@ -21,7 +21,7 @@ See also [secondary header component configuration](../secondary-header/availabl
## Using a filter as a secondary header
-As of version 2.7, you can use a filter as a header.
+You can use a filter as a header.
```php
// Example filter