diff --git a/.github/workflows/run-tests-pcov-pull.yml b/.github/workflows/run-tests-pcov-pull.yml index 08e7eea08..0a5f52d3e 100644 --- a/.github/workflows/run-tests-pcov-pull.yml +++ b/.github/workflows/run-tests-pcov-pull.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - 'develop' + - 'development' - 'master' jobs: diff --git a/.github/workflows/run-tests-pull.yml b/.github/workflows/run-tests-pull.yml index 50c0c38be..1abeaeee8 100644 --- a/.github/workflows/run-tests-pull.yml +++ b/.github/workflows/run-tests-pull.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - 'develop' + - 'development' - 'master' jobs: diff --git a/composer.json b/composer.json index d3e9e6372..bda267c29 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "laravel/pint": "^1.10", "monolog/monolog": "*", "nunomaduro/collision": "^6.0|^7.0|^8.0", - "nunomaduro/larastan": "^2.6", + "larastan/larastan": "^2.6", "orchestra/testbench": "^7.0|^8.0|^9.0", "phpunit/phpunit": "^9.0|^10.0|^11.0" }, diff --git a/docs/bulk-actions/available-methods.md b/docs/bulk-actions/available-methods.md index 22b8210ee..ad98e1999 100644 --- a/docs/bulk-actions/available-methods.md +++ b/docs/bulk-actions/available-methods.md @@ -239,3 +239,38 @@ public function configure(): void ]); } ``` + +## setShouldAlwaysHideBulkActionsDropdownOption + +Allows hiding the Bulk Actions button & menu, regardless of whether there are any items selected, or hideBulkActionsWhenEmptyEnabled behaviour + +```php +public function configure(): void +{ + $this->setShouldAlwaysHideBulkActionsDropdownOption(true); +} +``` + + +## setShouldAlwaysHideBulkActionsDropdownOptionEnabled + +Allows hiding the Bulk Actions button & menu, regardless of whether there are any items selected, or hideBulkActionsWhenEmptyEnabled behaviour + +```php +public function configure(): void +{ + $this->setShouldAlwaysHideBulkActionsDropdownOptionEnabled(); +} +``` + + +## setShouldAlwaysHideBulkActionsDropdownOptionDisabled + +Restores the Bulk Actions to default functionality, so it will respect the hideBulkActionsWhenEmptyEnabled behaviour + +```php +public function configure(): void +{ + $this->setShouldAlwaysHideBulkActionsDropdownOptionDisabled(); +} +``` diff --git a/docs/pagination/available-methods.md b/docs/pagination/available-methods.md index d1b60a375..638e58a4b 100644 --- a/docs/pagination/available-methods.md +++ b/docs/pagination/available-methods.md @@ -263,3 +263,36 @@ public function configure(): void ]); } ``` + +## setShouldRetrieveTotalItemCountStatus + +Used when "simple" pagination is being used, allows the enabling/disabling of the "total records" count. This may be desirable to disable in larger data sets. This is enabled by default. + +```php +public function configure(): void +{ + $this->setShouldRetrieveTotalItemCountStatus(false); +} +``` + +## setShouldRetrieveTotalItemCountEnabled + +Used when "simple" pagination is being used, enables the "total records" count. + +```php +public function configure(): void +{ + $this->setShouldRetrieveTotalItemCountEnabled(); +} +``` + +## setShouldRetrieveTotalItemCountDisabled + +Used when "simple" pagination is being used, disables the "total records" count. + +```php +public function configure(): void +{ + $this->setShouldRetrieveTotalItemCountDisabled(); +} +``` diff --git a/phpstan.neon b/phpstan.neon index 7ed8f5027..a0324459d 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ includes: - - vendor/nunomaduro/larastan/extension.neon + - vendor/larastan/larastan/extension.neon parameters: paths: @@ -10,11 +10,11 @@ parameters: tmpDir: build/phpstan checkOctaneCompatibility: true checkModelProperties: true - checkMissingIterableValueType: false treatPhpDocTypesAsCertain: false reportUnmatchedIgnoredErrors: false - checkGenericClassInNonGenericObjectType: false ignoreErrors: + - identifier: missingType.generics + - identifier: missingType.iterableValue - '#Access to an undefined property Rappasoft\\LaravelLivewireTables\\Views\\Column\:\:\$view#' - "#Unsafe usage of new static#" - '#on array\, mixed\>\> in empty\(\) does not exist.#' diff --git a/resources/js/laravel-livewire-tables.js b/resources/js/laravel-livewire-tables.js index 532a615ea..0d068dac1 100644 --- a/resources/js/laravel-livewire-tables.js +++ b/resources/js/laravel-livewire-tables.js @@ -8,7 +8,7 @@ document.addEventListener('alpine:init', () => { paginationTotalItemCount: wire.entangle('paginationTotalItemCount'), paginationCurrentItems: wire.entangle('paginationCurrentItems'), selectedItems: wire.entangle('selected'), - alwaysShowBulkActions: !wire.entangle('hideBulkActionsWhenEmpty'), + hideBulkActionsWhenEmpty: wire.entangle('hideBulkActionsWhenEmpty'), toggleSelectAll() { if (!showBulkActionsAlpine) { return; diff --git a/resources/js/laravel-livewire-tables.min.js b/resources/js/laravel-livewire-tables.min.js index 6d78ed178..3b5991c4a 100644 --- a/resources/js/laravel-livewire-tables.min.js +++ b/resources/js/laravel-livewire-tables.min.js @@ -1 +1 @@ -document.addEventListener("alpine:init",()=>{Alpine.data("tableWrapper",(e,t)=>({childElementOpen:!1,filtersOpen:e.entangle("filterSlideDownDefaultVisible"),paginationCurrentCount:e.entangle("paginationCurrentCount"),paginationTotalItemCount:e.entangle("paginationTotalItemCount"),paginationCurrentItems:e.entangle("paginationCurrentItems"),selectedItems:e.entangle("selected"),alwaysShowBulkActions:!e.entangle("hideBulkActionsWhenEmpty"),toggleSelectAll(){t&&(this.paginationTotalItemCount===this.selectedItems.length?this.clearSelected():this.setAllSelected())},setAllSelected(){t&&e.setAllSelected()},clearSelected(){t&&e.clearSelected()},selectAllOnPage(){if(!t)return;let e=this.selectedItems,i=this.paginationCurrentItems.values();for(let l of i)e.push(l.toString());this.selectedItems=[...new Set(e)]}})),Alpine.data("numberRangeFilter",(e,t,i,l,a)=>({allFilters:e.entangle("filterComponents",!1),originalMin:0,originalMax:100,filterMin:0,filterMax:100,currentMin:0,currentMax:100,hasUpdate:!1,wireValues:e.entangle("filterComponents."+t,!1),defaultMin:l.minRange,defaultMax:l.maxRange,restrictUpdates:!1,updateStyles(){let e=document.getElementById(i),t=document.getElementById(a+"-min"),l=document.getElementById(a+"-max");e.style.setProperty("--value-a",t.value),e.style.setProperty("--text-value-a",JSON.stringify(t.value)),e.style.setProperty("--value-b",l.value),e.style.setProperty("--text-value-b",JSON.stringify(l.value))},setupWire(){void 0!==this.wireValues?(this.filterMin=this.originalMin=void 0!==this.wireValues.min?this.wireValues.min:this.defaultMin,this.filterMax=this.originalMax=void 0!==this.wireValues.max?this.wireValues.max:this.defaultMax):(this.filterMin=this.originalMin=this.defaultMin,this.filterMax=this.originalMax=this.defaultMax),this.updateStyles()},allowUpdates(){this.updateWire()},updateWire(){let e=parseInt(this.filterMin),t=parseInt(this.filterMax);(e!=this.originalMin||t!=this.originalMax)&&(tthis.setupWire())}})),Alpine.data("flatpickrFilter",(e,t,i,l,a)=>({wireValues:e.entangle("filterComponents."+t),flatpickrInstance:flatpickr(l,{mode:"range",clickOpens:!0,allowInvalidPreload:!0,defaultDate:[],ariaDateFormat:i.ariaDateFormat,allowInput:i.allowInput,altFormat:i.altFormat,altInput:i.altInput,dateFormat:i.dateFormat,locale:"en",minDate:i.earliestDate,maxDate:i.latestDate,onOpen:function(){window.childElementOpen=!0},onChange:function(i,l,a){if(i.length>1){var s=l.split(" ")[0],r=l.split(" ")[2],n={};window.childElementOpen=!1,window.filterPopoverOpen=!1,n={minDate:s,maxDate:r},e.set("filterComponents."+t,n)}}}),setupWire(){if(void 0!==this.wireValues){if(void 0!==this.wireValues.minDate&&void 0!==this.wireValues.maxDate){let e=[this.wireValues.minDate,this.wireValues.maxDate];this.flatpickrInstance.setDate(e)}else this.flatpickrInstance.setDate([])}else this.flatpickrInstance.setDate([])},init(){this.setupWire(),this.$watch("wireValues",e=>this.setupWire())}})),Alpine.data("reorderFunction",(e,t,i)=>({dragging:!1,reorderEnabled:!1,sourceID:"",targetID:"",evenRowClasses:"",oddRowClasses:"",currentlyHighlightedElement:"",evenRowClassArray:{},oddRowClassArray:{},evenNotInOdd:{},oddNotInEven:{},orderedRows:[],defaultReorderColumn:e.get("defaultReorderColumn"),reorderStatus:e.get("reorderStatus"),currentlyReorderingStatus:e.entangle("currentlyReorderingStatus"),hideReorderColumnUnlessReorderingStatus:e.entangle("hideReorderColumnUnlessReorderingStatus"),reorderDisplayColumn:e.entangle("reorderDisplayColumn"),dragStart(e){this.sourceID=e.target.id,e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",e.target.id),e.target.classList.add("laravel-livewire-tables-dragging")},dragOverEvent(e){"object"==typeof this.currentlyHighlightedElement&&this.currentlyHighlightedElement.classList.remove("laravel-livewire-tables-highlight-bottom","laravel-livewire-tables-highlight-top");let t=e.target.closest("tr");this.currentlyHighlightedElement=t,e.offsetYi.getBoundingClientRect().height/2?l.insertBefore(a,i.nextSibling):l.insertBefore(a,i),r!l.includes(e)),this.oddNotInEven=l.filter(e=>!i.includes(e)),i=[],l=[])}},init(){this.$watch("currentlyReorderingStatus",e=>this.setupEvenOddClasses())}}))}); \ No newline at end of file +document.addEventListener("alpine:init",()=>{Alpine.data("tableWrapper",(e,t)=>({childElementOpen:!1,filtersOpen:e.entangle("filterSlideDownDefaultVisible"),paginationCurrentCount:e.entangle("paginationCurrentCount"),paginationTotalItemCount:e.entangle("paginationTotalItemCount"),paginationCurrentItems:e.entangle("paginationCurrentItems"),selectedItems:e.entangle("selected"),hideBulkActionsWhenEmpty:e.entangle("hideBulkActionsWhenEmpty"),toggleSelectAll(){t&&(this.paginationTotalItemCount===this.selectedItems.length?this.clearSelected():this.setAllSelected())},setAllSelected(){t&&e.setAllSelected()},clearSelected(){t&&e.clearSelected()},selectAllOnPage(){if(!t)return;let e=this.selectedItems,i=this.paginationCurrentItems.values();for(let l of i)e.push(l.toString());this.selectedItems=[...new Set(e)]}})),Alpine.data("numberRangeFilter",(e,t,i,l,a)=>({allFilters:e.entangle("filterComponents",!1),originalMin:0,originalMax:100,filterMin:0,filterMax:100,currentMin:0,currentMax:100,hasUpdate:!1,wireValues:e.entangle("filterComponents."+t,!1),defaultMin:l.minRange,defaultMax:l.maxRange,restrictUpdates:!1,updateStyles(){let e=document.getElementById(i),t=document.getElementById(a+"-min"),l=document.getElementById(a+"-max");e.style.setProperty("--value-a",t.value),e.style.setProperty("--text-value-a",JSON.stringify(t.value)),e.style.setProperty("--value-b",l.value),e.style.setProperty("--text-value-b",JSON.stringify(l.value))},setupWire(){void 0!==this.wireValues?(this.filterMin=this.originalMin=void 0!==this.wireValues.min?this.wireValues.min:this.defaultMin,this.filterMax=this.originalMax=void 0!==this.wireValues.max?this.wireValues.max:this.defaultMax):(this.filterMin=this.originalMin=this.defaultMin,this.filterMax=this.originalMax=this.defaultMax),this.updateStyles()},allowUpdates(){this.updateWire()},updateWire(){let e=parseInt(this.filterMin),t=parseInt(this.filterMax);(e!=this.originalMin||t!=this.originalMax)&&(tthis.setupWire())}})),Alpine.data("flatpickrFilter",(e,t,i,l,a)=>({wireValues:e.entangle("filterComponents."+t),flatpickrInstance:flatpickr(l,{mode:"range",clickOpens:!0,allowInvalidPreload:!0,defaultDate:[],ariaDateFormat:i.ariaDateFormat,allowInput:i.allowInput,altFormat:i.altFormat,altInput:i.altInput,dateFormat:i.dateFormat,locale:"en",minDate:i.earliestDate,maxDate:i.latestDate,onOpen:function(){window.childElementOpen=!0},onChange:function(i,l,a){if(i.length>1){var s=l.split(" ")[0],r=l.split(" ")[2],n={};window.childElementOpen=!1,window.filterPopoverOpen=!1,n={minDate:s,maxDate:r},e.set("filterComponents."+t,n)}}}),setupWire(){if(void 0!==this.wireValues){if(void 0!==this.wireValues.minDate&&void 0!==this.wireValues.maxDate){let e=[this.wireValues.minDate,this.wireValues.maxDate];this.flatpickrInstance.setDate(e)}else this.flatpickrInstance.setDate([])}else this.flatpickrInstance.setDate([])},init(){this.setupWire(),this.$watch("wireValues",e=>this.setupWire())}})),Alpine.data("reorderFunction",(e,t,i)=>({dragging:!1,reorderEnabled:!1,sourceID:"",targetID:"",evenRowClasses:"",oddRowClasses:"",currentlyHighlightedElement:"",evenRowClassArray:{},oddRowClassArray:{},evenNotInOdd:{},oddNotInEven:{},orderedRows:[],defaultReorderColumn:e.get("defaultReorderColumn"),reorderStatus:e.get("reorderStatus"),currentlyReorderingStatus:e.entangle("currentlyReorderingStatus"),hideReorderColumnUnlessReorderingStatus:e.entangle("hideReorderColumnUnlessReorderingStatus"),reorderDisplayColumn:e.entangle("reorderDisplayColumn"),dragStart(e){this.sourceID=e.target.id,e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",e.target.id),e.target.classList.add("laravel-livewire-tables-dragging")},dragOverEvent(e){"object"==typeof this.currentlyHighlightedElement&&this.currentlyHighlightedElement.classList.remove("laravel-livewire-tables-highlight-bottom","laravel-livewire-tables-highlight-top");let t=e.target.closest("tr");this.currentlyHighlightedElement=t,e.offsetYi.getBoundingClientRect().height/2?l.insertBefore(a,i.nextSibling):l.insertBefore(a,i),r!l.includes(e)),this.oddNotInEven=l.filter(e=>!i.includes(e)),i=[],l=[])}},init(){this.$watch("currentlyReorderingStatus",e=>this.setupEvenOddClasses())}}))}); \ No newline at end of file diff --git a/resources/views/components/table/td.blade.php b/resources/views/components/table/td.blade.php index 1ae7e41d6..0d6973242 100644 --- a/resources/views/components/table/td.blade.php +++ b/resources/views/components/table/td.blade.php @@ -21,7 +21,7 @@ ->class(['d-none' => $component->isBootstrap() && $column && $column->shouldCollapseAlways()]) ->class(['d-none d-md-table-cell' => $component->isBootstrap() && $column && $column->shouldCollapseOnMobile()]) ->class(['d-none d-lg-table-cell' => $component->isBootstrap() && $column && $column->shouldCollapseOnTablet()]) - ->style(['cursor:pointer' => $component->isBootstrap()]) + ->style(['cursor:pointer' => $component->isBootstrap() && $column && $column->isClickable()]) ->except('default') }} > diff --git a/resources/views/components/tools/toolbar.blade.php b/resources/views/components/tools/toolbar.blade.php index a753403c6..84bb061e8 100644 --- a/resources/views/components/tools/toolbar.blade.php +++ b/resources/views/components/tools/toolbar.blade.php @@ -56,7 +56,7 @@ @include($component->getConfigurableAreaFor('toolbar-right-start'), $component->getParametersForConfigurableArea('toolbar-right-start')) @endif - @if ($component->showBulkActionsDropdownAlpine()) + @if ($component->showBulkActionsDropdownAlpine() && $this->shouldAlwaysHideBulkActionsDropdownOption != true) @endif diff --git a/resources/views/components/tools/toolbar/items/bulk-actions.blade.php b/resources/views/components/tools/toolbar/items/bulk-actions.blade.php index 82fe34ca1..811a27b99 100644 --- a/resources/views/components/tools/toolbar/items/bulk-actions.blade.php +++ b/resources/views/components/tools/toolbar/items/bulk-actions.blade.php @@ -1,7 +1,7 @@ @aware(['component', 'tableName'])
$component->isBootstrap(), 'w-full md:w-auto mb-4 md:mb-0' => $component->isTailwind(), diff --git a/src/DataTableComponent.php b/src/DataTableComponent.php index b89da3dee..906878d7d 100644 --- a/src/DataTableComponent.php +++ b/src/DataTableComponent.php @@ -29,9 +29,7 @@ public function boot(): void /** * Runs on every request, after the component is mounted or hydrated, but before any update methods are called */ - public function booted(): void - { - } + public function booted(): void {} public function render(): \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View { diff --git a/src/Exceptions/DataTableConfigurationException.php b/src/Exceptions/DataTableConfigurationException.php index 1dabdf83a..795d82b06 100644 --- a/src/Exceptions/DataTableConfigurationException.php +++ b/src/Exceptions/DataTableConfigurationException.php @@ -2,6 +2,4 @@ namespace Rappasoft\LaravelLivewireTables\Exceptions; -class DataTableConfigurationException extends \Exception -{ -} +class DataTableConfigurationException extends \Exception {} diff --git a/src/Exceptions/NoColumnsException.php b/src/Exceptions/NoColumnsException.php index 5d11959c3..875a457cb 100644 --- a/src/Exceptions/NoColumnsException.php +++ b/src/Exceptions/NoColumnsException.php @@ -2,6 +2,4 @@ namespace Rappasoft\LaravelLivewireTables\Exceptions; -class NoColumnsException extends \Exception -{ -} +class NoColumnsException extends \Exception {} diff --git a/src/Exceptions/NoSearchableColumnsException.php b/src/Exceptions/NoSearchableColumnsException.php index de6b56713..5597b1235 100644 --- a/src/Exceptions/NoSearchableColumnsException.php +++ b/src/Exceptions/NoSearchableColumnsException.php @@ -2,6 +2,4 @@ namespace Rappasoft\LaravelLivewireTables\Exceptions; -class NoSearchableColumnsException extends \Exception -{ -} +class NoSearchableColumnsException extends \Exception {} diff --git a/src/Exceptions/NoSortableColumnsException.php b/src/Exceptions/NoSortableColumnsException.php index 825c54339..7ba3828f9 100644 --- a/src/Exceptions/NoSortableColumnsException.php +++ b/src/Exceptions/NoSortableColumnsException.php @@ -2,6 +2,4 @@ namespace Rappasoft\LaravelLivewireTables\Exceptions; -class NoSortableColumnsException extends \Exception -{ -} +class NoSortableColumnsException extends \Exception {} diff --git a/src/LaravelLivewireTablesServiceProvider.php b/src/LaravelLivewireTablesServiceProvider.php index f0a50ed70..e10027b51 100644 --- a/src/LaravelLivewireTablesServiceProvider.php +++ b/src/LaravelLivewireTablesServiceProvider.php @@ -14,7 +14,11 @@ class LaravelLivewireTablesServiceProvider extends ServiceProvider public function boot(): void { - AboutCommand::add('Rappasoft Laravel Livewire Tables', fn () => ['Version' => '3.2.7']); + if (class_exists(AboutCommand::class) && class_exists(\Composer\InstalledVersions::class)) { + AboutCommand::add('Rappasoft Laravel Livewire Tables', [ + 'Version' => \Composer\InstalledVersions::getPrettyVersion('rappasoft/laravel-livewire-tables'), + ]); + } $this->mergeConfigFrom( __DIR__.'/../config/livewire-tables.php', 'livewire-tables' @@ -40,7 +44,7 @@ public function boot(): void } - public function consoleCommands() + public function consoleCommands(): void { if ($this->app->runningInConsole()) { diff --git a/src/Traits/Configuration/BulkActionsConfiguration.php b/src/Traits/Configuration/BulkActionsConfiguration.php index 813d46f42..d0d5e17f3 100644 --- a/src/Traits/Configuration/BulkActionsConfiguration.php +++ b/src/Traits/Configuration/BulkActionsConfiguration.php @@ -150,4 +150,25 @@ public function setBulkActionsTdCheckboxAttributes(array $bulkActionsTdCheckboxA return $this; } + + public function setShouldAlwaysHideBulkActionsDropdownOption(bool $status = false): self + { + $this->alwaysHideBulkActionsDropdownOption = $status; + + return $this; + } + + public function setShouldAlwaysHideBulkActionsDropdownOptionEnabled(): self + { + $this->setShouldAlwaysHideBulkActionsDropdownOption(true); + + return $this; + } + + public function setShouldAlwaysHideBulkActionsDropdownOptionDisabled(): self + { + $this->setShouldAlwaysHideBulkActionsDropdownOption(false); + + return $this; + } } diff --git a/src/Traits/Configuration/PaginationConfiguration.php b/src/Traits/Configuration/PaginationConfiguration.php index d7ffa5c34..a8877653a 100644 --- a/src/Traits/Configuration/PaginationConfiguration.php +++ b/src/Traits/Configuration/PaginationConfiguration.php @@ -155,4 +155,26 @@ public function setPerPageFieldAttributes(array $attributes = []): self return $this; } + + public function setShouldRetrieveTotalItemCountStatus(bool $status): self + { + $this->shouldRetrieveTotalItemCount = $status; + + return $this; + + } + + public function setShouldRetrieveTotalItemCountEnabled(): self + { + $this->setShouldRetrieveTotalItemCountStatus(true); + + return $this; + } + + public function setShouldRetrieveTotalItemCountDisabled(): self + { + $this->setShouldRetrieveTotalItemCountStatus(false); + + return $this; + } } diff --git a/src/Traits/Helpers/BulkActionsHelpers.php b/src/Traits/Helpers/BulkActionsHelpers.php index 29f162bb6..70ea427a5 100644 --- a/src/Traits/Helpers/BulkActionsHelpers.php +++ b/src/Traits/Helpers/BulkActionsHelpers.php @@ -2,6 +2,8 @@ namespace Rappasoft\LaravelLivewireTables\Traits\Helpers; +use Livewire\Attributes\Computed; + trait BulkActionsHelpers { public function getBulkActionsStatus(): bool @@ -212,4 +214,10 @@ public function getBulkActionsTdCheckboxAttributes(): array { return $this->bulkActionsTdCheckboxAttributes ?? ['default' => true]; } + + #[Computed] + public function shouldAlwaysHideBulkActionsDropdownOption(): bool + { + return $this->alwaysHideBulkActionsDropdownOption ?? false; + } } diff --git a/src/Traits/Helpers/PaginationHelpers.php b/src/Traits/Helpers/PaginationHelpers.php index 7a744f225..717af7c12 100644 --- a/src/Traits/Helpers/PaginationHelpers.php +++ b/src/Traits/Helpers/PaginationHelpers.php @@ -149,4 +149,10 @@ public function getPerPageFieldAttributes(): array { return $this->perPageFieldAttributes; } + + #[Computed] + public function getShouldRetrieveTotalItemCount(): bool + { + return $this->shouldRetrieveTotalItemCount; + } } diff --git a/src/Traits/Helpers/TableAttributeHelpers.php b/src/Traits/Helpers/TableAttributeHelpers.php index 3da2da12e..866e72526 100644 --- a/src/Traits/Helpers/TableAttributeHelpers.php +++ b/src/Traits/Helpers/TableAttributeHelpers.php @@ -84,12 +84,12 @@ public function hasTableRowUrl(): bool return $this->trUrlCallback !== null; } - public function getTableRowUrl($row): ?string + public function getTableRowUrl(int|Model $row): ?string { return $this->trUrlCallback ? call_user_func($this->trUrlCallback, $row) : null; } - public function getTableRowUrlTarget($row): ?string + public function getTableRowUrlTarget(int|Model $row): ?string { return $this->trUrlTargetCallback ? call_user_func($this->trUrlTargetCallback, $row) : null; } diff --git a/src/Traits/WithBulkActions.php b/src/Traits/WithBulkActions.php index e05175733..08f69197b 100644 --- a/src/Traits/WithBulkActions.php +++ b/src/Traits/WithBulkActions.php @@ -34,6 +34,8 @@ trait WithBulkActions protected array $bulkActionsTdCheckboxAttributes = ['default' => true]; + protected bool $alwaysHideBulkActionsDropdownOption = false; + public function bulkActions(): array { return property_exists($this, 'bulkActions') ? $this->bulkActions : []; diff --git a/src/Traits/WithData.php b/src/Traits/WithData.php index 9dcd44a4c..6d3261c93 100644 --- a/src/Traits/WithData.php +++ b/src/Traits/WithData.php @@ -80,21 +80,25 @@ protected function executeQuery(): Collection|CursorPaginator|Paginator|LengthAw $this->paginationTotalItemCount = $paginatedResults->total() ?? 0; return $paginatedResults; - } - - if ($this->isPaginationMethod('simple')) { + } elseif ($this->isPaginationMethod('simple')) { - $this->paginationTotalItemCount = $this->getBuilder()->count(); + if ($this->getShouldRetrieveTotalItemCount()) { + $this->paginationTotalItemCount = $this->getBuilder()->count(); - return $this->getBuilder()->simplePaginate($this->getPerPage() === -1 ? $this->paginationTotalItemCount : $this->getPerPage(), ['*'], $this->getComputedPageName()); + return $this->getBuilder()->simplePaginate($this->getPerPage() === -1 ? $this->paginationTotalItemCount : $this->getPerPage(), ['*'], $this->getComputedPageName()); + } else { + $this->paginationTotalItemCount = -1; - } + return $this->getBuilder()->simplePaginate($this->getPerPage() === -1 ? 10 : $this->getPerPage(), ['*'], $this->getComputedPageName()); + } - if ($this->isPaginationMethod('cursor')) { + } elseif ($this->isPaginationMethod('cursor')) { $this->paginationTotalItemCount = $this->getBuilder()->count(); return $this->getBuilder()->cursorPaginate($this->getPerPage() === -1 ? $this->paginationTotalItemCount : $this->getPerPage(), ['*'], $this->getComputedPageName()); + } else { + throw new DataTableConfigurationException('Pagination method must be either simple, standard or cursor'); } } diff --git a/src/Traits/WithPagination.php b/src/Traits/WithPagination.php index 676d034b6..6f022a9fb 100644 --- a/src/Traits/WithPagination.php +++ b/src/Traits/WithPagination.php @@ -41,6 +41,8 @@ trait WithPagination protected array $perPageFieldAttributes = ['default-styling' => true, 'default-colors' => true, 'class' => '']; + protected bool $shouldRetrieveTotalItemCount = true; + public function mountWithPagination(): void { $sessionPerPage = session()->get($this->getPerPagePaginationSessionKey(), $this->getPerPageAccepted()[0] ?? 10); diff --git a/src/Traits/WithReordering.php b/src/Traits/WithReordering.php index 33679a1aa..553c7c42e 100644 --- a/src/Traits/WithReordering.php +++ b/src/Traits/WithReordering.php @@ -40,10 +40,7 @@ public function setupReordering(): void $this->restartReorderingIfNecessary(); } - public function enablePaginatedReordering(): void - { - - } + public function enablePaginatedReordering(): void {} public function enableReordering(): void { diff --git a/src/Views/Columns/ArrayColumn.php b/src/Views/Columns/ArrayColumn.php new file mode 100644 index 000000000..be9366db0 --- /dev/null +++ b/src/Views/Columns/ArrayColumn.php @@ -0,0 +1,31 @@ +'; + + public string $emptyValue = ''; + + protected mixed $dataCallback = null; + + protected mixed $outputFormat = null; + + public function __construct(string $title, ?string $from = null) + { + parent::__construct($title, $from); + if (! isset($from)) { + $this->label(fn () => null); + } + } +} diff --git a/src/Views/Traits/Configuration/ArrayColumnConfiguration.php b/src/Views/Traits/Configuration/ArrayColumnConfiguration.php new file mode 100644 index 000000000..72188fd79 --- /dev/null +++ b/src/Views/Traits/Configuration/ArrayColumnConfiguration.php @@ -0,0 +1,29 @@ +separator = $value; + + return $this; + } + + public function data(callable $callable): self + { + $this->dataCallback = $callable; + + return $this; + } + + public function outputFormat(callable $callable): self + { + $this->outputFormat = $callable; + + return $this; + } +} diff --git a/src/Views/Traits/Configuration/ImageColumnConfiguration.php b/src/Views/Traits/Configuration/ImageColumnConfiguration.php index e1283c2dc..8ab662b87 100644 --- a/src/Views/Traits/Configuration/ImageColumnConfiguration.php +++ b/src/Views/Traits/Configuration/ImageColumnConfiguration.php @@ -2,6 +2,4 @@ namespace Rappasoft\LaravelLivewireTables\Views\Traits\Configuration; -trait ImageColumnConfiguration -{ -} +trait ImageColumnConfiguration {} diff --git a/src/Views/Traits/Configuration/LinkColumnConfiguration.php b/src/Views/Traits/Configuration/LinkColumnConfiguration.php index dedcd6430..9d07ca9ad 100644 --- a/src/Views/Traits/Configuration/LinkColumnConfiguration.php +++ b/src/Views/Traits/Configuration/LinkColumnConfiguration.php @@ -2,6 +2,4 @@ namespace Rappasoft\LaravelLivewireTables\Views\Traits\Configuration; -trait LinkColumnConfiguration -{ -} +trait LinkColumnConfiguration {} diff --git a/src/Views/Traits/Core/HasAttributes.php b/src/Views/Traits/Core/HasAttributes.php index 2707b8671..2978d5822 100644 --- a/src/Views/Traits/Core/HasAttributes.php +++ b/src/Views/Traits/Core/HasAttributes.php @@ -11,7 +11,7 @@ trait HasAttributes { protected ?Closure $attributesCallback = null; - public function attributes(Closure $callback): self + public function attributes(Closure $callback): static { $this->attributesCallback = $callback; diff --git a/src/Views/Traits/Helpers/ArrayColumnHelpers.php b/src/Views/Traits/Helpers/ArrayColumnHelpers.php new file mode 100644 index 000000000..7c32f7c70 --- /dev/null +++ b/src/Views/Traits/Helpers/ArrayColumnHelpers.php @@ -0,0 +1,69 @@ +separator !== null && is_string($this->separator); + } + + public function getSeparator(): string + { + return $this->separator; + } + + public function getEmptyValue(): string + { + return $this->emptyValue; + } + + public function hasDataCallback(): bool + { + return isset($this->dataCallback) && is_callable($this->dataCallback); + } + + public function getDataCallback(): ?callable + { + return $this->dataCallback; + } + + public function hasOutputFormatCallback(): bool + { + return isset($this->outputFormat) && is_callable($this->outputFormat); + } + + public function getOutputFormatCallback(): ?callable + { + return $this->outputFormat; + } + + public function getContents(Model $row): null|string|\BackedEnum|HtmlString|DataTableConfigurationException|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View + { + $outputValues = []; + $value = $this->getValue($row); + + if (! $this->hasSeparator()) { + throw new DataTableConfigurationException('You must set a valid separator on an ArrayColumn'); + } + + if (! $this->hasDataCallback()) { + throw new DataTableConfigurationException('You must set a data() method on an ArrayColumn'); + } + + if (! $this->hasOutputFormatCallback()) { + throw new DataTableConfigurationException('You must set an outputFormat() method on an ArrayColumn'); + } + + foreach (call_user_func($this->getDataCallback(), $value, $row) as $i => $v) { + $outputValues[] = call_user_func($this->getOutputFormatCallback(), $i, $v); + } + + return new HtmlString((! empty($outputValues) ? implode($this->getSeparator(), $outputValues) : $this->getEmptyValue())); + } +} diff --git a/src/Views/Traits/Helpers/ImageColumnHelpers.php b/src/Views/Traits/Helpers/ImageColumnHelpers.php index 98de49507..2226586a1 100644 --- a/src/Views/Traits/Helpers/ImageColumnHelpers.php +++ b/src/Views/Traits/Helpers/ImageColumnHelpers.php @@ -2,6 +2,4 @@ namespace Rappasoft\LaravelLivewireTables\Views\Traits\Helpers; -trait ImageColumnHelpers -{ -} +trait ImageColumnHelpers {} diff --git a/src/Views/Traits/Helpers/LinkColumnHelpers.php b/src/Views/Traits/Helpers/LinkColumnHelpers.php index ef8026bc0..4555786d2 100644 --- a/src/Views/Traits/Helpers/LinkColumnHelpers.php +++ b/src/Views/Traits/Helpers/LinkColumnHelpers.php @@ -2,6 +2,4 @@ namespace Rappasoft\LaravelLivewireTables\Views\Traits\Helpers; -trait LinkColumnHelpers -{ -} +trait LinkColumnHelpers {} diff --git a/tests/DataTableComponentTest.php b/tests/DataTableComponentTest.php index c62fa4e09..5cd0115ff 100644 --- a/tests/DataTableComponentTest.php +++ b/tests/DataTableComponentTest.php @@ -55,9 +55,7 @@ public function test_default_fingerprint_will_always_be_the_same_for_same_datata public function test_default_datatable_fingerprints_will_be_different_for_each_table(): void { - $mockTable = new class() extends PetsTable - { - }; + $mockTable = new class() extends PetsTable {}; $this->assertNotSame($this->basicTable->getDataTableFingerprint(), $mockTable->getDataTableFingerprint()); } @@ -66,9 +64,7 @@ public function test_default_fingerprint_will_be_url_friendy(): void { $mocks = []; for ($i = 0; $i < 9; $i++) { - $mocks[$i] = new class() extends PetsTable - { - }; + $mocks[$i] = new class() extends PetsTable {}; $this->assertFalse(filter_var('http://'.$mocks[$i]->getDataTableFingerprint().'.dev', FILTER_VALIDATE_URL) === false); } // control diff --git a/tests/Http/Livewire/FailingTables/NoPrimaryKeyTable.php b/tests/Http/Livewire/FailingTables/NoPrimaryKeyTable.php index d71f7f3ec..be6f0100c 100644 --- a/tests/Http/Livewire/FailingTables/NoPrimaryKeyTable.php +++ b/tests/Http/Livewire/FailingTables/NoPrimaryKeyTable.php @@ -22,9 +22,7 @@ class NoPrimaryKeyTable extends DataTableComponent { public $model = Pet::class; - public function configure(): void - { - } + public function configure(): void {} public function columns(): array { diff --git a/tests/Traits/Helpers/PaginationHelpersTest.php b/tests/Traits/Helpers/PaginationHelpersTest.php index 471ee0d7f..0ec6557a4 100644 --- a/tests/Traits/Helpers/PaginationHelpersTest.php +++ b/tests/Traits/Helpers/PaginationHelpersTest.php @@ -141,4 +141,34 @@ public function test_can_get_pagination_field_attributes(): void $this->assertSame(['default-styling' => false, 'default-colors' => true, 'class' => 'bg-blue-500 dark:bg-red-500'], $this->basicTable->getPerPageFieldAttributes()); } + + public function test_can_toggle_total_item_count_retrieval(): void + { + + $this->assertTrue($this->basicTable->getShouldRetrieveTotalItemCount()); + + $this->basicTable->setShouldRetrieveTotalItemCountDisabled(); + + $this->assertFalse($this->basicTable->getShouldRetrieveTotalItemCount()); + + $this->basicTable->setShouldRetrieveTotalItemCountEnabled(); + + $this->assertTrue($this->basicTable->getShouldRetrieveTotalItemCount()); + + } + + public function test_can_toggle_total_item_count_retrieval_via_status(): void + { + + $this->assertTrue($this->basicTable->getShouldRetrieveTotalItemCount()); + + $this->basicTable->setShouldRetrieveTotalItemCountStatus(false); + + $this->assertFalse($this->basicTable->getShouldRetrieveTotalItemCount()); + + $this->basicTable->setShouldRetrieveTotalItemCountStatus(true); + + $this->assertTrue($this->basicTable->getShouldRetrieveTotalItemCount()); + + } } diff --git a/tests/Traits/Visuals/BulkActionsVisualsTest.php b/tests/Traits/Visuals/BulkActionsVisualsTest.php index 5447891da..91f73c177 100644 --- a/tests/Traits/Visuals/BulkActionsVisualsTest.php +++ b/tests/Traits/Visuals/BulkActionsVisualsTest.php @@ -80,4 +80,113 @@ public function test_bulk_actions_row_shows_correct_for_select_some(): void ->assertSee('do you want to select all') ->assertDontSee('You are currently selecting all'); }*/ + + public function test_bulk_dropdown_shows_when_necessary_extended(): void + { + Livewire::test(new class extends PetsTable + { + public function configure(): void + { + $this->setPrimaryKey('id'); + } + + public function bulkActions(): array + { + return ['exportBulk' => 'exportBulk']; + } + + public function exportBulk($items) + { + return $items; + } + })->assertSee('Bulk Actions'); + } + + public function test_bulk_dropdown_shows_when_not_permanently_hidden(): void + { + Livewire::test(new class extends PetsTable + { + public function configure(): void + { + $this->setPrimaryKey('id') + ->setShouldAlwaysHideBulkActionsDropdownOption(false); + } + + public function bulkActions(): array + { + return ['exportBulk' => 'exportBulk']; + } + + public function exportBulk($items) + { + return $items; + } + })->assertSee('Bulk Actions'); + } + + public function test_bulk_dropdown_hides_when_permanently_hidden(): void + { + Livewire::test(new class extends PetsTable + { + public function configure(): void + { + $this->setPrimaryKey('id') + ->setShouldAlwaysHideBulkActionsDropdownOption(true); + } + + public function bulkActions(): array + { + return ['exportBulk' => 'exportBulk']; + } + + public function exportBulk($items) + { + return $items; + } + })->assertDontSee('Bulk Actions'); + } + + public function test_bulk_dropdown_shows_when_not_permanently_hidden_disabled(): void + { + Livewire::test(new class extends PetsTable + { + public function configure(): void + { + $this->setPrimaryKey('id') + ->setShouldAlwaysHideBulkActionsDropdownOptionDisabled(); + } + + public function bulkActions(): array + { + return ['exportBulk' => 'exportBulk']; + } + + public function exportBulk($items) + { + return $items; + } + })->assertSee('Bulk Actions'); + } + + public function test_bulk_dropdown_hides_when_permanently_hidden_enabled(): void + { + Livewire::test(new class extends PetsTable + { + public function configure(): void + { + $this->setPrimaryKey('id') + ->setShouldAlwaysHideBulkActionsDropdownOptionEnabled(); + } + + public function bulkActions(): array + { + return ['exportBulk' => 'exportBulk']; + } + + public function exportBulk($items) + { + return $items; + } + })->assertDontSee('Bulk Actions'); + } } diff --git a/tests/Views/Columns/LinkColumnTest.php b/tests/Views/Columns/LinkColumnTest.php index 4a204c0ff..d981d7aad 100644 --- a/tests/Views/Columns/LinkColumnTest.php +++ b/tests/Views/Columns/LinkColumnTest.php @@ -44,8 +44,7 @@ public function test_can_render_field_if_title_and_location_callback(): void $this->assertNotEmpty($column); } - /** @test */ - public function can_check_ishtml_from_html_column(): void + public function test_can_check_ishtml_from_html_column(): void { $column = LinkColumn::make('Name', 'name') ->title(fn ($row) => 'Title') @@ -55,8 +54,7 @@ public function can_check_ishtml_from_html_column(): void $this->assertTrue($column->isHtml()); } - /** @test */ - public function can_get_html_from_html_label_column(): void + public function test_can_get_html_from_html_label_column(): void { $column = LinkColumn::make('Name', 'name') ->title(fn ($row) => 'My Label')