Skip to content

Commit

Permalink
Merge pull request #1610 from rappasoft/develop
Browse files Browse the repository at this point in the history
Develop to Master
  • Loading branch information
lrljoe committed Dec 26, 2023
2 parents 2bfe6df + 4e75b3d commit e2b5c4f
Show file tree
Hide file tree
Showing 20 changed files with 619 additions and 17 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
All notable changes to `laravel-livewire-tables` will be documented in this file

## UNRELEASED

### Bug Fixes
- Ensure mount() is called prior to bundler() executing by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1603

### New Features
- Add capability to call a new "addAdditionalSelects()" to append select table fields (without impacting setAdditionalSelect) by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1609

## [v3.1.5] - 2023-12-09
### New Features
- Add capability to use as a Full Page Component by @amshehzad and @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1580
- Add DateColumn by @lrljoe in https://github.com/rappasoft/laravel-livewire-tables/pull/1589
Expand Down
15 changes: 15 additions & 0 deletions docs/datatable/available-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,8 @@ public function configure(): void

By default the only columns defined in the select statement are the ones defined via columns. If you need to define additional selects that you don't have a column for you may:

Note - that you may only call this once, and it will override any existing additionalSelects in use.

```php
public function configure(): void
{
Expand All @@ -433,6 +435,19 @@ public function configure(): void

Since you probably won't have an `ID` column defined, the ID will not be available on the model to use. In the case of an actions column where you have buttons specific to the row, you probably need that, so you can add the select statement to make it available on the model.

### addAdditionalSelects

By default the only columns defined in the select statement are the ones defined via columns. If you need to define additional selects that you don't have a column for you may:

Note - that in contrast to setAdditionalSelects, you may call this multipole times, and it will append the additional selects. Take care not to re-use the same field names!

```php
public function configure(): void
{
$this->addAdditionalSelects(['users.id as id']);
}
```

## Misc.

### setEmptyMessage
Expand Down
102 changes: 102 additions & 0 deletions docs/filter-types/filters-livewire-component.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
title: Livewire Custom Filter (Beta)
weight: 11
---

## Livewire Custom Filter

**IN BETA**
This feature is currently in beta, and use in production is not recommended.

### Usage
This allows you to use a child/nested Livewire Component in place of the existing Filters, giving you more control over the look/feel/behaviour of a filter.

To use a LivewireComponentFilter, you must include it in your namespace:
```php
use Rappasoft\LaravelLivewireTables\Views\Filters\LivewireComponentFilter;
```

When creating a filter:
- Specify a unique name
- Set the path to a valid Livewire Component
- Define a filter() callback to define how the returned value will be used.

```php
public function filters(): array
{
return [
LivewireComponentFilter::make('My External Filter')
->setLivewireComponent('my-test-external-filter')
->filter(function (Builder $builder, string $value) {
$builder->where('name', 'like', '%'.$value.'%');
}),
];
}
```

### Configuring Your Livewire Filter Component

A basic example (replicating the Text Filter) looks like the below, note the usage of the "IsExternalFilter" trait.
```php
<?php

namespace App\Livewire;

use Livewire\Component;
use Rappasoft\LaravelLivewireTables\Views\Traits\IsExternalFilter;

class MyTestExternalFilter extends Component
{
use IsExternalFilter;

public function render()
{
return view('livewire.my-test-external-filter');
}
}
```

Should you prefer not to use the IsExternalFilter trait, the below contains all relevant code:
```php
<?php

namespace App\Livewire;

use Livewire\Component;
use Livewire\Attributes\Modelable;

