Filament Activity Timeline
Transformez les journaux d’activité techniques en événements métier clairs, localisés et lisibles dans les widgets, pages et infolists Filament.
Compatibilité
| PHP | ^8.3 |
|---|---|
| Laravel | ^12.0|^13.0 |
| Filament | ^4.0|^5.0 |
| spatie/laravel-activitylog | ^4.12|^5.0 (source optionnelle) |
| Version | v1.0.1 |
| Licence | MIT |
Installation
composer require laboiteacode/filament-activity-timeline
Présentation
Un journal d’activité sait généralement dire que customer_id est passé de 14 à 27. Un utilisateur, lui, veut lire que le client ACME France a été remplacé par Dupont Conseil. Filament Activity Timeline apporte cette couche de présentation métier, sans disperser des callbacks dans chaque ressource Filament.
Le package transforme une activité technique en phrase claire et localisée : qui a agi, sur quel enregistrement, quel événement s’est produit et quelles valeurs ont changé. Il fournit un widget, un composant de schéma pour les infolists et un objet Timeline utilisable dans une page.
Des changements compréhensibles
Les valeurs anciennes et nouvelles sont présentées selon leur sens réel : booléens traduits, dates formatées, montants localisés, enums affichées avec leur libellé et identifiants de relations résolus vers le nom de l’enregistrement. Les listes, objets JSON et maps disposent également de présentations dédiées.
Les attributs sensibles peuvent être cachés, masqués ou remplacés par un libellé « masqué ». Des snapshots optionnels conservent le titre d’un sujet ou d’une relation même après la suppression de l’enregistrement associé.
Une règle déclarée une fois
Le registre sémantique associe à chaque modèle son libellé, son titre métier, ses icônes, ses couleurs et ses formats d’attributs. Cette définition globale est ensuite partagée par chaque timeline. Les événements personnalisés peuvent recevoir leur propre phrase traduisible, par exemple un remboursement ou une validation.
La résolution respecte une priorité claire entre la configuration locale, le registre global, un contrat implémenté par le modèle, la ressource Filament et les conventions. Les relations sont résolues avec un cache par rendu pour éviter les requêtes N+1.
Adapté aux historiques volumineux
Les filtres par événement sont exécutés côté serveur. Le chargement progressif utilise une pagination par curseur lorsque la source le permet : les anciennes entrées restent affichées, les doublons sont évités et l’historique complet n’est jamais chargé en mémoire.
L’intégration prête à l’emploi cible spatie/laravel-activitylog 4.12 ou 5, mais le système de source reste extensible pour une table maison, un service externe ou un autre package.
Le composant reprend les variables et composants Filament, suit les thèmes clairs et sombres, et inclut les traductions anglaises et françaises. Il est open source sous licence MIT.
Documentation
Installation
Installez le package :
composer require laboiteacode/filament-activity-timeline
Pour utiliser la source Spatie intégrée, installez et préparez spatie/laravel-activitylog :
composer require spatie/laravel-activitylog
php artisan vendor:publish \
--provider="Spatie\Activitylog\ActivitylogServiceProvider" \
--tag="activitylog-migrations"
php artisan migrate
Enregistrez ensuite le plugin dans le provider du panel :
use LaBoiteACode\FilamentActivityTimeline\FilamentActivityTimelinePlugin;
public function panel(Panel $panel): Panel
{
return $panel->plugins([
FilamentActivityTimelinePlugin::make(),
]);
}
Démarrage rapide
Le package ne journalise pas lui-même l’activité : il présente les événements produits par une source. Avec Spatie, commencez par activer la journalisation sur le modèle :
use Spatie\Activitylog\Models\Concerns\LogsActivity;
use Spatie\Activitylog\Support\LogOptions;
class Order extends Model
{
use LogsActivity;
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()
->logOnly(['status', 'total', 'customer_id', 'paid_at'])
->logOnlyDirty();
}
}
Créez ensuite un widget configuré pour ce modèle :
use LaBoiteACode\FilamentActivityTimeline\Timeline;
use LaBoiteACode\FilamentActivityTimeline\Widgets\ActivityTimelineWidget;
class OrderTimelineWidget extends ActivityTimelineWidget
{
protected function timeline(): Timeline
{
return Timeline::make()
->source('spatie')
->heading('Historique')
->limit(15)
->loadMore()
->filters();
}
}
Utilisation
Dans une page de ressource
Enregistrez le widget sur la page d’un enregistrement. Filament injecte automatiquement le record courant :
protected function getFooterWidgets(): array
{
return [
OrderTimelineWidget::class,
];
}
Dans une infolist
Le composant de schéma reçoit lui aussi l’enregistrement de l’infolist :
use LaBoiteACode\FilamentActivityTimeline\Infolists\ActivityTimelineEntry;
ActivityTimelineEntry::make('activity')
->source('spatie')
->heading('Historique')
->perPage(10)
->loadMore()
->filters();
Ajoutez ->static() pour une présentation sans interactions Livewire.
Directement dans une page
Timeline implémente Htmlable et peut être rendu depuis une page :
Timeline::make('activity')
->record($this->record)
->loadMore()
->filters();
Registre sémantique
Déclarez une fois la façon dont un modèle raconte son histoire :
use LaBoiteACode\FilamentActivityTimeline\Facades\ActivityTimeline;
ActivityTimeline::forModel(Order::class)
->label('commande')
->titleUsing(fn (Order $order): string => $order->number)
->attributeLabel('customer_id', 'Client')
->eventSentence(
'status_changed',
':causer a changé le statut de :subject.',
);
Le registre accepte les icônes, couleurs, titres métier, formats d’attributs et phrases par événement. Une configuration locale sur une timeline peut compléter ou remplacer ces valeurs.
Affichage des changements
Les helpers de présentation couvrent les formats courants :
use LaBoiteACode\FilamentActivityTimeline\Presentation\AttributePresentation;
AttributePresentation::make('Actif')->boolean();
AttributePresentation::make('Échéance')->date();
AttributePresentation::make('Publié le')->dateTime();
AttributePresentation::make('Montant')->money('EUR');
AttributePresentation::make('Statut')->enum(OrderStatus::class);
AttributePresentation::make('Client')
->relationship('customer', titleAttribute: 'name');
AttributePresentation::make('Clé API')->redacted();
Les valeurs nulles, vides et booléennes sont localisées. Les longues chaînes sont tronquées et les attributs sensibles sont cachés par défaut.
Pour préserver un titre après suppression, stockez un snapshot dans les propriétés de l’activité :
'presentation' => [
'subject_title' => 'CMD-2026-0184',
'attributes' => [
'customer_id' => [
'old_label' => 'ACME France',
'new_label' => 'Dupont Conseil',
],
],
],
Filtres et pagination
Activez les onglets de filtre avec ->filters(). Une liste explicite permet de ne proposer que certains événements :
Timeline::make()
->filters(['created', 'updated'])
->limit(15)
->loadMore();
Le filtrage est appliqué à la requête de la source. Le chargement progressif conserve les éléments déjà rendus et utilise la pagination par curseur lorsque celle-ci est disponible.
Configuration
Publiez la configuration pour régler la source par défaut, la pagination, les événements, les attributs masqués, le fuseau horaire ou le mode diagnostic :
php artisan vendor:publish --tag="filament-activity-timeline-config"
Le mode debugPresentation() explique comment un libellé, un titre ou un format a été résolu. Gardez-le désactivé en production.
Une source personnalisée peut être enregistrée pour lire un stockage différent de Spatie :
ActivityTimeline::source('custom', fn () => app(CustomActivitySource::class));
Thème et traductions
Les sections, onglets, badges, avatars, boutons et états vides sont des composants Filament natifs. Le rail, les points et les puces de changement réutilisent les variables de couleur du panel : thèmes personnalisés et mode sombre sont pris en charge sans configuration.
Les traductions françaises et anglaises sont incluses. Publiez-les pour adapter les textes partagés :
php artisan vendor:publish --tag="filament-activity-timeline-translations"