From 1f076af0d2a1383583dc4567c4bfc3a76c5268b0 Mon Sep 17 00:00:00 2001 From: Joe <104938042+lrljoe@users.noreply.github.com> Date: Sun, 1 Sep 2024 17:18:22 +0100 Subject: [PATCH] Add hide table option (#1914) * Initial Commit * Fix styling * Further adjustments * Fix styling * Improve Tests - Extend PetsTable * Fix styling --------- Co-authored-by: lrljoe --- docs/misc/hiding-the-table.md | 78 ++++++++++ resources/js/laravel-livewire-tables.js | 16 ++ resources/js/laravel-livewire-tables.min.js | 2 +- resources/views/datatable.blade.php | 2 +- src/Traits/ComponentUtilities.php | 8 +- .../TableAttributeConfiguration.php | 15 ++ src/Traits/Helpers/ComponentHelpers.php | 2 +- src/Traits/Helpers/TableAttributeHelpers.php | 6 + src/Traits/WithTableAttributes.php | 3 + tests/Http/Livewire/PetsTable.php | 1 + tests/Http/Livewire/PetsTableAttributes.php | 139 +----------------- tests/Http/Livewire/PetsTableEvents.php | 25 ++++ .../Livewire/PetsTableLoadingPlaceholder.php | 139 +----------------- tests/Http/Livewire/PetsTableNoFilters.php | 15 +- tests/TestCase.php | 17 ++- tests/Traits/Visuals/ComponentVisualsTest.php | 6 +- tests/Traits/Visuals/HideableTableTest.php | 69 +++++++++ 17 files changed, 250 insertions(+), 293 deletions(-) create mode 100644 docs/misc/hiding-the-table.md create mode 100644 tests/Http/Livewire/PetsTableEvents.php create mode 100644 tests/Traits/Visuals/HideableTableTest.php diff --git a/docs/misc/hiding-the-table.md b/docs/misc/hiding-the-table.md new file mode 100644 index 000000000..b607ff52b --- /dev/null +++ b/docs/misc/hiding-the-table.md @@ -0,0 +1,78 @@ +--- +title: Hiding The Table (beta) +weight: 8 +--- + +You may wish to hide the table on load. To do so, you should use the following in the mount method. Note that this is in mount, not boot nor configure! + +```php + public function mount() + { + $this->setShouldBeHidden(); + } +``` + +### Using Events To Display/Hide + +For example, you may have a "Sales" table that you wish to hide by default: +```php +class SalesTable extends DataTableComponent +{ + public string $tableName = 'sales'; // Required to keep the call specific + + public function mount() + { + $this->setShouldBeHidden(); // Defaults the table to be hidden, note that this is in MOUNT and not CONFIGURE + } + + // Configure/Columns/Filters etc +} +``` + +The Table allows for different approaches, out-of-the-box it supports the more efficient client-side listeners. + +However - should you wish to use Livewire listeners in your table component, for example if you wish to pass more detail into the Table then you can: + +```php + #[On('showTable.{tableName}')] + public function showTable(): void + { + $this->setShouldBeDisplayed(); + } + + #[On('hideTable.{tableName}')] + public function hideTable(): void + { + $this->setShouldBeHidden(); + } +``` + + +### Secondary Table +Below are the two approaches. Note that you can customise the Livewire "On" to pass additional details should you wish. + +#### Using Client Side Listeners +```php + Column::make('Show') + ->label( + fn($row, Column $column) => "" + )->html(), + Column::make('Hide') + ->label( + fn($row, Column $column) => "" + )->html(), +``` + + +#### Using Livewire "On" Style Listeners: +```php + Column::make('Show') + ->label( + fn($row, Column $column) => "" + )->html(), + Column::make('Hide') + ->label( + fn($row, Column $column) => "" + )->html(), + +``` \ No newline at end of file diff --git a/resources/js/laravel-livewire-tables.js b/resources/js/laravel-livewire-tables.js index 306c3857d..2c214e492 100644 --- a/resources/js/laravel-livewire-tables.js +++ b/resources/js/laravel-livewire-tables.js @@ -3,6 +3,9 @@ document.addEventListener('alpine:init', () => { Alpine.data('laravellivewiretable', (wire, showBulkActionsAlpine, tableID, primaryKeyName) => ({ + shouldBeDisplayed: wire.entangle('shouldBeDisplayed'), + tableName: wire.entangle('tableName'), + dataTableFingerprint: wire.entangle('dataTableFingerprint'), listeners: [], childElementOpen: false, filtersOpen: wire.entangle('filterSlideDownDefaultVisible'), @@ -207,6 +210,18 @@ document.addEventListener('alpine:init', () => { } this.selectedItems = [...new Set(tempSelectedItems)]; }, + showTable(eventTableName = '', eventTableFingerpint = '') + { + if ((eventTableName != '' && eventTableName === this.tableName) || (eventTableFingerprint != '' && eventTableFingerpint === this.dataTableFingerprint)) { + this.shouldBeDisplayed = true; + } + }, + hideTable(eventTableName = '', eventTableFingerpint = '') + { + if ((eventTableName != '' && eventTableName === this.tableName) || (eventTableFingerprint != '' && eventTableFingerpint === this.dataTableFingerprint)) { + this.shouldBeDisplayed = false; + } + }, destroy() { this.listeners.forEach((listener) => { listener(); @@ -373,6 +388,7 @@ document.addEventListener('alpine:init', () => { Alpine.data('tableWrapper', (wire, showBulkActionsAlpine) => ({ + shouldBeDisplayed: wire.entangle('shouldBeDisplayed'), listeners: [], childElementOpen: false, filtersOpen: wire.entangle('filterSlideDownDefaultVisible'), diff --git a/resources/js/laravel-livewire-tables.min.js b/resources/js/laravel-livewire-tables.min.js index 35cecdd4f..5ab2c9730 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("laravellivewiretable",(e,t,l,i)=>({listeners:[],childElementOpen:!1,filtersOpen:e.entangle("filterSlideDownDefaultVisible"),paginationCurrentCount:e.entangle("paginationCurrentCount"),paginationTotalItemCount:e.entangle("paginationTotalItemCount"),paginationCurrentItems:e.entangle("paginationCurrentItems"),selectedItems:e.entangle("selected"),selectAllStatus:e.entangle("selectAll"),delaySelectAll:e.entangle("delaySelectAll"),hideBulkActionsWhenEmpty:e.entangle("hideBulkActionsWhenEmpty"),dragging:!1,reorderEnabled:!1,sourceID:"",targetID:"",evenRowClasses:"",oddRowClasses:"",currentlyHighlightedElement:"",evenRowClassArray:{},oddRowClassArray:{},evenNotInOdd:{},oddNotInEven:{},orderedRows:[],defaultReorderColumn:e.get("defaultReorderColumn"),reorderStatus:e.entangle("reorderStatus"),currentlyReorderingStatus:e.entangle("currentlyReorderingStatus"),hideReorderColumnUnlessReorderingStatus:e.entangle("hideReorderColumnUnlessReorderingStatus"),reorderDisplayColumn:e.entangle("reorderDisplayColumn"),dragStart(e){this.$nextTick(()=>{this.setupEvenOddClasses()}),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.offsetYt.getBoundingClientRect().height/2?i.insertBefore(s,t.nextSibling):i.insertBefore(s,t),r{this.setupEvenOddClasses()})},cancelReorder(){this.hideReorderColumnUnlessReorderingStatus&&(this.reorderDisplayColumn=!1),e.disableReordering()},updateOrderedItems(){let t=document.getElementById(l),s=[];for(let a=1,r;r=t.rows[a];a++)s.push({[i]:r.getAttribute("rowpk"),[this.defaultReorderColumn]:a});e.storeReorder(s)},setupEvenOddClasses(){if(void 0===this.evenNotInOdd.length||0==this.evenNotInOdd.length||void 0===this.oddNotInEven.length||0==this.oddNotInEven.length){let e=document.getElementById(l).getElementsByTagName("tbody")[0],t=[],i=[];void 0!==e.rows[0]&&void 0!==e.rows[1]&&(t=Array.from(e.rows[0].classList),i=Array.from(e.rows[1].classList),this.evenNotInOdd=t.filter(e=>!i.includes(e)),this.oddNotInEven=i.filter(e=>!t.includes(e)),t=[],i=[])}},toggleSelectAll(){t&&(this.paginationTotalItemCount===this.selectedItems.length?(this.clearSelected(),this.selectAllStatus=!1):this.delaySelectAll?this.setAllItemsSelected():this.setAllSelected())},setAllItemsSelected(){t&&(this.selectAllStatus=!0,this.selectAllOnPage())},setAllSelected(){t&&(this.delaySelectAll?(this.selectAllStatus=!0,this.selectAllOnPage()):e.setAllSelected())},clearSelected(){t&&(this.selectAllStatus=!1,e.clearSelected())},selectAllOnPage(){if(!t)return;let e=this.selectedItems,l=this.paginationCurrentItems.values();for(let i of l)e.push(i.toString());this.selectedItems=[...new Set(e)]},destroy(){this.listeners.forEach(e=>{e()})}})),Alpine.data("booleanFilter",(e,t,l,i)=>({switchOn:!1,value:e.entangle("filterComponents."+t).live,init(){this.switchOn=!1,void 0!==this.value&&(this.switchOn=Boolean(Number(this.value))),this.listeners.push(Livewire.on("filter-was-set",e=>{e.tableName==l&&e.filterKey==t&&(this.switchOn=e.value??i)}))}})),Alpine.data("numberRangeFilter",(e,t,l,i,s)=>({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:i.minRange,defaultMax:i.maxRange,restrictUpdates:!1,initialiseStyles(){let e=document.getElementById(l);e.style.setProperty("--value-a",this.wireValues.min??this.filterMin),e.style.setProperty("--text-value-a",JSON.stringify(this.wireValues.min??this.filterMin)),e.style.setProperty("--value-b",this.wireValues.max??this.filterMax),e.style.setProperty("--text-value-b",JSON.stringify(this.wireValues.max??this.filterMax))},updateStyles(e,t){let i=document.getElementById(l);i.style.setProperty("--value-a",e),i.style.setProperty("--text-value-a",JSON.stringify(e)),i.style.setProperty("--value-b",t),i.style.setProperty("--text-value-b",JSON.stringify(t))},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(this.filterMin,this.filterMax)},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,l,i,s)=>({wireValues:e.entangle("filterComponents."+t),flatpickrInstance:flatpickr(i,{mode:"range",altFormat:l.altFormat??"F j, Y",altInput:l.altInput??!1,allowInput:l.allowInput??!1,allowInvalidPreload:l.allowInvalidPreload??!0,ariaDateFormat:l.ariaDateFormat??"F j, Y",clickOpens:!0,dateFormat:l.dateFormat??"Y-m-d",defaultDate:l.defaultDate??null,defaultHour:l.defaultHour??12,defaultMinute:l.defaultMinute??0,enableTime:l.enableTime??!1,enableSeconds:l.enableSeconds??!1,hourIncrement:l.hourIncrement??1,locale:l.locale??"en",minDate:l.earliestDate??null,maxDate:l.latestDate??null,minuteIncrement:l.minuteIncrement??5,shorthandCurrentMonth:l.shorthandCurrentMonth??!1,time_24hr:l.time_24hr??!1,weekNumbers:l.weekNumbers??!1,onOpen:function(){window.childElementOpen=!0},onChange:function(l,i,s){if(l.length>1){var a=i.split(" "),r={};window.childElementOpen=!1,window.filterPopoverOpen=!1,r={minDate:a[0],maxDate:void 0===a[2]?a[0]:a[2]},e.set("filterComponents."+t,r)}}}),changedValue:function(l){l.length<5&&(this.flatpickrInstance.setDate([]),e.set("filterComponents."+t,{}))},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("tableWrapper",(e,t)=>({listeners:[],childElementOpen:!1,filtersOpen:e.entangle("filterSlideDownDefaultVisible"),paginationCurrentCount:e.entangle("paginationCurrentCount"),paginationTotalItemCount:e.entangle("paginationTotalItemCount"),paginationCurrentItems:e.entangle("paginationCurrentItems"),selectedItems:e.entangle("selected"),selectAllStatus:e.entangle("selectAll"),delaySelectAll:e.entangle("delaySelectAll"),hideBulkActionsWhenEmpty:e.entangle("hideBulkActionsWhenEmpty"),toggleSelectAll(){t&&(this.paginationTotalItemCount===this.selectedItems.length?(this.clearSelected(),this.selectAllStatus=!1):this.delaySelectAll?this.setAllItemsSelected():this.setAllSelected())},setAllItemsSelected(){t&&(this.selectAllStatus=!0,this.selectAllOnPage())},setAllSelected(){t&&(this.delaySelectAll?(this.selectAllStatus=!0,this.selectAllOnPage()):e.setAllSelected())},clearSelected(){t&&(this.selectAllStatus=!1,e.clearSelected())},selectAllOnPage(){if(!t)return;let e=this.selectedItems,l=this.paginationCurrentItems.values();for(let i of l)e.push(i.toString());this.selectedItems=[...new Set(e)]},destroy(){this.listeners.forEach(e=>{e()})}})),Alpine.data("reorderFunction",(e,t,l)=>({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.$nextTick(()=>{this.setupEvenOddClasses()}),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.offsetYl.getBoundingClientRect().height/2?i.insertBefore(s,l.nextSibling):i.insertBefore(s,l),r{this.setupEvenOddClasses()}),this.currentlyReorderingStatus?e.disableReordering():(this.setupEvenOddClasses(),this.hideReorderColumnUnlessReorderingStatus&&(this.reorderDisplayColumn=!0),e.enableReordering())},cancelReorder(){this.hideReorderColumnUnlessReorderingStatus&&(this.reorderDisplayColumn=!1),e.disableReordering()},updateOrderedItems(){let i=document.getElementById(t),s=[];for(let a=1,r;r=i.rows[a];a++)s.push({[l]:r.getAttribute("rowpk"),[this.defaultReorderColumn]:a});e.storeReorder(s)},setupEvenOddClasses(){if(void 0===this.evenNotInOdd.length||0==this.evenNotInOdd.length||void 0===this.oddNotInEven.length||0==this.oddNotInEven.length){let e=document.getElementById(t).getElementsByTagName("tbody")[0],l=[],i=[];void 0!==e.rows[0]&&void 0!==e.rows[1]&&(l=Array.from(e.rows[0].classList),i=Array.from(e.rows[1].classList),this.evenNotInOdd=l.filter(e=>!i.includes(e)),this.oddNotInEven=i.filter(e=>!l.includes(e)),l=[],i=[])}},init(){}}))}); \ No newline at end of file +document.addEventListener("alpine:init",()=>{Alpine.data("laravellivewiretable",(e,t,l,i)=>({shouldBeDisplayed:e.entangle("shouldBeDisplayed"),tableName:e.entangle("tableName"),dataTableFingerprint:e.entangle("dataTableFingerprint"),listeners:[],childElementOpen:!1,filtersOpen:e.entangle("filterSlideDownDefaultVisible"),paginationCurrentCount:e.entangle("paginationCurrentCount"),paginationTotalItemCount:e.entangle("paginationTotalItemCount"),paginationCurrentItems:e.entangle("paginationCurrentItems"),selectedItems:e.entangle("selected"),selectAllStatus:e.entangle("selectAll"),delaySelectAll:e.entangle("delaySelectAll"),hideBulkActionsWhenEmpty:e.entangle("hideBulkActionsWhenEmpty"),dragging:!1,reorderEnabled:!1,sourceID:"",targetID:"",evenRowClasses:"",oddRowClasses:"",currentlyHighlightedElement:"",evenRowClassArray:{},oddRowClassArray:{},evenNotInOdd:{},oddNotInEven:{},orderedRows:[],defaultReorderColumn:e.get("defaultReorderColumn"),reorderStatus:e.entangle("reorderStatus"),currentlyReorderingStatus:e.entangle("currentlyReorderingStatus"),hideReorderColumnUnlessReorderingStatus:e.entangle("hideReorderColumnUnlessReorderingStatus"),reorderDisplayColumn:e.entangle("reorderDisplayColumn"),dragStart(e){this.$nextTick(()=>{this.setupEvenOddClasses()}),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.offsetYt.getBoundingClientRect().height/2?i.insertBefore(s,t.nextSibling):i.insertBefore(s,t),r{this.setupEvenOddClasses()})},cancelReorder(){this.hideReorderColumnUnlessReorderingStatus&&(this.reorderDisplayColumn=!1),e.disableReordering()},updateOrderedItems(){let t=document.getElementById(l),s=[];for(let a=1,r;r=t.rows[a];a++)s.push({[i]:r.getAttribute("rowpk"),[this.defaultReorderColumn]:a});e.storeReorder(s)},setupEvenOddClasses(){if(void 0===this.evenNotInOdd.length||0==this.evenNotInOdd.length||void 0===this.oddNotInEven.length||0==this.oddNotInEven.length){let e=document.getElementById(l).getElementsByTagName("tbody")[0],t=[],i=[];void 0!==e.rows[0]&&void 0!==e.rows[1]&&(t=Array.from(e.rows[0].classList),i=Array.from(e.rows[1].classList),this.evenNotInOdd=t.filter(e=>!i.includes(e)),this.oddNotInEven=i.filter(e=>!t.includes(e)),t=[],i=[])}},toggleSelectAll(){t&&(this.paginationTotalItemCount===this.selectedItems.length?(this.clearSelected(),this.selectAllStatus=!1):this.delaySelectAll?this.setAllItemsSelected():this.setAllSelected())},setAllItemsSelected(){t&&(this.selectAllStatus=!0,this.selectAllOnPage())},setAllSelected(){t&&(this.delaySelectAll?(this.selectAllStatus=!0,this.selectAllOnPage()):e.setAllSelected())},clearSelected(){t&&(this.selectAllStatus=!1,e.clearSelected())},selectAllOnPage(){if(!t)return;let e=this.selectedItems,l=this.paginationCurrentItems.values();for(let i of l)e.push(i.toString());this.selectedItems=[...new Set(e)]},showTable(e="",t=""){(""!=e&&e===this.tableName||""!=eventTableFingerprint&&t===this.dataTableFingerprint)&&(this.shouldBeDisplayed=!0)},hideTable(e="",t=""){(""!=e&&e===this.tableName||""!=eventTableFingerprint&&t===this.dataTableFingerprint)&&(this.shouldBeDisplayed=!1)},destroy(){this.listeners.forEach(e=>{e()})}})),Alpine.data("booleanFilter",(e,t,l,i)=>({switchOn:!1,value:e.entangle("filterComponents."+t).live,init(){this.switchOn=!1,void 0!==this.value&&(this.switchOn=Boolean(Number(this.value))),this.listeners.push(Livewire.on("filter-was-set",e=>{e.tableName==l&&e.filterKey==t&&(this.switchOn=e.value??i)}))}})),Alpine.data("numberRangeFilter",(e,t,l,i,s)=>({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:i.minRange,defaultMax:i.maxRange,restrictUpdates:!1,initialiseStyles(){let e=document.getElementById(l);e.style.setProperty("--value-a",this.wireValues.min??this.filterMin),e.style.setProperty("--text-value-a",JSON.stringify(this.wireValues.min??this.filterMin)),e.style.setProperty("--value-b",this.wireValues.max??this.filterMax),e.style.setProperty("--text-value-b",JSON.stringify(this.wireValues.max??this.filterMax))},updateStyles(e,t){let i=document.getElementById(l);i.style.setProperty("--value-a",e),i.style.setProperty("--text-value-a",JSON.stringify(e)),i.style.setProperty("--value-b",t),i.style.setProperty("--text-value-b",JSON.stringify(t))},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(this.filterMin,this.filterMax)},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,l,i,s)=>({wireValues:e.entangle("filterComponents."+t),flatpickrInstance:flatpickr(i,{mode:"range",altFormat:l.altFormat??"F j, Y",altInput:l.altInput??!1,allowInput:l.allowInput??!1,allowInvalidPreload:l.allowInvalidPreload??!0,ariaDateFormat:l.ariaDateFormat??"F j, Y",clickOpens:!0,dateFormat:l.dateFormat??"Y-m-d",defaultDate:l.defaultDate??null,defaultHour:l.defaultHour??12,defaultMinute:l.defaultMinute??0,enableTime:l.enableTime??!1,enableSeconds:l.enableSeconds??!1,hourIncrement:l.hourIncrement??1,locale:l.locale??"en",minDate:l.earliestDate??null,maxDate:l.latestDate??null,minuteIncrement:l.minuteIncrement??5,shorthandCurrentMonth:l.shorthandCurrentMonth??!1,time_24hr:l.time_24hr??!1,weekNumbers:l.weekNumbers??!1,onOpen:function(){window.childElementOpen=!0},onChange:function(l,i,s){if(l.length>1){var a=i.split(" "),r={};window.childElementOpen=!1,window.filterPopoverOpen=!1,r={minDate:a[0],maxDate:void 0===a[2]?a[0]:a[2]},e.set("filterComponents."+t,r)}}}),changedValue:function(l){l.length<5&&(this.flatpickrInstance.setDate([]),e.set("filterComponents."+t,{}))},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("tableWrapper",(e,t)=>({shouldBeDisplayed:e.entangle("shouldBeDisplayed"),listeners:[],childElementOpen:!1,filtersOpen:e.entangle("filterSlideDownDefaultVisible"),paginationCurrentCount:e.entangle("paginationCurrentCount"),paginationTotalItemCount:e.entangle("paginationTotalItemCount"),paginationCurrentItems:e.entangle("paginationCurrentItems"),selectedItems:e.entangle("selected"),selectAllStatus:e.entangle("selectAll"),delaySelectAll:e.entangle("delaySelectAll"),hideBulkActionsWhenEmpty:e.entangle("hideBulkActionsWhenEmpty"),toggleSelectAll(){t&&(this.paginationTotalItemCount===this.selectedItems.length?(this.clearSelected(),this.selectAllStatus=!1):this.delaySelectAll?this.setAllItemsSelected():this.setAllSelected())},setAllItemsSelected(){t&&(this.selectAllStatus=!0,this.selectAllOnPage())},setAllSelected(){t&&(this.delaySelectAll?(this.selectAllStatus=!0,this.selectAllOnPage()):e.setAllSelected())},clearSelected(){t&&(this.selectAllStatus=!1,e.clearSelected())},selectAllOnPage(){if(!t)return;let e=this.selectedItems,l=this.paginationCurrentItems.values();for(let i of l)e.push(i.toString());this.selectedItems=[...new Set(e)]},destroy(){this.listeners.forEach(e=>{e()})}})),Alpine.data("reorderFunction",(e,t,l)=>({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.$nextTick(()=>{this.setupEvenOddClasses()}),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.offsetYl.getBoundingClientRect().height/2?i.insertBefore(s,l.nextSibling):i.insertBefore(s,l),r{this.setupEvenOddClasses()}),this.currentlyReorderingStatus?e.disableReordering():(this.setupEvenOddClasses(),this.hideReorderColumnUnlessReorderingStatus&&(this.reorderDisplayColumn=!0),e.enableReordering())},cancelReorder(){this.hideReorderColumnUnlessReorderingStatus&&(this.reorderDisplayColumn=!1),e.disableReordering()},updateOrderedItems(){let i=document.getElementById(t),s=[];for(let a=1,r;r=i.rows[a];a++)s.push({[l]:r.getAttribute("rowpk"),[this.defaultReorderColumn]:a});e.storeReorder(s)},setupEvenOddClasses(){if(void 0===this.evenNotInOdd.length||0==this.evenNotInOdd.length||void 0===this.oddNotInEven.length||0==this.oddNotInEven.length){let e=document.getElementById(t).getElementsByTagName("tbody")[0],l=[],i=[];void 0!==e.rows[0]&&void 0!==e.rows[1]&&(l=Array.from(e.rows[0].classList),i=Array.from(e.rows[1].classList),this.evenNotInOdd=l.filter(e=>!i.includes(e)),this.oddNotInEven=i.filter(e=>!l.includes(e)),l=[],i=[])}},init(){}}))}); \ No newline at end of file diff --git a/resources/views/datatable.blade.php b/resources/views/datatable.blade.php index 6cf84f2ce..d8105236a 100644 --- a/resources/views/datatable.blade.php +++ b/resources/views/datatable.blade.php @@ -6,7 +6,7 @@ @php($isBootstrap4 = $this->isBootstrap4) @php($isBootstrap5 = $this->isBootstrap5) -
+
@if($this->hasActions && !$this->showActionsInToolbar) diff --git a/src/Traits/ComponentUtilities.php b/src/Traits/ComponentUtilities.php index d065b25ed..fc1b20153 100644 --- a/src/Traits/ComponentUtilities.php +++ b/src/Traits/ComponentUtilities.php @@ -4,6 +4,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Str; +use Livewire\Attributes\Locked; use Rappasoft\LaravelLivewireTables\Exceptions\DataTableConfigurationException; use Rappasoft\LaravelLivewireTables\Traits\Configuration\ComponentConfiguration; use Rappasoft\LaravelLivewireTables\Traits\Helpers\ComponentHelpers; @@ -27,7 +28,8 @@ trait ComponentUtilities protected string $tableName = 'table'; - protected ?string $dataTableFingerprint; + #[Locked] + public ?string $dataTableFingerprint; protected bool $offlineIndicatorStatus = true; @@ -61,6 +63,8 @@ public function mountComponentUtilities(): void if (is_null($this->theme)) { $this->setTheme(); } + $this->generateDataTableFingerprint(); + } /** @@ -81,7 +85,7 @@ public function bootedComponentUtilities(): void // Make sure a primary key is set if (! $this->hasPrimaryKey()) { - throw new DataTableConfigurationException('You must set a primary key using setPrimaryKey in the configure method.'); + throw new DataTableConfigurationException('You must set a primary key using setPrimaryKey in the configure method, or configuring/configured lifecycle hooks'); } } diff --git a/src/Traits/Configuration/TableAttributeConfiguration.php b/src/Traits/Configuration/TableAttributeConfiguration.php index 01cf7376d..c1bb681e9 100644 --- a/src/Traits/Configuration/TableAttributeConfiguration.php +++ b/src/Traits/Configuration/TableAttributeConfiguration.php @@ -118,4 +118,19 @@ public function setTableRowUrlTarget(\Closure $callback): self return $this; } + + public function setShouldBeDisplayedStatus(bool $status): void + { + $this->shouldBeDisplayed = $status; + } + + public function setShouldBeDisplayed(): void + { + $this->setShouldBeDisplayedStatus(true); + } + + public function setShouldBeHidden(): void + { + $this->setShouldBeDisplayedStatus(false); + } } diff --git a/src/Traits/Helpers/ComponentHelpers.php b/src/Traits/Helpers/ComponentHelpers.php index 828df37a5..0480f39e4 100644 --- a/src/Traits/Helpers/ComponentHelpers.php +++ b/src/Traits/Helpers/ComponentHelpers.php @@ -9,7 +9,7 @@ trait ComponentHelpers { public function getDataTableFingerprint(): string { - return $this->dataTableFingerprint ?? $this->generateDataTableFingerprint(); + return $this->dataTableFingerprint ?? ($this->dataTableFingerprint = $this->generateDataTableFingerprint()); } public function setBuilder(Builder $builder): void diff --git a/src/Traits/Helpers/TableAttributeHelpers.php b/src/Traits/Helpers/TableAttributeHelpers.php index 842c20886..d5f57f03e 100644 --- a/src/Traits/Helpers/TableAttributeHelpers.php +++ b/src/Traits/Helpers/TableAttributeHelpers.php @@ -76,4 +76,10 @@ public function getTableRowUrlTarget(int|Model $row): ?string { return isset($this->trUrlTargetCallback) ? call_user_func($this->trUrlTargetCallback, $row) : null; } + + #[Computed] + public function getShouldBeDisplayed(): bool + { + return $this->shouldBeDisplayed; + } } diff --git a/src/Traits/WithTableAttributes.php b/src/Traits/WithTableAttributes.php index 0ec1884c1..f87edea61 100644 --- a/src/Traits/WithTableAttributes.php +++ b/src/Traits/WithTableAttributes.php @@ -3,6 +3,7 @@ namespace Rappasoft\LaravelLivewireTables\Traits; use Closure; +use Livewire\Attributes\On; use Rappasoft\LaravelLivewireTables\Traits\Configuration\TableAttributeConfiguration; use Rappasoft\LaravelLivewireTables\Traits\Helpers\TableAttributeHelpers; @@ -32,4 +33,6 @@ trait WithTableAttributes protected ?\Closure $trUrlCallback; protected ?\Closure $trUrlTargetCallback; + + public bool $shouldBeDisplayed = true; } diff --git a/tests/Http/Livewire/PetsTable.php b/tests/Http/Livewire/PetsTable.php index 28cc1782c..59b52049d 100644 --- a/tests/Http/Livewire/PetsTable.php +++ b/tests/Http/Livewire/PetsTable.php @@ -3,6 +3,7 @@ namespace Rappasoft\LaravelLivewireTables\Tests\Http\Livewire; use Illuminate\Database\Eloquent\Builder; +use Livewire\Attributes\On; use Rappasoft\LaravelLivewireTables\DataTableComponent; use Rappasoft\LaravelLivewireTables\Tests\Models\Breed; use Rappasoft\LaravelLivewireTables\Tests\Models\Pet; diff --git a/tests/Http/Livewire/PetsTableAttributes.php b/tests/Http/Livewire/PetsTableAttributes.php index 53f79646f..690faf813 100644 --- a/tests/Http/Livewire/PetsTableAttributes.php +++ b/tests/Http/Livewire/PetsTableAttributes.php @@ -2,26 +2,8 @@ namespace Rappasoft\LaravelLivewireTables\Tests\Http\Livewire; -use Illuminate\Database\Eloquent\Builder; -use Rappasoft\LaravelLivewireTables\DataTableComponent; -use Rappasoft\LaravelLivewireTables\Tests\Models\Breed; -use Rappasoft\LaravelLivewireTables\Tests\Models\Pet; -use Rappasoft\LaravelLivewireTables\Tests\Models\Species; -use Rappasoft\LaravelLivewireTables\Views\Column; -use Rappasoft\LaravelLivewireTables\Views\Columns\ImageColumn; -use Rappasoft\LaravelLivewireTables\Views\Columns\LinkColumn; -use Rappasoft\LaravelLivewireTables\Views\Filters\DateFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\DateTimeFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectDropdownFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\NumberFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\SelectFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\TextFilter; - -class PetsTableAttributes extends DataTableComponent +class PetsTableAttributes extends PetsTable { - public $model = Pet::class; - public function configure(): void { $this->setPrimaryKey('id') @@ -49,123 +31,4 @@ public function configure(): void }); } - - public function columns(): array - { - return [ - Column::make('ID', 'id') - ->sortable() - ->setSortingPillTitle('Key') - ->setSortingPillDirections('0-9', '9-0'), - Column::make('Sort') - ->sortable() - ->excludeFromColumnSelect(), - Column::make('Name') - ->sortable() - ->secondaryHeader($this->getFilterByKey('pet_name_filter')) - ->footerFilter('pet_name_filter') - ->searchable(), - - Column::make('Age'), - - Column::make('Breed', 'breed.name') - ->secondaryHeaderFilter('breed') - ->footer($this->getFilterByKey('breed')) - ->sortable( - fn (Builder $query, string $direction) => $query->orderBy('pets.id', $direction) - ) - ->searchable( - fn (Builder $query, $searchTerm) => $query->orWhere('breed.name', $searchTerm) - ), - - Column::make('Other') - ->label(function ($row, Column $column) { - return 'Other'; - }) - ->footer(function ($rows) { - return 'Count: '.$rows->count(); - }), - - LinkColumn::make('Link') - ->title(fn ($row) => 'Edit') - ->location(fn ($row) => 'http://www.google.com') - ->attributes(fn ($row) => [ - 'class' => 'rounded-full', - 'alt' => $row->name.' Avatar', - ]), - ImageColumn::make('RowImg') - ->location(fn ($row) => 'test'.$row->id) - ->attributes(fn ($row) => [ - 'class' => 'rounded-full', - 'alt' => $row->name.' Avatar', - ]), - Column::make('Last Visit', 'last_visit') - ->sortable() - ->deselected(), - ]; - } - - public function filters(): array - { - return [ - MultiSelectFilter::make('Breed') - ->options( - Breed::query() - ->orderBy('name') - ->get() - ->keyBy('id') - ->map(fn ($breed) => $breed->name) - ->toArray() - ) - ->filter(function (Builder $builder, array $values) { - return $builder->whereIn('breed_id', $values); - }), - MultiSelectDropdownFilter::make('Species') - ->options( - Species::query() - ->orderBy('name') - ->get() - ->keyBy('id') - ->map(fn ($species) => $species->name) - ->toArray() - ) - ->filter(function (Builder $builder, array $values) { - return $builder->whereIn('species_id', $values); - }), - NumberFilter::make('Breed ID', 'breed_id_filter') - ->filter(function (Builder $builder, string $value) { - return $builder->where('breed_id', '=', $value); - }), - - TextFilter::make('Pet Name', 'pet_name_filter') - ->filter(function (Builder $builder, string $value) { - return $builder->where('pets.name', '=', $value); - }), - - DateFilter::make('Last Visit After Date', 'last_visit_date_filter') - ->filter(function (Builder $builder, string $value) { - return $builder->whereDate('pets.last_visit', '=>', $value); - }), - - DateTimeFilter::make('Last Visit Before DateTime', 'last_visit_datetime_filter') - ->filter(function (Builder $builder, string $value) { - return $builder->whereDate('pets.last_visit', '<=', $value); - }), - - SelectFilter::make('Breed SelectFilter', 'breed_select_filter') - ->options( - Breed::query() - ->orderBy('name') - ->get() - ->keyBy('id') - ->map(fn ($breed) => $breed->name) - ->toArray() - ) - ->filter(function (Builder $builder, string $value) { - return $builder->where('breed_id', $value); - }) - ->setCustomFilterLabel('livewire-tables::tests.testFilterLabel') - ->setFilterPillBlade('livewire-tables::tests.testFilterPills'), - ]; - } } diff --git a/tests/Http/Livewire/PetsTableEvents.php b/tests/Http/Livewire/PetsTableEvents.php new file mode 100644 index 000000000..24c7163cf --- /dev/null +++ b/tests/Http/Livewire/PetsTableEvents.php @@ -0,0 +1,25 @@ +setShouldBeHidden(); + } + + #[On('showTable')] + public function showTable(): void + { + $this->setShouldBeDisplayed(); + } + + #[On('hideTable')] + public function hideTable() + { + $this->setShouldBeHidden(); + } +} diff --git a/tests/Http/Livewire/PetsTableLoadingPlaceholder.php b/tests/Http/Livewire/PetsTableLoadingPlaceholder.php index c5096c496..26fd7c367 100644 --- a/tests/Http/Livewire/PetsTableLoadingPlaceholder.php +++ b/tests/Http/Livewire/PetsTableLoadingPlaceholder.php @@ -2,149 +2,12 @@ namespace Rappasoft\LaravelLivewireTables\Tests\Http\Livewire; -use Illuminate\Database\Eloquent\Builder; -use Rappasoft\LaravelLivewireTables\DataTableComponent; -use Rappasoft\LaravelLivewireTables\Tests\Models\Breed; -use Rappasoft\LaravelLivewireTables\Tests\Models\Pet; -use Rappasoft\LaravelLivewireTables\Tests\Models\Species; -use Rappasoft\LaravelLivewireTables\Views\Column; -use Rappasoft\LaravelLivewireTables\Views\Columns\ImageColumn; -use Rappasoft\LaravelLivewireTables\Views\Columns\LinkColumn; -use Rappasoft\LaravelLivewireTables\Views\Filters\DateFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\DateTimeFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectDropdownFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\NumberFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\SelectFilter; -use Rappasoft\LaravelLivewireTables\Views\Filters\TextFilter; - -class PetsTableLoadingPlaceholder extends DataTableComponent +class PetsTableLoadingPlaceholder extends PetsTable { - public $model = Pet::class; - public function configure(): void { $this->setPrimaryKey('id') ->setLoadingPlaceholderEnabled() ->setLoadingPlaceholderContent('TestLoadingPlaceholderContentTestTest'); } - - public function columns(): array - { - return [ - Column::make('ID', 'id') - ->sortable() - ->setSortingPillTitle('Key') - ->setSortingPillDirections('0-9', '9-0'), - Column::make('Sort') - ->sortable() - ->excludeFromColumnSelect(), - Column::make('Name') - ->sortable() - ->secondaryHeader($this->getFilterByKey('pet_name_filter')) - ->footerFilter('pet_name_filter') - ->searchable(), - - Column::make('Age'), - - Column::make('Breed', 'breed.name') - ->secondaryHeaderFilter('breed') - ->footer($this->getFilterByKey('breed')) - ->sortable( - fn (Builder $query, string $direction) => $query->orderBy('pets.id', $direction) - ) - ->searchable( - fn (Builder $query, $searchTerm) => $query->orWhere('breed.name', $searchTerm) - ), - - Column::make('Other') - ->label(function ($row, Column $column) { - return 'Other'; - }) - ->footer(function ($rows) { - return 'Count: '.$rows->count(); - }), - - LinkColumn::make('Link') - ->title(fn ($row) => 'Edit') - ->location(fn ($row) => 'http://www.google.com') - ->attributes(fn ($row) => [ - 'class' => 'rounded-full', - 'alt' => $row->name.' Avatar', - ]), - ImageColumn::make('RowImg') - ->location(fn ($row) => 'test'.$row->id) - ->attributes(fn ($row) => [ - 'class' => 'rounded-full', - 'alt' => $row->name.' Avatar', - ]), - Column::make('Last Visit', 'last_visit') - ->sortable() - ->deselected(), - ]; - } - - public function filters(): array - { - return [ - MultiSelectFilter::make('Breed') - ->options( - Breed::query() - ->orderBy('name') - ->get() - ->keyBy('id') - ->map(fn ($breed) => $breed->name) - ->toArray() - ) - ->filter(function (Builder $builder, array $values) { - return $builder->whereIn('breed_id', $values); - }), - MultiSelectDropdownFilter::make('Species') - ->options( - Species::query() - ->orderBy('name') - ->get() - ->keyBy('id') - ->map(fn ($species) => $species->name) - ->toArray() - ) - ->filter(function (Builder $builder, array $values) { - return $builder->whereIn('species_id', $values); - }), - NumberFilter::make('Breed ID', 'breed_id_filter') - ->filter(function (Builder $builder, string $value) { - return $builder->where('breed_id', '=', $value); - }), - - TextFilter::make('Pet Name', 'pet_name_filter') - ->filter(function (Builder $builder, string $value) { - return $builder->where('pets.name', '=', $value); - }), - - DateFilter::make('Last Visit After Date', 'last_visit_date_filter') - ->filter(function (Builder $builder, string $value) { - return $builder->whereDate('pets.last_visit', '=>', $value); - }), - - DateTimeFilter::make('Last Visit Before DateTime', 'last_visit_datetime_filter') - ->filter(function (Builder $builder, string $value) { - return $builder->whereDate('pets.last_visit', '<=', $value); - }), - - SelectFilter::make('Breed SelectFilter', 'breed_select_filter') - ->options( - Breed::query() - ->orderBy('name') - ->get() - ->keyBy('id') - ->map(fn ($breed) => $breed->name) - ->toArray() - ) - ->filter(function (Builder $builder, string $value) { - return $builder->where('breed_id', $value); - }) - ->setCustomFilterLabel('livewire-tables::tests.testFilterLabel') - ->setFilterPillBlade('livewire-tables::tests.testFilterPills'), - ]; - } } diff --git a/tests/Http/Livewire/PetsTableNoFilters.php b/tests/Http/Livewire/PetsTableNoFilters.php index 20bc7a7b9..d209a6602 100644 --- a/tests/Http/Livewire/PetsTableNoFilters.php +++ b/tests/Http/Livewire/PetsTableNoFilters.php @@ -6,15 +6,8 @@ use Rappasoft\LaravelLivewireTables\Tests\Models\Pet; use Rappasoft\LaravelLivewireTables\Views\Column; -class PetsTableNoFilters extends DataTableComponent +class PetsTableNoFilters extends PetsTable { - public $model = Pet::class; - - public function configure(): void - { - $this->setPrimaryKey('id'); - } - public function columns(): array { return [ @@ -36,4 +29,10 @@ public function columns(): array }), ]; } + + public function filters(): array + { + return [ + ]; + } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 0bf3aa3e2..92cec4db2 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -9,7 +9,7 @@ use Livewire\LivewireServiceProvider; use Orchestra\Testbench\TestCase as Orchestra; use Rappasoft\LaravelLivewireTables\LaravelLivewireTablesServiceProvider; -use Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\{BreedsTable,PetsTable,PetsTableUnpaginated,PetsTableWithOwner,SpeciesTable}; +use Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\{BreedsTable,PetsTable,PetsTableEvents,PetsTableUnpaginated,PetsTableWithOwner,SpeciesTable}; use Rappasoft\LaravelLivewireTables\Tests\Http\TestComponent; use Rappasoft\LaravelLivewireTables\Tests\Models\Breed; use Rappasoft\LaravelLivewireTables\Tests\Models\Owner; @@ -107,6 +107,21 @@ protected function setupBasicTable() $this->basicTable->render(); } + protected function setupEventsTable() + { + $view = view('livewire-tables::datatable'); + $this->eventsTable = new PetsTableEvents; + $this->eventsTable->boot(); + $this->eventsTable->bootedComponentUtilities(); + $this->eventsTable->bootedWithData(); + $this->eventsTable->bootedWithColumns(); + $this->eventsTable->bootedWithColumnSelect(); + $this->eventsTable->bootedWithSecondaryHeader(); + $this->eventsTable->booted(); + $this->eventsTable->renderingWithPagination($view, []); + $this->eventsTable->render(); + } + protected function setupBreedsTable() { $view = view('livewire-tables::datatable'); diff --git a/tests/Traits/Visuals/ComponentVisualsTest.php b/tests/Traits/Visuals/ComponentVisualsTest.php index 62cd5cf6b..1b2df3adf 100644 --- a/tests/Traits/Visuals/ComponentVisualsTest.php +++ b/tests/Traits/Visuals/ComponentVisualsTest.php @@ -48,15 +48,15 @@ public function test_fails_when_table_has_no_pk(): void Livewire::test(NoPrimaryKeyTable::class); } catch (DataTableConfigurationException $DataTableConfigurationException) { $this->testErrors = true; - $this->assertSame('You must set a primary key using setPrimaryKey in the configure method.', substr($DataTableConfigurationException->getMessage(), 0, 71)); + $this->assertSame('You must set a primary key using setPrimaryKey in the configure method, or configuring/configured lifecycle hooks', substr($DataTableConfigurationException->getMessage(), 0, 113)); } catch (ViewException $ViewException) { $this->testErrors = true; - $this->assertSame('You must set a primary key using setPrimaryKey in the configure method.', substr($ViewException->getMessage(), 0, 71)); + $this->assertSame('You must set a primary key using setPrimaryKey in the configure method, or configuring/configured lifecycle hooks', substr($ViewException->getMessage(), 0, 113)); } catch (Exception $standardException) { $this->testErrors = true; - $this->assertSame('You must set a primary key using setPrimaryKey in the configure method.', substr($standardException->getMessage(), 0, 71)); + $this->assertSame('You must set a primary key using setPrimaryKey in the configure method, or configuring/configured lifecycle hooks', substr($standardException->getMessage(), 0, 113)); } if (! $this->testErrors) { $this->fail('Did Not Throw Error - Missing Primary Key'); diff --git a/tests/Traits/Visuals/HideableTableTest.php b/tests/Traits/Visuals/HideableTableTest.php new file mode 100644 index 000000000..6af61ed75 --- /dev/null +++ b/tests/Traits/Visuals/HideableTableTest.php @@ -0,0 +1,69 @@ +setPrimaryKey('id'); + } + + public function bulkActions(): array + { + return ['exportBulk' => 'exportBulk']; + } + + public function exportBulk($items) + { + return $items; + } + }); + Livewire::test($petsTable) + ->assertSet('shouldBeDisplayed', true) + ->assertSee('Cartman'); + } + + public function test_can_see_table_if_shown(): void + { + $this->setupEventsTable(); + + Livewire::test($this->eventsTable) + ->assertSet('shouldBeDisplayed', false) + ->assertSee('Cartman') + ->call('setShouldBeDisplayed') + ->assertSet('shouldBeDisplayed', true) + ->assertSee('Cartman'); + + } + + public function test_can_not_see_hidden_table(): void + { + $this->setupEventsTable(); + + Livewire::test($this->eventsTable) + ->assertSee('Cartman') + ->assertSet('shouldBeDisplayed', false) + ->assertSee('Cartman'); + } + + public function test_can_show_hidden_table(): void + { + $this->setupEventsTable(); + + Livewire::test($this->eventsTable) + ->assertSet('shouldBeDisplayed', false) + ->dispatch('showTable') + ->assertSet('shouldBeDisplayed', true) + ->assertSee('Cartman'); + + } +}