class MyTestExternalFilter extends Component
{
#[Modelable]
public $value = '';

public $filterKey = '';

public function render()
{
return view('livewire.my-test-external-filter');
}
}
```


### Important Notes for Livewire Component Filter Blade
- You must update the "value" property on your component in order to return a value to the DataTableComponent. This is setup via the "IsExternalFilter" trait.
- You should use "debounce" rather than "live" to avoid repetitive updates to the DataTableComponent

An example "my-test-external-filter.blade.php" is given below:
```php
<div role="menuitem">
<div class="rounded-md shadow-sm" >
<input wire:model.debounce.1000ms="value"
type="text"
id="my_test_external_filter_input"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder=""
>
</div>
</div>
```

### Important Notes For The livewire-component-filter.blade.php
- It is **strongly** recommmended not to publish, nor update this file, while this feature is in beta, as it is subject to change at short notice, which may lead to breaking changes.
4 changes: 2 additions & 2 deletions docs/misc/lifecycle-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ With the migration to Livewire 3, there we are implementing several Lifecycle Ho
You may use these either in your Table Component, or in a trait

## configuring
This is called immediately prior to the configure() method being called
This is called immediately prior to the configure() method being called. This will be overridden by anything you define in configure()

## configured
This is called immediately after the configure() method is called
This is called immediately after the configure() method is called. This will override anything you define in configure()

## settingColumns
This is called prior to setting up the available Columns via the columns() method
Expand Down
2 changes: 1 addition & 1 deletion resources/laravel-livewire-tables.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
import './css/laravel-livewire-tables.min.css'
import './js/laravel-livewire-tables.js'
import './js/laravel-livewire-tables.min.js'
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div wire:key="filterComponents.{{ $filter->getKey() }}-wrapper">
<x-livewire-tables::tools.filter-label :$filter :$filterLayout :$tableName :$isTailwind :$isBootstrap4 :$isBootstrap5 :$isBootstrap />

<livewire:dynamic-component :is="$livewireComponent" :filterKey="$filter->getKey()" :key="'filterComponents-'.$filter->getKey()" wire:model.live="filterComponents.{{ $filter->getKey() }}" />
</div>
2 changes: 1 addition & 1 deletion src/Traits/ComponentUtilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function mountComponentUtilities(): void
/**
* Runs configure() with Lifecycle Hooks on each Lifecycle
*/
public function bootComponentUtilities(): void
public function bootedComponentUtilities(): void
{
// Fire Lifecycle Hooks for configuring
$this->callHook('configuring');
Expand Down
16 changes: 16 additions & 0 deletions src/Traits/Configuration/ComponentConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ public function setEagerLoadAllRelationsDisabled(): self
return $this;
}

/**
* Allows adding a single set of additional selects to the query
*/
public function setAdditionalSelects(string|array $selects): self
{
if (! is_array($selects)) {
Expand All @@ -74,6 +77,19 @@ public function setAdditionalSelects(string|array $selects): self
return $this;
}

/**
* Allows appending more additional selects
*/
public function addAdditionalSelects(string|array $selects): self
{
if (! is_array($selects)) {
$selects = [$selects];
}
$this->additionalSelects = [...$this->additionalSelects, ...$selects];

return $this;
}

public function setDataTableFingerprint(string $dataTableFingerprint): self
{
$this->dataTableFingerprint = $dataTableFingerprint;
Expand Down
2 changes: 1 addition & 1 deletion src/Traits/WithColumnSelect.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ protected function queryStringWithColumnSelect(): array
return [];
}

public function bootWithColumnSelect(): void
public function bootedWithColumnSelect(): void
{
$this->setupColumnSelect();
}
Expand Down
2 changes: 1 addition & 1 deletion src/Traits/WithColumns.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ trait WithColumns
/**
* Sets up Columns
*/
public function bootWithColumns(): void
public function bootedWithColumns(): void
{
$this->columns = collect();

Expand Down
2 changes: 1 addition & 1 deletion src/Traits/WithData.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ trait WithData
/**
* Sets up the Builder instance
*/
public function bootWithData(): void
public function bootedWithData(): void
{
//Sets up the Builder Instance
$this->setBuilder($this->builder());
Expand Down
10 changes: 5 additions & 5 deletions src/Traits/WithSecondaryHeader.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ trait WithSecondaryHeader

protected $secondaryHeaderTdAttributesCallback;

public function bootedWithSecondaryHeader(): void
{
$this->setupSecondaryHeader();
}

public function setupSecondaryHeader(): void
{
foreach ($this->getColumns() as $column) {
Expand All @@ -26,9 +31,4 @@ public function setupSecondaryHeader(): void
}
}
}

public function bootWithSecondaryHeader(): void
{
$this->setupSecondaryHeader();
}
}
65 changes: 65 additions & 0 deletions src/Views/Filters/LivewireComponentFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace Rappasoft\LaravelLivewireTables\Views\Filters;

use Rappasoft\LaravelLivewireTables\Exceptions\DataTableConfigurationException;
use Rappasoft\LaravelLivewireTables\Views\Filter;

class LivewireComponentFilter extends Filter
{
public string $viewPath = 'livewire-tables::components.tools.filters.livewire-component-filter';

public string $livewireComponent = '';

public function validate(string $value): string|bool
{
return $value;
}

public function isEmpty(?string $value): bool
{
return is_null($value) || $value === '';
}

/**
* Gets the Default Value for this Filter via the Component
*/
public function getFilterDefaultValue(): ?string
{
return $this->filterDefaultValue ?? null;
}

public function setLivewireComponent(string $livewireComponent): self
{

$class = '\\'.config('livewire.class_namespace').'\\'.collect(str($livewireComponent)->explode('.'))->map(fn ($segment) => (string) str($segment)->studly())->join('\\');

if (! class_exists($class)) {
throw new DataTableConfigurationException('You must specify a valid path to your Livewire Component Filter.');
}

if (! is_subclass_of($class, \Livewire\Component::class)) {
throw new DataTableConfigurationException('Your Livewire Component Filter MUST Extend Livewire\Component.');
}

$this->livewireComponent = $livewireComponent;

return $this;
}

public function getLivewireComponent(): string
{
return $this->livewireComponent ?? '';
}

public function render(): string|\Illuminate\Contracts\Foundation\Application|\Illuminate\View\View|\Illuminate\View\Factory
{
if ($this->livewireComponent == '') {
throw new DataTableConfigurationException('You must specify a valid path to your Livewire Component Filter.');
}

return view($this->getViewPath(), $this->getFilterDisplayData())->with([
'livewireComponent' => $this->livewireComponent,
]);
}
}
13 changes: 13 additions & 0 deletions src/Views/Traits/IsExternalFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Rappasoft\LaravelLivewireTables\Views\Traits;

use Livewire\Attributes\Modelable;

trait IsExternalFilter
{
#[Modelable]
public $value = '';

public $filterKey = '';
}
19 changes: 19 additions & 0 deletions tests/DataTableComponentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Rappasoft\LaravelLivewireTables\Tests;

use Livewire\Livewire;
use Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\FailingTables\NoColumnsTable;
use Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\FailingTables\NoPrimaryKeyTable;
use Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\PetsTable;

Expand Down Expand Up @@ -79,4 +80,22 @@ public function default_fingerprint_will_be_url_friendy(): void
// control
$this->assertTrue(filter_var('http://[9/$].dev', FILTER_VALIDATE_URL) === false);
}

/** @test */
public function minimum_one_column_expected(): void
{
$this->expectException(\Rappasoft\LaravelLivewireTables\Exceptions\NoColumnsException::class);
$table = new NoColumnsTable();
$table->boot();
$table->bootedComponentUtilities();
$table->bootedWithData();
$table->bootedWithColumns();
$table->bootedWithColumnSelect();
$table->bootedWithSecondaryHeader();
$table->booted();
$table->renderingWithData($view, []);
$table->renderingWithPagination($view, []);
$table->render();

}
}
Loading

0 comments on commit e2b5c4f

Please sign in to comment.