Skip to content

Commit fe6a3dc

Browse files
authored
5.1.0 (#107)
* Added ability to chain a `->when(bool $condition)` method to an instantiated head action, in order to enable it conditionally * Added a new built-in `RedirectHeadAction`, that will be used by the pre-configured `CreateHeadAction` * Added an optional `bool $openInNewWindow = false` to the `CreateHeadAction` * Added a new [JavaScript snippet](/README.md#set-up-a-few-lines-of-javascript) to handle head action link opening in tab: you'll have to add it if you want to benefit from this new ability
1 parent b2807c5 commit fe6a3dc

File tree

9 files changed

+154
-22
lines changed

9 files changed

+154
-22
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ jobs:
5959
- name: Code analysis
6060
if: matrix.php == '8.1' && matrix.laravel == '9.*'
6161
run: |
62-
# Remove this line once Larastan and Livewire are working well together
63-
sed -i -e 's#.*protected \$enablesPackageDiscoveries.*#&\nprotected function overrideApplicationBindings($app){return["livewire"=>"Livewire\\\\LivewireManager"];}#' vendor/nunomaduro/larastan/src/ApplicationResolver.php
6462
vendor/bin/pint --test -vvv
6563
vendor/bin/phpmd config,src,tests text phpmd.xml
6664
vendor/bin/phpstan analyse

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Changelog
22

3+
## [5.1.0](https://github.com/Okipa/laravel-table/compare/5.0.2...5.1.0)
4+
5+
2022-10-25
6+
7+
* Added ability to chain a `->when(bool $condition)` method to an instantiated head action, in order to enable it conditionally
8+
* Added a new built-in `RedirectHeadAction`, that will be used by the pre-configured `CreateHeadAction`
9+
* Added an optional `bool $openInNewWindow = false` to the `CreateHeadAction`
10+
* Added a new [JavaScript snippet](/README.md#set-up-a-few-lines-of-javascript) to handle head action link opening in tab: you'll have to add it if you want to benefit from this new ability
11+
312
## [5.0.2](https://github.com/Okipa/laravel-table/compare/5.0.1...5.0.2)
413

514
2022-10-07

README.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -473,11 +473,18 @@ Configure a table action that will be displayed as a button positioned at the ri
473473
If no head action is declared, the dedicated slot for it in the table head will remain empty.
474474

475475
This package provides the following built-in head actions:
476-
* `CreateHeadAction`:
477-
* Requires a `string $createUrl` argument on instantiation
476+
* `RedirectHeadAction`:
477+
* Requires `string $url`, `string $label`, `string $icon`, `array $class = ['btn', 'btn-success']` and `bool $openInNewWindow = false` arguments on instantiation
478478
* Redirects to the model create page from a click on a `Create` button
479+
* `CreateHeadAction`:
480+
* Requires `string $createUrl` and `bool $openInNewWindow = false` arguments on instantiation
481+
* Instantiate a pre-configured `RedirectHeadAction` with the given `$createUrl` as URL, `__('Create')` as label and `config('laravel-table.icon.create')` as icon
479482

480-
To use it, you'll have to pass an instance of it to the `headAction` method.
483+
To use one of them, you'll have to pass an instance of it to the `headAction` method.
484+
485+
You'll be able to chain the following method to your head action:
486+
* `when(bool $condition): Okipa\LaravelTable\Abstracts\AbstractHeadAction`
487+
* Determines whether the head action should be enabled
481488

482489
```php
483490
namespace App\Tables;
@@ -493,7 +500,8 @@ class UsersTable extends AbstractTableConfiguration
493500
{
494501
return Table::make()
495502
->model(User::class)
496-
->headAction(new CreateHeadAction(route('user.create')));
503+
// Create head action will not be available when authenticated user is not allowed to create users
504+
->headAction((new CreateHeadAction(route('user.create')))->when(Auth::user()->cannot('create_users')));
497505
}
498506
}
499507
```
@@ -549,9 +557,9 @@ This package provides the built-in following bulk actions:
549557

550558
To use them, you'll have to pass a closure parameter to the `bulkActions` method. This closure will allow you to manipulate a `Illuminate\Database\Eloquent $model` argument and has to return an array containing bulk action instances.
551559

552-
You'll ben able to chain the following methods to your bulk actions:
560+
You'll be able to chain the following methods to your bulk actions:
553561
* `when(bool $condition): Okipa\LaravelTable\Abstracts\AbstractBulkAction`
554-
* Determines if action should be available on table rows
562+
* Determines whether the bulk action should be enabled on the table rows
555563
* `confirmationQuestion(string|false $confirmationQuestion): Okipa\LaravelTable\Abstracts\AbstractBulkAction`
556564
* Overrides the default action confirmation message
557565
* `feedbackMessage(string|false $feedbackMessage): Okipa\LaravelTable\Abstracts\AbstractBulkAction`:
@@ -1185,6 +1193,14 @@ Livewire.on('laraveltable:action:feedback', (feedbackMessage) => {
11851193
});
11861194
```
11871195

1196+
Finally, in order to allow head `RedirectHeadAction` and `CreateHeadAction` to open link in new tab, you'll also have to add the following JS snippet:
1197+
1198+
```javascript
1199+
Livewire.on('laraveltable:link:open:newtab', (url) => {
1200+
window.open(url, '_blank').focus();
1201+
});
1202+
```
1203+
11881204
### Trigger Livewire events on table load
11891205

11901206
You may want to trigger some events on table load, in order to load UI third party JS libraries for example.

src/Abstracts/AbstractHeadAction.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,26 @@ abstract class AbstractHeadAction
99
{
1010
public string $rowActionClass;
1111

12+
protected bool $isAllowed = true;
13+
1214
abstract protected function class(): array;
1315

1416
abstract protected function icon(): string;
1517

1618
abstract protected function title(): string;
1719

20+
public function when(bool $condition): self
21+
{
22+
$this->isAllowed = $condition;
23+
24+
return $this;
25+
}
26+
27+
public function isAllowed(): bool
28+
{
29+
return $this->isAllowed;
30+
}
31+
1832
/** @return mixed|void */
1933
abstract public function action(Component $livewire);
2034

src/HeadActions/CreateHeadAction.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,40 @@
22

33
namespace Okipa\LaravelTable\HeadActions;
44

5-
use Illuminate\Http\RedirectResponse;
65
use Livewire\Component;
7-
use Livewire\Redirector;
86
use Okipa\LaravelTable\Abstracts\AbstractHeadAction;
97

108
class CreateHeadAction extends AbstractHeadAction
119
{
12-
public function __construct(public string $createUrl)
10+
protected RedirectHeadAction $redirectHeadAction;
11+
12+
public function __construct(public string $createUrl, bool $openInNewWindow = false)
1313
{
14-
//
14+
$this->redirectHeadAction = new RedirectHeadAction(
15+
url: $createUrl,
16+
label: __('Create'),
17+
icon: config('laravel-table.icon.create'),
18+
openInNewWindow: $openInNewWindow
19+
);
1520
}
1621

1722
protected function class(): array
1823
{
19-
return ['btn', 'btn-success'];
24+
return $this->redirectHeadAction->class();
2025
}
2126

2227
protected function title(): string
2328
{
24-
return __('Create');
29+
return $this->redirectHeadAction->title();
2530
}
2631

2732
protected function icon(): string
2833
{
29-
return config('laravel-table.icon.create');
34+
return $this->redirectHeadAction->icon();
3035
}
3136

32-
public function action(Component $livewire): RedirectResponse|Redirector
37+
public function action(Component $livewire): void
3338
{
34-
return redirect()->to($this->createUrl);
39+
$this->redirectHeadAction->action($livewire);
3540
}
3641
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace Okipa\LaravelTable\HeadActions;
4+
5+
use Livewire\Component;
6+
use Okipa\LaravelTable\Abstracts\AbstractHeadAction;
7+
8+
class RedirectHeadAction extends AbstractHeadAction
9+
{
10+
public function __construct(
11+
public string $url,
12+
public string $label,
13+
public string $icon,
14+
public array $class = ['btn', 'btn-success'],
15+
public bool $openInNewWindow = false,
16+
) {
17+
//
18+
}
19+
20+
protected function class(): array
21+
{
22+
return $this->class;
23+
}
24+
25+
protected function title(): string
26+
{
27+
return __($this->label);
28+
}
29+
30+
protected function icon(): string
31+
{
32+
return $this->icon;
33+
}
34+
35+
public function action(Component $livewire): void
36+
{
37+
$this->openInNewWindow
38+
? $livewire->emit('laraveltable:link:open:newtab', $this->url)
39+
: redirect()->to($this->url);
40+
}
41+
}

src/Livewire/Table.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class Table extends Component
5252

5353
public bool $resetFilters = false;
5454

55-
public array|null $headActionArray;
55+
public array $headActionArray;
5656

5757
public bool $selectAll = false;
5858

@@ -233,7 +233,15 @@ public function sortBy(string $columnKey): void
233233

234234
public function headAction(): mixed
235235
{
236-
return AbstractHeadAction::make($this->headActionArray)->action($this);
236+
if (! $this->headActionArray) {
237+
return null;
238+
}
239+
$headActionInstance = AbstractHeadAction::make($this->headActionArray);
240+
if (! $headActionInstance->isAllowed()) {
241+
return null;
242+
}
243+
244+
return $headActionInstance->action($this);
237245
}
238246

239247
public function updatedSelectAll(): void

src/Table.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -354,16 +354,20 @@ public function getFilterClosures(array $filtersArray, array $selectedFilters):
354354
return $filterClosures;
355355
}
356356

357-
public function getHeadActionArray(): array|null
357+
public function getHeadActionArray(): array
358358
{
359359
if (! $this->headAction) {
360-
return null;
360+
return [];
361361
}
362362
$this->headAction->setup();
363+
if (! $this->headAction->isAllowed()) {
364+
return [];
365+
}
363366

364367
return (array) $this->headAction;
365368
}
366369

370+
/** @throws \JsonException */
367371
public function getRowClass(): array
368372
{
369373
$tableRowClass = [];
@@ -374,7 +378,10 @@ public function getRowClass(): array
374378
$tableRowClass[$model->laravel_table_unique_identifier] = ($this->rowClassesClosure)($model);
375379
}
376380

377-
return $tableRowClass;
381+
return json_decode(json_encode(
382+
$tableRowClass,
383+
JSON_THROW_ON_ERROR
384+
), true, 512, JSON_THROW_ON_ERROR);
378385
}
379386

380387
/** @throws \JsonException */

tests/Unit/Bootstrap5/TableHeadActionTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,38 @@ protected function columns(): array
4949
->call('headAction')
5050
->assertRedirect(route('user.create'));
5151
}
52+
53+
/** @test */
54+
public function it_can_allow_head_action_conditionally(): void
55+
{
56+
app('router')->get('/user/create', ['as' => 'user.create']);
57+
Config::set('laravel-table.icon.create', 'create-icon');
58+
$config = new class extends AbstractTableConfiguration
59+
{
60+
protected function table(): Table
61+
{
62+
return Table::make()->model(User::class)
63+
->headAction((new CreateHeadAction(route('user.create'), true))->when(false));
64+
}
65+
66+
protected function columns(): array
67+
{
68+
return [
69+
Column::make('name'),
70+
];
71+
}
72+
};
73+
Livewire::test(\Okipa\LaravelTable\Livewire\Table::class, ['config' => $config::class])
74+
->call('init')
75+
->assertDontSeeHtml([
76+
'<a wire:click.prevent="headAction()"',
77+
' class="btn btn-success"',
78+
' href=""',
79+
' title="Create">',
80+
'create-icon Create',
81+
'</a>',
82+
])
83+
->call('headAction')
84+
->assertNotEmitted('laraveltable:link:open:newtab');
85+
}
5286
}

0 commit comments

Comments
 (0)