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); + } +}