From c576c28bb7403fa660483e95f78b49a3592331d4 Mon Sep 17 00:00:00 2001 From: Joe <104938042+lrljoe@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:06:03 +0100 Subject: [PATCH] v3.4.16 (#1897) ## [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 --- CHANGELOG.md | 12 ++ database/{sqlite.database => database.sqlite} | Bin 45056 -> 49152 bytes docs/column-types/icon_column.md | 87 ++++++++++++++ docs/column-types/image_columns.md | 2 +- docs/column-types/link_columns.md | 2 +- .../column-types/livewire_component_column.md | 2 +- docs/column-types/sum_column.md | 2 +- docs/column-types/view_component_column.md | 2 +- docs/column-types/wire_link_column.md | 2 +- docs/columns/other-column-types.md | 3 + docs/misc/tools.md | 59 ++++++++++ phpstan-baseline.neon | 76 ++++++++++++ phpstan.neon | 13 +-- .../views/components/tools/toolbar.blade.php | 10 -- resources/views/datatable.blade.php | 10 +- .../views/includes/columns/icon.blade.php | 7 ++ src/Traits/ComponentUtilities.php | 2 +- .../Configuration/ToolsConfiguration.php | 40 +++++++ src/Traits/HasAllTraits.php | 3 +- src/Traits/Helpers/ActionsHelpers.php | 22 ++-- src/Traits/Helpers/SortingHelpers.php | 2 +- src/Traits/Helpers/ToolsHelpers.php | 108 ++++++++++++++++++ src/Traits/WithActions.php | 3 + src/Traits/WithTools.php | 16 +++ src/Views/Columns/IconColumn.php | 43 +++++++ .../Configuration/IconColumnConfiguration.php | 13 +++ src/Views/Traits/Core/HasAttributes.php | 2 +- .../Traits/Helpers/IconColumnHelpers.php | 27 +++++ tests/TestCase.php | 4 +- tests/Traits/Helpers/ToolsHelpersTest.php | 103 +++++++++++++++++ .../Visuals/Columns/IconColumnVisualsTest.php | 64 +++++++++++ tests/Views/Columns/IconColumnTest.php | 108 ++++++++++++++++++ 32 files changed, 807 insertions(+), 42 deletions(-) rename database/{sqlite.database => database.sqlite} (87%) create mode 100644 docs/column-types/icon_column.md create mode 100644 docs/misc/tools.md create mode 100644 phpstan-baseline.neon create mode 100644 resources/views/includes/columns/icon.blade.php create mode 100644 src/Traits/Configuration/ToolsConfiguration.php create mode 100644 src/Traits/Helpers/ToolsHelpers.php create mode 100644 src/Traits/WithTools.php create mode 100644 src/Views/Columns/IconColumn.php create mode 100644 src/Views/Traits/Configuration/IconColumnConfiguration.php create mode 100644 src/Views/Traits/Helpers/IconColumnHelpers.php create mode 100644 tests/Traits/Helpers/ToolsHelpersTest.php create mode 100644 tests/Traits/Visuals/Columns/IconColumnVisualsTest.php create mode 100644 tests/Views/Columns/IconColumnTest.php 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 51e3c6632db04ef6c45a17f38916d86e009bb5ad..1a9e27435b4d4a1ffd860d2f3cb79b2bce625f63 100644 GIT binary patch delta 1339 zcmcgrJ#5oJ81>n496JfuUxE~=a$TUU)Hd!9LnS0gQ@e^tonoA!3&u^at<^LMwkZ?| zrL+>Ppv-JcT@Z={8$%~l6@=&p3lbw@V_@ViPNJrnSbEYY%kRDKeRqE6-5>PsF7qPZ z-9=GU1Q&-3;EKK+n;z<-CLWig;Uh{29a3-)$`{P&r?4cv5oY`lyXP($GOso zG>9!anp$&5#idB~I6MG?)nDPsS|9(84&Z>VS3idbD*Jc+Tc4GyVOb!IY8b zk~)(df&MS7wybb+=N(pCR+VOi=NDF6R{2K4r@}g&a2+NIw>33-a2(BB*nTe>M59fp z9Y<3=+y{67zrbp(yXy&z^>a)Dbo_K|^&l|}xZ2mmgxDkCE5gDP3jT$^;ZOJ-p5WFS zuzK6vo8_2ZU_5w4ljowf!|+TDq&Dn)i4~YQpRycp%PJCb4i(8&Yp!4|a_>*JCyL)$ zs8jG8d=Fp29jIgLo3L_)6{t`Q48{TN+i_F!)bzM~ZCsuiQtOMMj%X=>WxaJ7j|Z^6 zXoiSnyi}E;K3-z#8Y&I|*&&S?Rh4CWEigzox_Lm(5c0dHaCZXFAO->EGQgTRp1_0V NX)gM@$>tO+`v((qXKMfe delta 524 zcmZo@U~YK8G(lRBpMima8;D_mbE1y1B0qy(xEC)_h>KH%fxn60fG?i+ERPKLDQ+dM z^<0*mBAW#Trf_T);oQc=62QhLKKUHC+~g-52Aa)!tnA{VqKs|!C5cHnsRgMe#URY) z9OUX4;;Inh=;Y(7pac|}+{b68RGeQ_qNI?SSCX2ZTBMMdU!ss#nv@3MW|wF`9-Oj>601x_0n_{Ae=mf?9@sP zgaMigMX712MX7nosl`xpie220*~Vtjfs6z#%QDD9y>p s>6}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); + } +}