Skip to content

Commit 4d60f56

Browse files
feat:[LAR-34] Add filament tags crud in cpanel with feature test (#203)
2 parents 66de40f + d76617d commit 4d60f56

File tree

4 files changed

+186
-1
lines changed

4 files changed

+186
-1
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
npm-debug.log
55
yarn-error.log
66
yarn.lock
7-
87
/vendor
98
composer.phar
109

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Filament\Resources;
6+
7+
use App\Filament\Resources\TagResource\Pages;
8+
use App\Models\Tag;
9+
use Filament\Forms;
10+
use Filament\Forms\Components\Select;
11+
use Filament\Forms\Form;
12+
use Filament\Resources\Resource;
13+
use Filament\Support\Enums\MaxWidth;
14+
use Filament\Tables;
15+
use Filament\Tables\Table;
16+
use Illuminate\Support\Str;
17+
18+
final class TagResource extends Resource
19+
{
20+
protected static ?string $model = Tag::class;
21+
22+
protected static ?string $navigationIcon = 'heroicon-o-tag';
23+
24+
public static function form(Form $form): Form
25+
{
26+
return $form
27+
->schema([
28+
Forms\Components\TextInput::make('name')
29+
->live(onBlur: true)
30+
->required()
31+
->unique()
32+
->validationMessages([
33+
'unique' => 'Cette valeur existe déjà',
34+
])
35+
->afterStateUpdated(function (string $operation, $state, Forms\Set $set): void {
36+
$set('slug', Str::slug($state));
37+
})
38+
->columnSpanFull(),
39+
Forms\Components\TextInput::make('slug')
40+
->readOnly()
41+
->required()
42+
->helperText(__('Cette valeur est générée dynamiquement en fonction du Name.'))
43+
->columnSpanFull(),
44+
Select::make('concerns')
45+
->multiple()
46+
->options([
47+
'post' => 'Post',
48+
'tutorial' => 'Tutoriel',
49+
'discussion' => 'Discussion',
50+
])
51+
->required()
52+
->columnSpanFull(),
53+
Forms\Components\Textarea::make('description')
54+
->columnSpanFull(),
55+
]);
56+
}
57+
58+
public static function table(Table $table): Table
59+
{
60+
return $table
61+
->columns([
62+
Tables\Columns\TextColumn::make('name')
63+
->searchable(),
64+
Tables\Columns\TextColumn::make('slug')
65+
->searchable(),
66+
Tables\Columns\TextColumn::make(name: 'concerns'),
67+
])
68+
->filters([
69+
//
70+
])
71+
->actions([
72+
\Filament\Tables\Actions\ActionGroup::make([
73+
Tables\Actions\DeleteAction::make(),
74+
Tables\Actions\EditAction::make()
75+
->slideOver()
76+
->modalWidth(MaxWidth::Large),
77+
]),
78+
])
79+
->bulkActions([
80+
Tables\Actions\BulkActionGroup::make([
81+
Tables\Actions\DeleteBulkAction::make(),
82+
]),
83+
]);
84+
}
85+
86+
public static function getPages(): array
87+
{
88+
return [
89+
'index' => Pages\ListTags::route('/'),
90+
];
91+
}
92+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Filament\Resources\TagResource\Pages;
6+
7+
use App\Filament\Resources\TagResource;
8+
use Filament\Actions;
9+
use Filament\Resources\Pages\ListRecords;
10+
use Filament\Support\Enums\MaxWidth;
11+
12+
final class ListTags extends ListRecords
13+
{
14+
protected static string $resource = TagResource::class;
15+
16+
protected function getHeaderActions(): array
17+
{
18+
return [
19+
Actions\CreateAction::make()
20+
->slideOver()
21+
->modalWidth(MaxWidth::Large),
22+
];
23+
}
24+
}

tests/Feature/Filament/TagTest.php

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use App\Filament\Resources\TagResource;
6+
use App\Filament\Resources\TagResource\Pages\ListTags;
7+
use App\Models\Tag;
8+
use Filament\Actions\CreateAction;
9+
use Filament\Actions\EditAction;
10+
use Illuminate\Database\Eloquent\Factories\Sequence;
11+
use Livewire\Livewire;
12+
13+
beforeEach(function (): void {
14+
$this->user = $this->login();
15+
$this->tags = Tag::factory()
16+
->count(10)
17+
->state(new Sequence(
18+
['concerns' => ['post', 'tutorial']],
19+
['concerns' => ['post']],
20+
))
21+
->create();
22+
});
23+
24+
describe(TagResource::class, function (): void {
25+
it('page can display table with records', function (): void {
26+
Livewire::test(ListTags::class)
27+
->assertCanSeeTableRecords($this->tags);
28+
});
29+
30+
it('can validate input is value is null or empty', function (): void {
31+
$name = fake()->name();
32+
33+
Livewire::test(ListTags::class)
34+
->callAction(CreateAction::class, data: [
35+
'name' => null,
36+
'concerns' => [],
37+
'description' => 'Description du tag '.$name,
38+
])
39+
->assertHasActionErrors(['name' => 'required', 'concerns' => 'required']);
40+
});
41+
42+
it('Admin can create tag', function (): void {
43+
$name = fake()->name();
44+
45+
Livewire::test(ListTags::class)
46+
->callAction(CreateAction::class, data: [
47+
'name' => $name,
48+
'concerns' => ['post', 'tutorial'],
49+
'description' => 'Description du tag '.$name,
50+
])
51+
->assertHasNoActionErrors()
52+
->assertStatus(200);
53+
});
54+
55+
it('Admin can edit tag', function (): void {
56+
$tag = Tag::factory()->create();
57+
58+
Livewire::test(ListTags::class)
59+
->callTableAction(EditAction::class, $tag, data: [
60+
'name' => 'Edited tag',
61+
])
62+
->assertHasNoTableActionErrors();
63+
64+
$tag->refresh();
65+
66+
expect($tag->name)
67+
->toBe('Edited tag');
68+
});
69+
70+
})->group('tags');

0 commit comments

Comments
 (0)