diff --git a/.github/workflows/discord-releases.yml b/.github/workflows/discord-releases.yml index c75bedd41..84ea5b888 100644 --- a/.github/workflows/discord-releases.yml +++ b/.github/workflows/discord-releases.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Package Releases uses: SethCohen/github-releases-to-discord@v1.13.1 with: diff --git a/.github/workflows/pint.yml b/.github/workflows/pint.yml index 097689b83..230a58799 100644 --- a/.github/workflows/pint.yml +++ b/.github/workflows/pint.yml @@ -2,6 +2,11 @@ name: Fix PHP code style issues on: push: + branches: + - '*' # matches every branch that doesn't contain a '/' + - '*/*' # matches every branch containing a single '/' + - '**' # matches every branch + - '!master' paths: - '**.php' @@ -14,7 +19,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} diff --git a/.github/workflows/run-phpstan.yml b/.github/workflows/run-phpstan.yml index a94ed2a24..4faf52718 100644 --- a/.github/workflows/run-phpstan.yml +++ b/.github/workflows/run-phpstan.yml @@ -1,6 +1,16 @@ name: run-phpstan -on: [push, pull_request] +on: + pull_request: + branches: + - 'master' + - 'development' + push: + branches: + - '*' # matches every branch that doesn't contain a '/' + - '*/*' # matches every branch containing a single '/' + - '**' # matches every branch + - '!master' jobs: test: @@ -20,7 +30,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup cache environment id: extcache @@ -31,7 +41,7 @@ jobs: key: ${{ env.extensionKey }} - name: Cache extensions - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.extcache.outputs.dir }} key: ${{ steps.extcache.outputs.key }} @@ -55,7 +65,7 @@ jobs: run: | echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-PHPStan-P${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }} diff --git a/.github/workflows/run-tests-pcov-pull.yml b/.github/workflows/run-tests-pcov-pull.yml index 08e7eea08..3a24a91ba 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: @@ -24,7 +25,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup cache environment id: extcache @@ -46,7 +47,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Cache extensions - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.extcache.outputs.dir }} key: ${{ steps.extcache.outputs.key }} @@ -60,7 +61,7 @@ jobs: run: | echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-PCOV-PULL-PHP${{ matrix.php }}-Laravel${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }} diff --git a/.github/workflows/run-tests-pull.yml b/.github/workflows/run-tests-pull.yml index 50c0c38be..38f635f9c 100644 --- a/.github/workflows/run-tests-pull.yml +++ b/.github/workflows/run-tests-pull.yml @@ -4,30 +4,29 @@ on: pull_request: branches: - 'develop' + - 'development' - 'master' jobs: - test: + test-laravel10: runs-on: ${{ matrix.os }} strategy: fail-fast: false + max-parallel: 3 matrix: os: [ubuntu-latest] php: [8.1, 8.2, 8.3] - laravel: [10.*,11.*] + laravel: [10.*] stability: [prefer-dist] - exclude: - - laravel: 11.* - php: 8.1 - name: STD-PULL - ${{ matrix.os }} - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} + name: PULL PHP-${{ matrix.php }} - Laravel-10 env: - extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }} + extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}-L{{ matrix.laravel }} extensions: dom, curl, libxml, mbstring, zip, pcntl, pcov, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, :psr steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup cache environment id: extcache @@ -35,14 +34,14 @@ jobs: with: php-version: ${{ matrix.php }} extensions: ${{ env.extensions }} - key: ${{ runner.os }}-${{ env.extensionKey }} + key: ${{ env.extensionKey }} - name: Cache extensions - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.extcache.outputs.dir }} - key: ${{ steps.extcache.outputs.key }} - restore-keys: ${{ steps.extcache.outputs.key }} + key: ${{ runner.os }}-${{ steps.extcache.outputs.key }} + restore-keys: ${{ runner.os }}-${{ steps.extcache.outputs.key }} - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -63,11 +62,11 @@ jobs: run: | echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-STDPULL-PHP-${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-STDPULL-PHP-${{ matrix.php }}-L${{ matrix.laravel }}-composer- + key: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer- - name: Add token run: | @@ -78,7 +77,90 @@ jobs: run: composer require "laravel/framework:${{ matrix.laravel }}.*" --no-interaction --no-update - name: Update dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' run: composer update --${{ matrix.stability }} --no-interaction + - name: Setup problem matchers for PHPUnit + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: Run Unit Tests + run: php ./vendor/bin/paratest --no-coverage --processes=4 + + + test-laravel11: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + max-parallel: 2 + matrix: + os: [ubuntu-latest] + php: [8.2, 8.3] + laravel: [11.*] + stability: [prefer-dist] + + name: PULL PHP-${{ matrix.php }} - Laravel-11 + env: + extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}-L{{ matrix.laravel }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pcov, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, :psr + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup cache environment + id: extcache + uses: shivammathur/cache-extensions@v1 + with: + php-version: ${{ matrix.php }} + extensions: ${{ env.extensions }} + key: ${{ env.extensionKey }} + + - name: Cache extensions + uses: actions/cache@v4 + with: + path: ${{ steps.extcache.outputs.dir }} + key: ${{ runner.os }}-${{ steps.extcache.outputs.key }} + restore-keys: ${{ runner.os }}-${{ steps.extcache.outputs.key }} + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: ${{ env.extensions }} + tools: phpunit:latest + ini-values: memory_limit=512M + coverage: none + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup problem matchers for PHP + run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + + - name: Get composer cache directory + id: composer-cache + run: | + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer- + + - name: Add token + run: | + composer config github-oauth.github.com ${{ secrets.GITHUB_TOKEN }} + + - name: Install dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer require "laravel/framework:${{ matrix.laravel }}.*" --no-interaction --no-update + + - name: Update dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer update --${{ matrix.stability }} --no-interaction + + - name: Setup problem matchers for PHPUnit + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Run Unit Tests run: php ./vendor/bin/paratest --no-coverage --processes=4 diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index ce258214d..9f6997a6c 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -1,29 +1,33 @@ name: run-tests -on: [push] +on: + push: + branches: + - '*' # matches every branch that doesn't contain a '/' + - '*/*' # matches every branch containing a single '/' + - '**' # matches every branch + - '!master' jobs: - test: + test-laravel10: runs-on: ${{ matrix.os }} strategy: fail-fast: false + max-parallel: 3 matrix: os: [ubuntu-latest] php: [8.1, 8.2, 8.3] - laravel: [10.*,11.*] + laravel: [10.*] stability: [prefer-dist] - exclude: - - laravel: 11.* - php: 8.1 - name: STD-PUSH - ${{ matrix.os }} - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} + name: PHP-${{ matrix.php }} - Laravel-10 env: - extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }} + extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}-L{{ matrix.laravel }} extensions: dom, curl, libxml, mbstring, zip, pcntl, pcov, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, :psr steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup cache environment id: extcache @@ -34,7 +38,7 @@ jobs: key: ${{ env.extensionKey }} - name: Cache extensions - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.extcache.outputs.dir }} key: ${{ runner.os }}-${{ steps.extcache.outputs.key }} @@ -59,7 +63,86 @@ jobs: run: | echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer- + + - name: Add token + run: | + composer config github-oauth.github.com ${{ secrets.GITHUB_TOKEN }} + + - name: Install dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer require "laravel/framework:${{ matrix.laravel }}.*" --no-interaction --no-update + + - name: Update dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer update --${{ matrix.stability }} --no-interaction + + - name: Setup problem matchers for PHPUnit + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: Run Unit Tests + run: php ./vendor/bin/paratest --no-coverage --processes=4 + + + test-laravel11: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + max-parallel: 2 + matrix: + os: [ubuntu-latest] + php: [8.2, 8.3] + laravel: [11.*] + stability: [prefer-dist] + + name: PHP-${{ matrix.php }} - Laravel-11 + env: + extensionKey: phpextensions-${{ matrix.os }}-P${{ matrix.php }}-L{{ matrix.laravel }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pcov, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, :psr + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup cache environment + id: extcache + uses: shivammathur/cache-extensions@v1 + with: + php-version: ${{ matrix.php }} + extensions: ${{ env.extensions }} + key: ${{ env.extensionKey }} + + - name: Cache extensions + uses: actions/cache@v4 + with: + path: ${{ steps.extcache.outputs.dir }} + key: ${{ runner.os }}-${{ steps.extcache.outputs.key }} + restore-keys: ${{ runner.os }}-${{ steps.extcache.outputs.key }} + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: ${{ env.extensions }} + tools: phpunit:latest + ini-values: memory_limit=512M + coverage: none + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup problem matchers for PHP + run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + + - name: Get composer cache directory + id: composer-cache + run: | + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-STDPUSH-PHP${{ matrix.php }}-L${{ matrix.laravel }}-composer-${{ hashFiles('**/composer.json') }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 7060f51c2..6993a50e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to `laravel-livewire-tables` will be documented in this file +## [v3.2.8] - 2024-07-03 +### Bug Fixes +- Fix hide bulk actions when empty not reflecting in frontend by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1747 +- Apply cursor pointer only on clickable columns when using Bootstrap by @MP70 in https://github.com/rappasoft/laravel-livewire-tables/pull/1742 + +### New Features +- Always hide bulk actions option by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1752 +- Add ArrayColumn (BETA) by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1751 +- Optionally disable total item count for simple pagination by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1755 + +### Tweaks +- TypeHint fixes by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1750 +- Change Return Type for attributes() to static by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1749 +- Switch to using Composer\InstalledVersions for AboutCommand by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1748 + ## [v3.2.7] - 2024-06-05 ### Bug Fixes - Ensure HTML Columns return HTML correctly by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1737 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..7ff21a707 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,15 +10,18 @@ parameters: tmpDir: build/phpstan checkOctaneCompatibility: true checkModelProperties: true - checkMissingIterableValueType: false treatPhpDocTypesAsCertain: false reportUnmatchedIgnoredErrors: false - checkGenericClassInNonGenericObjectType: 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.#' + - '#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.#' 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/Commands/MakeCommand.php b/src/Commands/MakeCommand.php index cdaa67130..8338a1216 100644 --- a/src/Commands/MakeCommand.php +++ b/src/Commands/MakeCommand.php @@ -5,6 +5,7 @@ use Illuminate\Console\Command; use Illuminate\Contracts\Console\PromptsForMissingInput; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\File; use Illuminate\Support\Str; use Livewire\Features\SupportConsoleCommands\Commands\ComponentParser; @@ -97,10 +98,7 @@ protected function createClass(bool $force = false): bool return $classPath; } - /** - * @param mixed $path - */ - protected function ensureDirectoryExists($path): void + protected function ensureDirectoryExists(string $path): void { if (! File::isDirectory(dirname($path))) { File::makeDirectory(dirname($path), 0777, true, true); @@ -147,7 +145,7 @@ public function getModelImport(): string /* * Credits to Harm Smits: https://stackoverflow.com/a/67099502/2263114 */ - private function getClassesList($file): array + private function getClassesList(string $file): array { $classes = []; $namespace = ''; @@ -215,7 +213,7 @@ private function generateColumns(string $modelName): string return $columns; } - protected function possibleModels() + protected function possibleModels(): array { $modelPath = is_dir(app_path('Models')) ? app_path('Models') : app_path(); @@ -226,7 +224,7 @@ protected function possibleModels() ->all(); } - protected function promptForMissingArguments(InputInterface $input, OutputInterface $output) + protected function promptForMissingArguments(InputInterface $input, OutputInterface $output): void { if ($this->didReceiveOptions($input)) { diff --git a/src/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/Mechanisms/RappasoftFrontendAssets.php b/src/Mechanisms/RappasoftFrontendAssets.php index 62889d0ff..d460f5431 100644 --- a/src/Mechanisms/RappasoftFrontendAssets.php +++ b/src/Mechanisms/RappasoftFrontendAssets.php @@ -56,7 +56,7 @@ public function boot(): void } - protected function registerBladeDirectives() + protected function registerBladeDirectives(): void { Blade::directive('rappasoftTableScripts', [static::class, 'rappasoftTableScripts']); Blade::directive('rappasoftTableStyles', [static::class, 'rappasoftTableStyles']); diff --git a/src/Traits/Configuration/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/FilterConfiguration.php b/src/Traits/Configuration/FilterConfiguration.php index 9eac5d75f..3367c9168 100644 --- a/src/Traits/Configuration/FilterConfiguration.php +++ b/src/Traits/Configuration/FilterConfiguration.php @@ -121,7 +121,7 @@ public function generateFilterGenericData(): array return (new FilterGenericData($this))->toArray(); } - public function setFilterGenericData(array $filterGenericData = []) + public function setFilterGenericData(array $filterGenericData = []): void { $this->filterGenericData = $filterGenericData; } diff --git a/src/Traits/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/FilterHelpers.php b/src/Traits/Helpers/FilterHelpers.php index 55c824fad..d4c043531 100644 --- a/src/Traits/Helpers/FilterHelpers.php +++ b/src/Traits/Helpers/FilterHelpers.php @@ -312,7 +312,7 @@ public function hasFilterGenericData(): bool return ! empty($this->filterGenericData); } - public function getFilterGenericData() + public function getFilterGenericData(): array { if (! $this->hasFilterGenericData()) { $this->setFilterGenericData($this->generateFilterGenericData()); diff --git a/src/Traits/Helpers/FooterHelpers.php b/src/Traits/Helpers/FooterHelpers.php index 37e8276bd..df220e3c0 100644 --- a/src/Traits/Helpers/FooterHelpers.php +++ b/src/Traits/Helpers/FooterHelpers.php @@ -47,7 +47,7 @@ public function useHeaderAsFooterIsDisabled(): bool */ public function getFooterTrAttributes($rows): array { - return $this->footerTrAttributesCallback ? call_user_func($this->footerTrAttributesCallback, $rows) : ['default' => true]; + return isset($this->footerTrAttributesCallback) ? call_user_func($this->footerTrAttributesCallback, $rows) : ['default' => true]; } /** @@ -56,6 +56,6 @@ public function getFooterTrAttributes($rows): array */ public function getFooterTdAttributes(Column $column, $rows, int $index): array { - return $this->footerTdAttributesCallback ? call_user_func($this->footerTdAttributesCallback, $column, $rows, $index) : ['default' => true]; + return isset($this->footerTdAttributesCallback) ? call_user_func($this->footerTdAttributesCallback, $column, $rows, $index) : ['default' => true]; } } diff --git a/src/Traits/Helpers/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/SecondaryHeaderHelpers.php b/src/Traits/Helpers/SecondaryHeaderHelpers.php index cc7694002..6af852483 100644 --- a/src/Traits/Helpers/SecondaryHeaderHelpers.php +++ b/src/Traits/Helpers/SecondaryHeaderHelpers.php @@ -32,7 +32,7 @@ public function secondaryHeaderIsDisabled(): bool */ public function getSecondaryHeaderTrAttributes($rows): array { - return $this->secondaryHeaderTrAttributesCallback ? call_user_func($this->secondaryHeaderTrAttributesCallback, $rows) : ['default' => true]; + return isset($this->secondaryHeaderTrAttributesCallback) ? call_user_func($this->secondaryHeaderTrAttributesCallback, $rows) : ['default' => true]; } /** @@ -41,6 +41,6 @@ public function getSecondaryHeaderTrAttributes($rows): array */ public function getSecondaryHeaderTdAttributes(Column $column, $rows, int $index): array { - return $this->secondaryHeaderTdAttributesCallback ? call_user_func($this->secondaryHeaderTdAttributesCallback, $column, $rows, $index) : ['default' => true]; + return isset($this->secondaryHeaderTdAttributesCallback) ? call_user_func($this->secondaryHeaderTdAttributesCallback, $column, $rows, $index) : ['default' => true]; } } diff --git a/src/Traits/Helpers/TableAttributeHelpers.php b/src/Traits/Helpers/TableAttributeHelpers.php index 3da2da12e..ffebab51c 100644 --- a/src/Traits/Helpers/TableAttributeHelpers.php +++ b/src/Traits/Helpers/TableAttributeHelpers.php @@ -52,7 +52,7 @@ public function getTbodyAttributes(): array */ public function getThAttributes(Column $column): array { - return $this->thAttributesCallback ? call_user_func($this->thAttributesCallback, $column) : ['default' => true]; + return isset($this->thAttributesCallback) ? call_user_func($this->thAttributesCallback, $column) : ['default' => true]; } /** @@ -60,7 +60,7 @@ public function getThAttributes(Column $column): array */ public function getThSortButtonAttributes(Column $column): array { - return $this->thSortButtonAttributesCallback ? call_user_func($this->thSortButtonAttributesCallback, $column) : ['default' => true]; + return isset($this->thSortButtonAttributesCallback) ? call_user_func($this->thSortButtonAttributesCallback, $column) : ['default' => true]; } /** @@ -68,7 +68,7 @@ public function getThSortButtonAttributes(Column $column): array */ public function getTrAttributes(Model $row, int $index): array { - return $this->trAttributesCallback ? call_user_func($this->trAttributesCallback, $row, $index) : ['default' => true]; + return isset($this->trAttributesCallback) ? call_user_func($this->trAttributesCallback, $row, $index) : ['default' => true]; } /** @@ -76,21 +76,21 @@ public function getTrAttributes(Model $row, int $index): array */ public function getTdAttributes(Column $column, Model $row, int $colIndex, int $rowIndex): array { - return $this->tdAttributesCallback ? call_user_func($this->tdAttributesCallback, $column, $row, $colIndex, $rowIndex) : ['default' => true]; + return isset($this->tdAttributesCallback) ? call_user_func($this->tdAttributesCallback, $column, $row, $colIndex, $rowIndex) : ['default' => true]; } public function hasTableRowUrl(): bool { - return $this->trUrlCallback !== null; + return isset($this->trUrlCallback); } - public function getTableRowUrl($row): ?string + public function getTableRowUrl(int|Model $row): ?string { - return $this->trUrlCallback ? call_user_func($this->trUrlCallback, $row) : null; + return isset($this->trUrlCallback) ? call_user_func($this->trUrlCallback, $row) : null; } - public function getTableRowUrlTarget($row): ?string + public function getTableRowUrlTarget(int|Model $row): ?string { - return $this->trUrlTargetCallback ? call_user_func($this->trUrlTargetCallback, $row) : null; + return isset($this->trUrlTargetCallback) ? call_user_func($this->trUrlTargetCallback, $row) : null; } } diff --git a/src/Traits/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..5e1ca3298 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'); } } @@ -171,7 +175,7 @@ protected function joinRelation(Column $column): Builder return $this->getBuilder(); } - protected function performJoin($table, $foreign, $other, $type = 'left'): Builder + protected function performJoin(string $table, string $foreign, string $other, string $type = 'left'): Builder { $joins = []; diff --git a/src/Traits/WithEvents.php b/src/Traits/WithEvents.php index 448dcc69f..dca549f2a 100644 --- a/src/Traits/WithEvents.php +++ b/src/Traits/WithEvents.php @@ -4,7 +4,7 @@ trait WithEvents { - public function setSortEvent($field, $direction): void + public function setSortEvent(string $field, string $direction): void { $this->setSort($field, $direction); } @@ -14,7 +14,7 @@ public function clearSortEvent(): void $this->clearSorts(); } - public function setFilterEvent($filter, $value): void + public function setFilterEvent(string $filter, string $value): void { $this->setFilter($filter, $value); } diff --git a/src/Traits/WithFilters.php b/src/Traits/WithFilters.php index ec6c7aac2..878c660ce 100644 --- a/src/Traits/WithFilters.php +++ b/src/Traits/WithFilters.php @@ -3,6 +3,7 @@ namespace Rappasoft\LaravelLivewireTables\Traits; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Collection; use Rappasoft\LaravelLivewireTables\Traits\Configuration\FilterConfiguration; use Rappasoft\LaravelLivewireTables\Traits\Helpers\FilterHelpers; @@ -23,7 +24,7 @@ trait WithFilters public int $filterCount; - protected $filterCollection; + protected ?Collection $filterCollection; public array $filterComponents = []; diff --git a/src/Traits/WithFooter.php b/src/Traits/WithFooter.php index 376f2340b..b1035cf29 100644 --- a/src/Traits/WithFooter.php +++ b/src/Traits/WithFooter.php @@ -16,9 +16,9 @@ trait WithFooter protected bool $columnsWithFooter = false; - protected $footerTrAttributesCallback; + protected ?object $footerTrAttributesCallback; - protected $footerTdAttributesCallback; + protected ?object $footerTdAttributesCallback; public function setupFooter(): void { diff --git a/src/Traits/WithPagination.php b/src/Traits/WithPagination.php index 676d034b6..946bed2cb 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); @@ -51,7 +53,7 @@ public function mountWithPagination(): void } // TODO: Test - public function updatedPerPage($value): void + public function updatedPerPage(int|string $value): void { if (! in_array((int) $value, $this->getPerPageAccepted(), false)) { $value = $this->getPerPageAccepted()[0] ?? 10; diff --git a/src/Traits/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/Traits/WithSecondaryHeader.php b/src/Traits/WithSecondaryHeader.php index 94022b5f1..875d0ae03 100644 --- a/src/Traits/WithSecondaryHeader.php +++ b/src/Traits/WithSecondaryHeader.php @@ -14,9 +14,9 @@ trait WithSecondaryHeader protected bool $columnsWithSecondaryHeader = false; - protected $secondaryHeaderTrAttributesCallback; + protected ?object $secondaryHeaderTrAttributesCallback; - protected $secondaryHeaderTdAttributesCallback; + protected ?object $secondaryHeaderTdAttributesCallback; public function bootedWithSecondaryHeader(): void { diff --git a/src/Traits/WithTableAttributes.php b/src/Traits/WithTableAttributes.php index f75f75f9e..b58c6baf0 100644 --- a/src/Traits/WithTableAttributes.php +++ b/src/Traits/WithTableAttributes.php @@ -21,15 +21,15 @@ trait WithTableAttributes protected array $tbodyAttributes = []; - protected $thAttributesCallback; + protected ?object $thAttributesCallback; - protected $thSortButtonAttributesCallback; + protected ?object $thSortButtonAttributesCallback; - protected $trAttributesCallback; + protected ?object $trAttributesCallback; - protected $tdAttributesCallback; + protected ?object $tdAttributesCallback; - protected $trUrlCallback; + protected ?object $trUrlCallback; - protected $trUrlTargetCallback; + protected ?object $trUrlTargetCallback; } diff --git a/src/Traits/WithTableHooks.php b/src/Traits/WithTableHooks.php index 160713e56..eb0f18fd8 100644 --- a/src/Traits/WithTableHooks.php +++ b/src/Traits/WithTableHooks.php @@ -6,14 +6,14 @@ trait WithTableHooks { - public function callHook($name, $params = []) + public function callHook(string $name, array $params = []): void { if (method_exists($this, $name)) { wrap($this)->__call($name, $params); } } - public function callTraitHook($name, $params = []) + public function callTraitHook(string $name, array $params = []): void { foreach (class_uses_recursive($this) as $trait) { $method = $name.class_basename($trait); diff --git a/src/Views/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/Filters/MultiSelectDropdownFilter.php b/src/Views/Filters/MultiSelectDropdownFilter.php index ae784b58c..3022ddba5 100644 --- a/src/Views/Filters/MultiSelectDropdownFilter.php +++ b/src/Views/Filters/MultiSelectDropdownFilter.php @@ -2,6 +2,7 @@ namespace Rappasoft\LaravelLivewireTables\Views\Filters; +use Illuminate\Support\Collection; use Rappasoft\LaravelLivewireTables\Views\Filter; use Rappasoft\LaravelLivewireTables\Views\Traits\Core\HasWireables; use Rappasoft\LaravelLivewireTables\Views\Traits\Filters\{HasOptions,IsArrayFilter}; @@ -42,7 +43,7 @@ public function getFilterPillValue($value): ?string foreach ($value as $item) { $found = $this->getCustomFilterPillValue($item) - ?? collect($this->getOptions()) + ?? (new Collection($this->getOptions())) ->mapWithKeys(fn ($options, $optgroupLabel) => is_iterable($options) ? $options : [$optgroupLabel => $options])[$item] ?? null; @@ -54,7 +55,7 @@ public function getFilterPillValue($value): ?string return implode(', ', $values); } - public function isEmpty($value): bool + public function isEmpty(mixed $value): bool { if (! is_array($value)) { return true; diff --git a/src/Views/Filters/SelectFilter.php b/src/Views/Filters/SelectFilter.php index a62260dd9..0f247ada4 100644 --- a/src/Views/Filters/SelectFilter.php +++ b/src/Views/Filters/SelectFilter.php @@ -2,6 +2,7 @@ namespace Rappasoft\LaravelLivewireTables\Views\Filters; +use Illuminate\Support\Collection; use Rappasoft\LaravelLivewireTables\Views\Filter; use Rappasoft\LaravelLivewireTables\Views\Traits\Core\HasWireables; use Rappasoft\LaravelLivewireTables\Views\Traits\Filters\{HasOptions,IsStringFilter}; @@ -22,8 +23,8 @@ class SelectFilter extends Filter public function getKeys(): array { - return collect($this->getOptions()) - ->map(fn ($value, $key) => is_iterable($value) ? collect($value)->keys() : $key) + return (new Collection($this->getOptions())) + ->map(fn ($value, $key) => is_iterable($value) ? (new Collection($value))->keys() : $key) ->flatten() ->map(fn ($value) => (string) $value) ->filter(fn ($value) => strlen($value) > 0) @@ -42,8 +43,9 @@ public function validate(string $value): array|string|bool public function getFilterPillValue($value): ?string { + return $this->getCustomFilterPillValue($value) - ?? collect($this->getOptions()) + ?? (new Collection($this->getOptions())) ->mapWithKeys(fn ($options, $optgroupLabel) => is_iterable($options) ? $options : [$optgroupLabel => $options])[$value] ?? null; } diff --git a/src/Views/Traits/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/ColorColumnHelpers.php b/src/Views/Traits/Helpers/ColorColumnHelpers.php index 00f017e9e..d437243e7 100644 --- a/src/Views/Traits/Helpers/ColorColumnHelpers.php +++ b/src/Views/Traits/Helpers/ColorColumnHelpers.php @@ -2,12 +2,13 @@ namespace Rappasoft\LaravelLivewireTables\Views\Traits\Helpers; +use Illuminate\Database\Eloquent\Model; use Illuminate\View\ComponentAttributeBag; trait ColorColumnHelpers { // TODO: Test - public function getColor($row): string + public function getColor(Model|int $row): string { return $this->hasColorCallback() ? app()->call($this->getColorCallback(), ['row' => $row]) : ($this->getValue($row)); } diff --git a/src/Views/Traits/Helpers/ColumnHelpers.php b/src/Views/Traits/Helpers/ColumnHelpers.php index a43d21681..fb2fbfb38 100644 --- a/src/Views/Traits/Helpers/ColumnHelpers.php +++ b/src/Views/Traits/Helpers/ColumnHelpers.php @@ -131,7 +131,7 @@ public function getContents(Model $row): null|string|\BackedEnum|HtmlString|Data } // TODO: Test - public function getValue(Model $row) + public function getValue(Model $row): mixed { if ($this->isBaseColumn()) { return $row->{$this->getField()}; 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')