Filament moderne (groupes nav, 4 charts, filtres/badges) + Filament Shield (rôles/permissions) + noms exos localisés dans routines
Build & Deploy / build (push) Successful in 19s

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-19 05:09:29 +02:00
co-authored by Claude Opus 4.8
parent 3ec14f219b
commit 52fab9fbe5
47 changed files with 1644 additions and 292 deletions
@@ -13,12 +13,21 @@ use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use Technical\Integrations\Models\Integration;
use UnitEnum;
class IntegrationResource extends Resource
{
protected static ?string $model = Integration::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedArrowsRightLeft;
protected static string|UnitEnum|null $navigationGroup = 'Système';
protected static ?int $navigationSort = 1;
protected static ?string $modelLabel = 'intégration';
protected static ?string $pluralModelLabel = 'intégrations';
public static function form(Schema $schema): Schema
{
@@ -37,6 +46,14 @@ class IntegrationResource extends Resource
];
}
/**
* @return array<int, string>
*/
public static function getGloballySearchableAttributes(): array
{
return ['provider', 'external_user_id', 'user.name'];
}
public static function getPages(): array
{
return [
@@ -2,13 +2,17 @@
namespace App\Filament\Resources\Integrations\Tables;
use Filament\Actions\BulkAction;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
use Technical\Integrations\Enums\IntegrationStatus;
use Technical\Integrations\Models\Integration;
/**
* Table des intégrations externes : utilisateur, fournisseur, état, dernière synchro.
@@ -27,7 +31,17 @@ class IntegrationsTable
TextColumn::make('provider')
->label('Fournisseur')
->badge()
->searchable(),
->color(fn (string $state): string => match (strtolower($state)) {
'strava' => 'danger',
'garmin' => 'info',
default => 'gray',
})
->searchable()
->sortable(),
TextColumn::make('external_user_id')
->label('ID externe')
->toggleable(isToggledHiddenByDefault: true)
->placeholder('—'),
TextColumn::make('status')
->label('État')
->badge()
@@ -36,6 +50,11 @@ class IntegrationsTable
IntegrationStatus::Revoked => 'gray',
IntegrationStatus::Error => 'danger',
}),
TextColumn::make('connected_at')
->label('Connecté le')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('last_synced_at')
->label('Dernière synchro')
->dateTime()
@@ -43,6 +62,9 @@ class IntegrationsTable
->placeholder('Jamais'),
])
->filters([
SelectFilter::make('provider')
->label('Fournisseur')
->options(fn (): array => self::distinctProviders()),
SelectFilter::make('status')
->label('État')
->options(IntegrationStatus::class),
@@ -53,8 +75,34 @@ class IntegrationsTable
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
// Révocation groupée : coupe l'accès sans supprimer l'historique de connexion.
BulkAction::make('revoke')
->label('Révoquer')
->icon(Heroicon::OutlinedBoltSlash)
->color('danger')
->requiresConfirmation()
->action(function (Collection $records): void {
$records->each(fn (Integration $integration) => $integration->update([
'status' => IntegrationStatus::Revoked,
]));
})
->deselectRecordsAfterCompletion(),
]),
])
->defaultSort('last_synced_at', 'desc');
}
/**
* Valeurs distinctes de la colonne "provider" pour alimenter le filtre.
*
* @return array<string, string>
*/
private static function distinctProviders(): array
{
return Integration::query()
->distinct()
->orderBy('provider')
->pluck('provider', 'provider')
->all();
}
}