diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4958d0393..5adab2fbc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,18 @@
All notable changes to `laravel-livewire-tables` will be documented in this file
+## [v3.4.16] - 2024-08-27
+### New Features
+- Add icon column by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1902
+- Enable/Disable Tools/Toolbar by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1896
+
+### Bug Fixes
+- Fix has actions by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1901
+- Use Computed Properties By Default by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1898
+
+### Tweaks
+- PHPStan - Config File Update and Baseline by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1903
+
## [v3.4.15] - 2024-08-25
### New Features
- BooleanColumn - Toggleable Callback by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1892
diff --git a/database/sqlite.database b/database/database.sqlite
similarity index 87%
rename from database/sqlite.database
rename to database/database.sqlite
index 51e3c6632..1a9e27435 100644
Binary files a/database/sqlite.database and b/database/database.sqlite differ
diff --git a/docs/column-types/icon_column.md b/docs/column-types/icon_column.md
new file mode 100644
index 000000000..28c74458f
--- /dev/null
+++ b/docs/column-types/icon_column.md
@@ -0,0 +1,87 @@
+---
+title: Icon Columns (beta)
+weight: 10
+---
+
+Icon columns provide a way to display icons in your table without having to use `format()` or partial views.
+
+### setIcon
+setIcon requires a valid path to an SVG (Directly or via a Library), it receives the $row, and $value (if available) to help you customise which icon to use
+```php
+IconColumn::make('Icon', 'status')
+ ->setIcon(function ($row, $value) {
+ if($value == 1) {
+ return "heroicon-o-check-circle";
+ }
+ else
+ {
+ return "heroicon-o-x-circle";
+ }
+ }),
+```
+
+### attributes
+Attributes receives the $row, and $value (if available) to help you customise which attributes to apply, you may pass both classes, and other SVG specific attributes.
+```php
+IconColumn::make('Icon', 'status')
+ ->setIcon(function ($row, $value) { if($value == 1) { return "heroicon-o-check-circle"; } else { return "heroicon-o-x-circle"; } })
+ ->attributes(function ($row, $value) {
+ if($value == 1) {
+ return [
+ 'class' => 'w-6 h-6',
+ 'stroke' => '#008000'
+ ];
+ }
+ else
+ {
+ return [
+ 'class' => 'w-3 h-3',
+ 'stroke' => '#FF0000'
+ ];
+ }
+ }),
+```
+
+For example:
+### Example
+```php
+IconColumn::make('Icon', 'status')
+ ->setIcon(function ($row, $value) { if($value == 1) { return "heroicon-o-check-circle"; } else { return "heroicon-o-x-circle"; } })
+ ->attributes(function ($row, $value) {
+ if($value == 3) {
+ return [
+ 'class' => 'w-3 h-3',
+ 'stroke' => '#008000'
+ ];
+ }
+ else if($value == 2) {
+ return [
+ 'class' => 'w-3 h-3',
+ 'stroke' => '#0000FF'
+ ];
+ }
+ else
+ {
+ return [
+ 'class' => 'w-3 h-3',
+ 'stroke' => '#FF0000'
+ ];
+ }
+ }),
+```
+
+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 5e6868792..4225593b3 100644
--- a/docs/column-types/image_columns.md
+++ b/docs/column-types/image_columns.md
@@ -1,6 +1,6 @@
---
title: Image Columns
-weight: 10
+weight: 11
---
Image columns provide a way to display images in your table without having to use `format()` or partial views:
diff --git a/docs/column-types/link_columns.md b/docs/column-types/link_columns.md
index e3f3120a4..1e4aa7fa1 100644
--- a/docs/column-types/link_columns.md
+++ b/docs/column-types/link_columns.md
@@ -1,6 +1,6 @@
---
title: Link Columns
-weight: 11
+weight: 12
---
Link columns provide a way to display HTML links in your table without having to use `format()` or partial views:
diff --git a/docs/column-types/livewire_component_column.md b/docs/column-types/livewire_component_column.md
index b12ada72e..9b1851299 100644
--- a/docs/column-types/livewire_component_column.md
+++ b/docs/column-types/livewire_component_column.md
@@ -1,6 +1,6 @@
---
title: Livewire Component (beta)
-weight: 12
+weight: 13
---
Livewire Component Columns allow for the use of a Livewire Component as a Column.
diff --git a/docs/column-types/sum_column.md b/docs/column-types/sum_column.md
index d63aa8f47..b15288ef2 100644
--- a/docs/column-types/sum_column.md
+++ b/docs/column-types/sum_column.md
@@ -1,6 +1,6 @@
---
title: Sum Columns (beta)
-weight: 13
+weight: 14
---
Sum columns provide an easy way to display the "Sum" of a field on a relation.
diff --git a/docs/column-types/view_component_column.md b/docs/column-types/view_component_column.md
index 4b1b9a033..f3dd04276 100644
--- a/docs/column-types/view_component_column.md
+++ b/docs/column-types/view_component_column.md
@@ -1,6 +1,6 @@
---
title: View Component Columns
-weight: 14
+weight: 15
---
View Component columns let you specify a component name and attributes and provide attributes to the View Component. This will render the View Component in it's entirety.
diff --git a/docs/column-types/wire_link_column.md b/docs/column-types/wire_link_column.md
index 9abf15aac..253544cd0 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: 15
+weight: 16
---
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
diff --git a/docs/columns/other-column-types.md b/docs/columns/other-column-types.md
index c3a8bd154..f12adf6e7 100644
--- a/docs/columns/other-column-types.md
+++ b/docs/columns/other-column-types.md
@@ -28,6 +28,9 @@ weight: 4
Date Columns
+
+ [Icon Columns (Beta)](../column-types/icon_columns)
+
Image Columns
diff --git a/docs/misc/tools.md b/docs/misc/tools.md
new file mode 100644
index 000000000..7904caa0c
--- /dev/null
+++ b/docs/misc/tools.md
@@ -0,0 +1,59 @@
+---
+title: Tools
+weight: 9
+---
+
+The Table offers additional configuration to show/hide the Tools/Toolbar sections:
+## Tools
+Contains:
+- Filter Pills
+- Sorting Pills
+- The Toolbar
+
+## Toolbar
+Contains:
+- Actions (if set to Toolbar)
+- Column Select dropdown
+- Configurable Areas for Toolbar
+- Filters Button/Dropdown/Popover
+- Pagination dropdown
+- Reorder Button
+- Search Input
+
+## Component Available Methods
+
+### setToolsEnabled
+The Default Behaviour, Tools Are Enabled. But will only be rendered if there are available/enabled elements. If the Toolbar is enabled, this takes into account any Toolbar elements that are present.
+```php
+ public function configure(): void
+ {
+ $this->setToolsEnabled();
+ }
+```
+
+### setToolsDisabled
+Disables the Tools section, this includes the Toolbar, and Sort/Filter pills
+```php
+ public function configure(): void
+ {
+ $this->setToolsDisabled();
+ }
+```
+
+### setToolBarEnabled
+The Default Behaviour, ToolBar is Enabled. But will only be rendered if there are available/enabled elements
+```php
+ public function configure(): void
+ {
+ $this->setToolBarEnabled();
+ }
+```
+
+### setToolBarDisabled
+Disables the Toolbar, which contains the Reorder, Filters, Search, Column Select, Pagination buttons/options. Does not impact the Filter/Sort pills (if enabled)
+```php
+ public function configure(): void
+ {
+ $this->setToolBarDisabled();
+ }
+```
\ No newline at end of file
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 000000000..205fd1d59
--- /dev/null
+++ b/phpstan-baseline.neon
@@ -0,0 +1,76 @@
+parameters:
+ ignoreErrors:
+ -
+ message: "#^Offset '1' on array\\, mixed\\>\\> in empty\\(\\) does not exist\\.$#"
+ count: 1
+ path: src/DataTableComponent.php
+
+ -
+ message: "#^Offset '99' on array\\, mixed\\>\\> in isset\\(\\) does not exist\\.$#"
+ count: 1
+ path: src/DataTableComponent.php
+
+ -
+ message: "#^Offset '99' on non\\-empty\\-array\\<1\\|string, array\\, mixed\\>\\> in isset\\(\\) does not exist\\.$#"
+ count: 1
+ path: src/DataTableComponent.php
+
+ -
+ message: "#^Property Illuminate\\\\Database\\\\Query\\\\Builder\\:\\:\\$joins \\(array\\) on left side of \\?\\? is not nullable\\.$#"
+ count: 1
+ path: src/DataTableComponent.php
+
+ -
+ message: "#^Property Rappasoft\\\\LaravelLivewireTables\\\\DataTableComponent\\:\\:\\$model has no type specified\\.$#"
+ count: 1
+ path: src/DataTableComponent.php
+
+ -
+ message: "#^Unsafe usage of new static\\(\\)\\.$#"
+ count: 1
+ path: src/Views/Action.php
+
+ -
+ message: "#^Unsafe usage of new static\\(\\)\\.$#"
+ count: 1
+ path: src/Views/Column.php
+
+ -
+ message: "#^Unsafe usage of new static\\(\\)\\.$#"
+ count: 1
+ path: src/Views/Filter.php
+
+ -
+ message: "#^Parameter \\#1 \\$callback of method Illuminate\\\\Support\\\\Collection\\\\:\\:filter\\(\\) expects \\(callable\\(string, int\\)\\: bool\\)\\|null, Closure\\(mixed\\)\\: int\\<0, max\\> given\\.$#"
+ count: 1
+ path: src/Views/Filters/MultiSelectDropdownFilter.php
+
+ -
+ message: "#^Unable to resolve the template type TMapWithKeysKey in call to method Illuminate\\\\Support\\\\Collection\\<\\(int\\|string\\),mixed\\>\\:\\:mapWithKeys\\(\\)$#"
+ count: 1
+ path: src/Views/Filters/MultiSelectDropdownFilter.php
+
+ -
+ message: "#^Unable to resolve the template type TMapWithKeysValue in call to method Illuminate\\\\Support\\\\Collection\\<\\(int\\|string\\),mixed\\>\\:\\:mapWithKeys\\(\\)$#"
+ count: 1
+ path: src/Views/Filters/MultiSelectDropdownFilter.php
+
+ -
+ message: "#^Parameter \\#1 \\$callback of method Illuminate\\\\Support\\\\Collection\\\\:\\:filter\\(\\) expects \\(callable\\(string, int\\)\\: bool\\)\\|null, Closure\\(mixed\\)\\: int\\<0, max\\> given\\.$#"
+ count: 1
+ path: src/Views/Filters/MultiSelectFilter.php
+
+ -
+ message: "#^Parameter \\#1 \\$callback of method Illuminate\\\\Support\\\\Collection\\\\:\\:filter\\(\\) expects \\(callable\\(string, int\\)\\: bool\\)\\|null, Closure\\(mixed\\)\\: int\\<0, max\\> given\\.$#"
+ count: 1
+ path: src/Views/Filters/NumberRangeFilter.php
+
+ -
+ message: "#^Unable to resolve the template type TMapWithKeysKey in call to method Illuminate\\\\Support\\\\Collection\\<\\(int\\|string\\),mixed\\>\\:\\:mapWithKeys\\(\\)$#"
+ count: 1
+ path: src/Views/Filters/SelectFilter.php
+
+ -
+ message: "#^Unable to resolve the template type TMapWithKeysValue in call to method Illuminate\\\\Support\\\\Collection\\<\\(int\\|string\\),mixed\\>\\:\\:mapWithKeys\\(\\)$#"
+ count: 1
+ path: src/Views/Filters/SelectFilter.php
diff --git a/phpstan.neon b/phpstan.neon
index eff01a782..494125a83 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,5 +1,6 @@
includes:
- vendor/larastan/larastan/extension.neon
+ - phpstan-baseline.neon
parameters:
paths:
@@ -14,14 +15,4 @@ parameters:
reportUnmatchedIgnoredErrors: false
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.#'
- - '#on 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.#'
+ - identifier: missingType.iterableValue
\ No newline at end of file
diff --git a/resources/views/components/tools/toolbar.blade.php b/resources/views/components/tools/toolbar.blade.php
index c0e1a217d..8a3c8901b 100644
--- a/resources/views/components/tools/toolbar.blade.php
+++ b/resources/views/components/tools/toolbar.blade.php
@@ -1,10 +1,6 @@
@aware(['component', 'tableName','isTailwind','isBootstrap'])
@props([])
-@if ($this->hasConfigurableAreaFor('before-toolbar'))
- @include($this->getConfigurableAreaFor('before-toolbar'), $this->getParametersForConfigurableArea('before-toolbar'))
-@endif
-
$this->isBootstrap,
'md:flex md:justify-between mb-4 px-4 md:p-0' => $this->isTailwind,
@@ -90,9 +86,3 @@
@endif
-
-@if ($this->hasConfigurableAreaFor('after-toolbar'))
-
- @include($this->getConfigurableAreaFor('after-toolbar'), $this->getParametersForConfigurableArea('after-toolbar'))
-
-@endif
diff --git a/resources/views/datatable.blade.php b/resources/views/datatable.blade.php
index f2877c961..6cf84f2ce 100644
--- a/resources/views/datatable.blade.php
+++ b/resources/views/datatable.blade.php
@@ -17,6 +17,7 @@
@include($this->getConfigurableAreaFor('before-tools'), $this->getParametersForConfigurableArea('before-tools'))
@endif
+ @if($this->shouldShowTools)
@if ($this->showSortPillsSection)
@@ -24,8 +25,15 @@
@if($this->showFilterPillsSection)
@endif
-
+
+ @includeWhen($this->hasConfigurableAreaFor('before-toolbar'), $this->getConfigurableAreaFor('before-toolbar'), $this->getParametersForConfigurableArea('before-toolbar'))
+ @if($this->shouldShowToolBar)
+
+ @endif
+ @includeWhen($this->hasConfigurableAreaFor('after-toolbar'), $this->getConfigurableAreaFor('after-toolbar'), $this->getParametersForConfigurableArea('after-toolbar'))
+
+ @endif
diff --git a/resources/views/includes/columns/icon.blade.php b/resources/views/includes/columns/icon.blade.php
new file mode 100644
index 000000000..0f8298c03
--- /dev/null
+++ b/resources/views/includes/columns/icon.blade.php
@@ -0,0 +1,7 @@
+
+ @svg(
+ $icon,
+ $classes,
+ $attributes,
+ )
+
\ No newline at end of file
diff --git a/src/Traits/ComponentUtilities.php b/src/Traits/ComponentUtilities.php
index 815cd216e..d065b25ed 100644
--- a/src/Traits/ComponentUtilities.php
+++ b/src/Traits/ComponentUtilities.php
@@ -45,7 +45,7 @@ trait ComponentUtilities
protected array $extraWithAvgs = [];
- protected bool $useComputedProperties = false;
+ protected bool $useComputedProperties = true;
/**
* Set any configuration options
diff --git a/src/Traits/Configuration/ToolsConfiguration.php b/src/Traits/Configuration/ToolsConfiguration.php
new file mode 100644
index 000000000..08fe1b95d
--- /dev/null
+++ b/src/Traits/Configuration/ToolsConfiguration.php
@@ -0,0 +1,40 @@
+toolsStatus = $status;
+
+ return $this;
+ }
+
+ public function setToolsEnabled(): self
+ {
+ return $this->setToolsStatus(true);
+ }
+
+ public function setToolsDisabled(): self
+ {
+ return $this->setToolsStatus(false);
+ }
+
+ public function setToolBarStatus(bool $status): self
+ {
+ $this->toolBarStatus = $status;
+
+ return $this;
+ }
+
+ public function setToolBarEnabled(): self
+ {
+ return $this->setToolBarStatus(true);
+ }
+
+ public function setToolBarDisabled(): self
+ {
+ return $this->setToolBarStatus(false);
+ }
+}
diff --git a/src/Traits/HasAllTraits.php b/src/Traits/HasAllTraits.php
index 7f048a4a8..567afccd3 100644
--- a/src/Traits/HasAllTraits.php
+++ b/src/Traits/HasAllTraits.php
@@ -27,5 +27,6 @@ trait HasAllTraits
WithRefresh,
WithReordering,
WithSecondaryHeader,
- WithTableAttributes;
+ WithTableAttributes,
+ WithTools;
}
diff --git a/src/Traits/Helpers/ActionsHelpers.php b/src/Traits/Helpers/ActionsHelpers.php
index 7e8e6e5fe..116ea60c9 100644
--- a/src/Traits/Helpers/ActionsHelpers.php
+++ b/src/Traits/Helpers/ActionsHelpers.php
@@ -29,18 +29,24 @@ public function getActionWrapperAttributes(): array
#[Computed]
public function hasActions(): bool
{
- return (new Collection($this->actions()))
- ->filter(fn ($action) => $action instanceof Action)->count() > 0;
+ if (! isset($this->validActions)) {
+ $this->validActions = $this->getActions();
+ }
+
+ return $this->validActions->count() > 0;
}
#[Computed]
public function getActions(): Collection
{
- return (new Collection($this->actions()))
- ->filter(fn ($action) => $action instanceof Action)
- ->each(function (Action $action, int $key) {
- $action->setTheme($this->getTheme());
- });
-
+ if (! isset($this->validActions)) {
+ $this->validActions = (new Collection($this->actions()))
+ ->filter(fn ($action) => $action instanceof Action)
+ ->each(function (Action $action, int $key) {
+ $action->setTheme($this->getTheme());
+ });
+ }
+
+ return $this->validActions;
}
}
diff --git a/src/Traits/Helpers/SortingHelpers.php b/src/Traits/Helpers/SortingHelpers.php
index c78ec9a2f..a0043d41e 100644
--- a/src/Traits/Helpers/SortingHelpers.php
+++ b/src/Traits/Helpers/SortingHelpers.php
@@ -164,6 +164,6 @@ public function getDefaultSortingLabelDesc(): string
#[Computed]
public function showSortPillsSection(): bool
{
- return $this->sortingPillsAreEnabled() && $this->hasSorts();
+ return $this->sortingIsEnabled() && $this->sortingPillsAreEnabled() && $this->hasSorts();
}
}
diff --git a/src/Traits/Helpers/ToolsHelpers.php b/src/Traits/Helpers/ToolsHelpers.php
new file mode 100644
index 000000000..a73b7fe53
--- /dev/null
+++ b/src/Traits/Helpers/ToolsHelpers.php
@@ -0,0 +1,108 @@
+toolsStatus;
+ }
+
+ public function getToolBarStatus(): bool
+ {
+ return $this->toolBarStatus;
+ }
+
+ #[Computed]
+ public function shouldShowTools(): bool
+ {
+ if ($this->getToolsStatus()) {
+ if ($this->shouldShowToolBar()) {
+ return true;
+ } else {
+ if ($this->showSortPillsSection()) { // Sort Pills Are Enabled
+ return true;
+ } elseif ($this->showFilterPillsSection()) { // Filter Pills Are Enable)
+ return true;
+ } else {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ }
+
+ #[Computed]
+ public function shouldShowToolBar(): bool
+ {
+ if ($this->getToolsStatus() == false) {
+ return false;
+ }
+
+ if ($this->getToolBarStatus()) {
+ if (
+ $this->hasToolbarConfigurableAreas() || // Has Configured Toolbar Configurable Areas
+ $this->hasToolbarActions() || // Actions Exist In Toolbar
+ $this->hasToolbarReorder() || // If Reorder Is Enabled
+ $this->hasToolbarColumnSelect() || // Column Select Enabled
+ $this->displayToolbarSearch() || // If Search Is Enabled
+ $this->displayToolbarFilters() || // If Filters Are Enabled
+ $this->displayToolbarPagination() // Pagination Selection Is Enabled
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ return false;
+ }
+
+ #[Computed]
+ public function displayToolbarPagination(): bool
+ {
+ return $this->paginationIsEnabled() && $this->perPageVisibilityIsEnabled();
+ }
+
+ #[Computed]
+ public function displayToolbarSearch(): bool
+ {
+ return $this->searchIsEnabled() && $this->searchVisibilityIsEnabled();
+ }
+
+ #[Computed]
+ public function displayToolbarFilters(): bool
+ {
+ if ($this->filtersAreEnabled() && $this->filtersVisibilityIsEnabled() && $this->hasVisibleFilters()) {
+ return true;
+ } elseif ($this->filtersAreEnabled() && $this->showBulkActionsDropdownAlpine() && $this->shouldAlwaysHideBulkActionsDropdownOption() != true) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected function hasToolbarColumnSelect(): bool
+ {
+ return $this->columnSelectIsEnabled();
+ }
+
+ protected function hasToolbarReorder(): bool
+ {
+ return $this->reorderIsEnabled();
+ }
+
+ protected function hasToolbarConfigurableAreas(): bool
+ {
+ return $this->hasConfigurableAreaFor('toolbar-left-end') || $this->hasConfigurableAreaFor('toolbar-left-start') || $this->hasConfigurableAreaFor('toolbar-right-start') || $this->hasConfigurableAreaFor('toolbar-right-end');
+ }
+
+ protected function hasToolbarActions(): bool
+ {
+ return $this->hasActions() && $this->showActionsInToolbar();
+ }
+}
diff --git a/src/Traits/WithActions.php b/src/Traits/WithActions.php
index 1d78fa675..b9531e755 100644
--- a/src/Traits/WithActions.php
+++ b/src/Traits/WithActions.php
@@ -2,6 +2,7 @@
namespace Rappasoft\LaravelLivewireTables\Traits;
+use Illuminate\Support\Collection;
use Rappasoft\LaravelLivewireTables\Traits\Configuration\ActionsConfiguration;
use Rappasoft\LaravelLivewireTables\Traits\Helpers\ActionsHelpers;
@@ -16,6 +17,8 @@ trait WithActions
protected string $actionsPosition = 'right';
+ protected ?Collection $validActions;
+
protected function actions(): array
{
return [];
diff --git a/src/Traits/WithTools.php b/src/Traits/WithTools.php
new file mode 100644
index 000000000..31d91a57a
--- /dev/null
+++ b/src/Traits/WithTools.php
@@ -0,0 +1,16 @@
+label(fn () => null);
+ }
+
+ $this->html();
+ }
+
+ public function getContents(Model $row): null|string|\Illuminate\Support\HtmlString|DataTableConfigurationException|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
+ {
+ $attributeBag = $this->getAttributeBag($row);
+
+ return view($this->getView())
+ ->withIsTailwind($this->isTailwind())
+ ->withIsBootstrap($this->isBootstrap())
+ ->withIcon($this->getIcon($row))
+ ->withClasses($attributeBag['class'])
+ ->withAttributes(collect($attributeBag)->except('class')->toArray());
+ }
+}
diff --git a/src/Views/Traits/Configuration/IconColumnConfiguration.php b/src/Views/Traits/Configuration/IconColumnConfiguration.php
new file mode 100644
index 000000000..f52bc9e2e
--- /dev/null
+++ b/src/Views/Traits/Configuration/IconColumnConfiguration.php
@@ -0,0 +1,13 @@
+iconCallback = $callback;
+
+ return $this;
+ }
+}
diff --git a/src/Views/Traits/Core/HasAttributes.php b/src/Views/Traits/Core/HasAttributes.php
index 76220d4bc..5ddd4653b 100644
--- a/src/Views/Traits/Core/HasAttributes.php
+++ b/src/Views/Traits/Core/HasAttributes.php
@@ -31,7 +31,7 @@ public function hasAttributesCallback(): bool
// TODO: Test
public function getAttributeBag(Model $row): ComponentAttributeBag
{
- return new ComponentAttributeBag($this->hasAttributesCallback() ? app()->call($this->getAttributesCallback(), ['row' => $row]) : []);
+ return new ComponentAttributeBag($this->hasAttributesCallback() ? app()->call($this->getAttributesCallback(), ['row' => $row, 'value' => $this->getValue($row)]) : []);
}
/**
diff --git a/src/Views/Traits/Helpers/IconColumnHelpers.php b/src/Views/Traits/Helpers/IconColumnHelpers.php
new file mode 100644
index 000000000..ceb8f9439
--- /dev/null
+++ b/src/Views/Traits/Helpers/IconColumnHelpers.php
@@ -0,0 +1,27 @@
+hasIconCallback() ? app()->call($this->getIconCallback(), ['row' => $row, 'value' => $this->getValue($row) ?? '']) : ($this->getValue($row));
+ }
+
+ public function getIconCallback(): ?callable
+ {
+ return $this->iconCallback;
+ }
+
+ public function hasIconCallback(): bool
+ {
+ return isset($this->iconCallback);
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
index d930575f7..0bf3aa3e2 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -193,10 +193,10 @@ public function getEnvironmentSetUp($app): void
$app['config']->set('view.cache', false);
$app['config']->set('view.compiled', realpath(storage_path('framework/views')).'/'.rand(0, 100));
- if (file_exists(__DIR__.'/../database/sqlite.database')) {
+ if (file_exists(__DIR__.'/../database/database.sqlite')) {
$app['config']->set('database.connections.sqlite', [
'driver' => 'sqlite',
- 'database' => __DIR__.'/../database/sqlite.database',
+ 'database' => __DIR__.'/../database/database.sqlite',
'prefix' => '',
]);
} else {
diff --git a/tests/Traits/Helpers/ToolsHelpersTest.php b/tests/Traits/Helpers/ToolsHelpersTest.php
new file mode 100644
index 000000000..07533cbbc
--- /dev/null
+++ b/tests/Traits/Helpers/ToolsHelpersTest.php
@@ -0,0 +1,103 @@
+assertTrue($this->basicTable->getToolBarStatus());
+ $this->assertTrue($this->basicTable->getToolsStatus());
+
+ $this->basicTable->setToolBarDisabled();
+
+ $this->assertFalse($this->basicTable->getToolBarStatus());
+ $this->assertTrue($this->basicTable->getToolsStatus());
+
+ }
+
+ public function test_can_get_tools_status(): void
+ {
+ $this->assertTrue($this->basicTable->getToolsStatus());
+ $this->assertTrue($this->basicTable->getToolBarStatus());
+
+ $this->basicTable->setToolsDisabled();
+
+ $this->assertFalse($this->basicTable->getToolsStatus());
+ $this->assertTrue($this->basicTable->getToolBarStatus());
+ }
+
+ public function test_can_get_tools_should_display(): void
+ {
+ $this->assertTrue($this->basicTable->getToolsStatus());
+ $this->assertTrue($this->basicTable->getToolBarStatus());
+ $this->assertTrue($this->basicTable->shouldShowTools());
+ $this->assertTrue($this->basicTable->shouldShowToolBar());
+
+ $this->basicTable->setToolsDisabled();
+
+ $this->assertFalse($this->basicTable->getToolsStatus());
+ $this->assertTrue($this->basicTable->getToolBarStatus());
+ $this->assertFalse($this->basicTable->shouldShowTools());
+ $this->assertFalse($this->basicTable->shouldShowToolBar());
+ }
+
+ public function test_can_get_toolbar_display(): void
+ {
+ $this->assertTrue($this->basicTable->getToolsStatus());
+ $this->assertTrue($this->basicTable->getToolBarStatus());
+ $this->basicTable->setFiltersDisabled();
+ $this->basicTable->setSingleSortingDisabled();
+ $this->basicTable->setSearchDisabled();
+ $this->basicTable->setColumnSelectDisabled();
+ $this->basicTable->setPerPageVisibilityDisabled();
+ $this->basicTable->setSortingDisabled();
+ $this->basicTable->setSortingPillsDisabled();
+
+ $this->assertTrue($this->basicTable->getToolsStatus());
+ $this->assertTrue($this->basicTable->getToolBarStatus());
+ $this->assertFalse($this->basicTable->shouldShowToolBar());
+
+ }
+
+ public function test_can_get_tools_display(): void
+ {
+ $this->assertTrue($this->basicTable->getToolsStatus());
+ $this->assertTrue($this->basicTable->getToolBarStatus());
+ $this->basicTable->setSearchDisabled()
+ ->setColumnSelectDisabled()
+ ->setPerPageVisibilityDisabled();
+ $this->basicTable->setSorts(['id' => 'asc', 'name' => 'desc']);
+
+ $this->assertTrue($this->basicTable->shouldShowToolBar());
+ $this->assertTrue($this->basicTable->shouldShowTools());
+
+ $this->basicTable->setFiltersDisabled();
+
+ $this->assertFalse($this->basicTable->shouldShowToolBar());
+ $this->assertTrue($this->basicTable->shouldShowTools());
+
+ $this->basicTable->setSortingDisabled();
+
+ $this->assertFalse($this->basicTable->shouldShowToolBar());
+ $this->assertFalse($this->basicTable->shouldShowTools());
+
+ $this->basicTable->setFiltersEnabled();
+
+ $this->assertTrue($this->basicTable->shouldShowToolBar());
+ $this->assertTrue($this->basicTable->shouldShowTools());
+
+ $this->basicTable->clearSorts();
+
+ $this->assertTrue($this->basicTable->shouldShowToolBar());
+ $this->assertTrue($this->basicTable->shouldShowTools());
+
+ $this->basicTable->setFiltersDisabled();
+
+ $this->assertFalse($this->basicTable->shouldShowToolBar());
+ $this->assertFalse($this->basicTable->shouldShowTools());
+
+ }
+}
diff --git a/tests/Traits/Visuals/Columns/IconColumnVisualsTest.php b/tests/Traits/Visuals/Columns/IconColumnVisualsTest.php
new file mode 100644
index 000000000..68d3c80fb
--- /dev/null
+++ b/tests/Traits/Visuals/Columns/IconColumnVisualsTest.php
@@ -0,0 +1,64 @@
+setPrimaryKey('id');
+ }
+
+ public function columns(): array
+ {
+ return [
+ \Rappasoft\LaravelLivewireTables\Views\Column::make('Name')->searchable(),
+ \Rappasoft\LaravelLivewireTables\Views\Columns\IconColumn::make('Old Age', 'age')
+ ->setIcon(function (\Rappasoft\LaravelLivewireTables\Tests\Models\Pet $row, int $value) {
+ if ($value >= 5) {
+ return 'heroicon-o-check-circle';
+ } else {
+ return 'heroicon-o-x-circle';
+ }
+ }),
+ ];
+ }
+
+ public function filters(): array
+ {
+ return [];
+ }
+ })
+ ->call('setSearch', 'Cartman')
+ ->assertSeeHtmlInOrder([
+ '',
+ ])
+ ->assertDontSeeHtml('')
+ ->call('setSearch', 'May')
+ ->assertDontSeeHtml('')
+ ->assertSeeHtmlInOrder([
+ '',
+ ]);
+
+ }
+}
diff --git a/tests/Views/Columns/IconColumnTest.php b/tests/Views/Columns/IconColumnTest.php
new file mode 100644
index 000000000..3ac423234
--- /dev/null
+++ b/tests/Views/Columns/IconColumnTest.php
@@ -0,0 +1,108 @@
+assertSame('Icon Column 1', $column->getTitle());
+ }
+
+ public function test_can_get_the_column_view(): void
+ {
+ $column = IconColumn::make('Icon Column 1', 'favorite_color');
+
+ $this->assertSame('livewire-tables::includes.columns.icon', $column->getView());
+ $column->setView('test-icon-column');
+ $this->assertSame('test-icon-column', $column->getView());
+
+ }
+
+ public function test_can_infer_field_name_from_title_if_no_from(): void
+ {
+ $column = IconColumn::make('Icon Column 1');
+
+ $this->assertNull($column->getField());
+ }
+
+ public function test_can_setup_column_correctly(): void
+ {
+ $column = IconColumn::make('Icon Column 1')
+ ->setIcon(function ($row, $value) {
+ if ($value == 1) {
+ return 'heroicon-o-check-circle';
+ } else {
+ return 'heroicon-o-x-circle';
+ }
+ });
+
+ $this->assertNotEmpty($column);
+ }
+
+ public function test_icons_correctly_via_value(): void
+ {
+ $rows = $this->basicTable->getRows();
+ $column = IconColumn::make('Old Age', 'age')
+ ->setIcon(function (Pet $row, int $value) {
+ if ($value >= 5) {
+ return 'heroicon-o-check-circle';
+ } else {
+ return 'heroicon-o-x-circle';
+ }
+ });
+
+ $this->assertSame('heroicon-o-check-circle', $column->getIcon(Pet::where('age', '>', 5)->first()));
+ $this->assertSame('heroicon-o-x-circle', $column->getIcon(Pet::where('age', '<', 4)->first()));
+ }
+
+ public function test_icons_correctly_via_row(): void
+ {
+ $rows = $this->basicTable->getRows();
+ $column = IconColumn::make('Old Age', 'age')
+ ->setIcon(function (Pet $row) {
+ if ($row->age >= 7) {
+ return 'old-icon';
+ } else {
+ return 'young-icon';
+ }
+ });
+
+ $this->assertSame('old-icon', $column->getIcon(Pet::where('age', '>', 9)->first()));
+ $this->assertSame('young-icon', $column->getIcon(Pet::where('age', '<', 4)->first()));
+ }
+
+ public function test_renders_correctly(): void
+ {
+ $rows = $this->basicTable->getRows();
+ $row1 = $rows->first();
+ $column = IconColumn::make('Old Age', 'age')
+ ->setIcon(function (Pet $row, int $value) {
+ if ($value >= 5) {
+ return 'heroicon-o-check-circle';
+ } else {
+ return 'heroicon-o-x-circle';
+ }
+ });
+ $youngString = '';
+ $oldString = '';
+ $firstLine = str_replace(' ', ' ', str_replace(["\r", "\n"], '', $column->getContents(Pet::where('age', '<', 4)->first())));
+ $firstLine = str_replace('> <', '><', $firstLine);
+ $firstLine = str_replace('> <', '><', $firstLine);
+
+ $this->assertSame($oldString, $firstLine);
+
+ $lastLine = str_replace(' ', ' ', str_replace(["\r", "\n"], '', $column->getContents(Pet::where('age', '>', 5)->first())));
+ $lastLine = str_replace('> <', '><', $lastLine);
+ $lastLine = str_replace('> <', '><', $lastLine);
+
+ $this->assertSame($youngString, $lastLine);
+ }
+}