From f7e3d1ff7a7f5dd5026241ad98c2ad56bc3fed02 Mon Sep 17 00:00:00 2001 From: Thomas Wijnands Date: Mon, 6 Oct 2025 20:24:57 +0200 Subject: [PATCH] feat: upgrade filament to v4 --- composer.json | 2 +- src/Actions/ActivitylogAction.php | 4 +- src/AttributeTable/Attribute.php | 28 +++----- src/AttributeTable/Builder.php | 21 +++--- .../Contracts/ValueFormatter.php | 3 +- .../LabelProviders/BaseLabelProvider.php | 19 ++++++ .../LabelProviders/HeadlineProvider.php | 3 +- .../LabelProviders/ModelSpecificProvider.php | 2 +- .../ValueFormatters/BaseValueFormatter.php | 19 ++++++ .../BelongsToRelationFormatter.php | 6 +- .../ValueFormatters/BoolFormatter.php | 6 +- .../ValueFormatters/DateCastFormatter.php | 26 +++++-- .../ValueFormatters/DateTimeCastFormatter.php | 26 +++++-- .../ValueFormatters/EmptyFormatter.php | 6 +- .../ValueFormatters/HasLabelFormatter.php | 6 +- .../ValueFormatters/HasValueFormatter.php | 6 +- .../ValueFormatters/HtmlableFormatter.php | 19 ++++++ .../ValueFormatters/JsonFormatter.php | 6 +- .../ValueFormatters/ModelFormatter.php | 6 +- .../ModelSpecificFormatter.php | 5 +- .../ValueFormatters/NullFormatter.php | 6 +- .../ValueFormatters/ScalarFormatter.php | 6 +- .../ValueFormatters/StringableFormatter.php | 6 +- src/EntryContent/Contracts/ViewResolver.php | 3 +- src/EntryContent/EntryContent.php | 6 ++ src/EntryContent/EntryContentManager.php | 15 ++-- .../ViewResolver/EventViewResolver.php | 4 +- src/FilamentActivitylogServiceProvider.php | 34 ++++++---- src/Livewire/Activitylog.php | 45 +++++++----- src/Tables/Actions/ActivitylogAction.php | 68 ------------------- tests/AttributeTableFormatterTest.php | 10 +-- tests/Models/ModelWithCastsRelations.php | 11 +-- tests/Models/ModelWithLabel.php | 3 +- tests/Models/ModelWithValue.php | 3 +- tests/TestCase.php | 3 +- .../ModelWithCastsRelationsFactory.php | 2 +- .../factories/ModelWithLabelFactory.php | 2 +- .../factories/ModelWithValueFactory.php | 2 +- 38 files changed, 237 insertions(+), 211 deletions(-) create mode 100644 src/AttributeTable/LabelProviders/BaseLabelProvider.php create mode 100644 src/AttributeTable/ValueFormatters/BaseValueFormatter.php create mode 100644 src/AttributeTable/ValueFormatters/HtmlableFormatter.php delete mode 100644 src/Tables/Actions/ActivitylogAction.php diff --git a/composer.json b/composer.json index 392f787..cbb097c 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ ], "require": { "php": "^8.1", - "filament/filament": "^3.0", + "filament/filament": "^4.0", "spatie/laravel-activitylog": "^4.10", "spatie/laravel-package-tools": "^1.15.0" }, diff --git a/src/Actions/ActivitylogAction.php b/src/Actions/ActivitylogAction.php index 6222131..8ff0512 100644 --- a/src/Actions/ActivitylogAction.php +++ b/src/Actions/ActivitylogAction.php @@ -4,7 +4,7 @@ use Closure; use Filament\Actions\Action; -use Filament\Support\Enums\MaxWidth; +use Filament\Support\Enums\Width; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Database\Eloquent\Model; use Illuminate\View\View; @@ -61,7 +61,7 @@ protected function setUp(): void 'enableComments' => $this->getEnableComments(), ])) ->modalHeading(__('filament-activitylog::activitylog.action.heading')) - ->modalWidth(MaxWidth::ScreenSmall) + ->modalWidth(Width::ScreenSmall) ->modalSubmitAction(false) ->modalCancelAction(false); } diff --git a/src/AttributeTable/Attribute.php b/src/AttributeTable/Attribute.php index 353183f..00fac3b 100644 --- a/src/AttributeTable/Attribute.php +++ b/src/AttributeTable/Attribute.php @@ -2,6 +2,7 @@ namespace Swis\Filament\Activitylog\AttributeTable; +use Illuminate\Contracts\Support\Htmlable; use Stringable; /** @phpstan-consistent-constructor */ @@ -9,26 +10,20 @@ class Attribute { protected string $key; - /** - * @var string|Stringable - */ - protected $value; + protected string | Htmlable | Stringable $value; - /** - * @var string|Stringable|null - */ - protected $oldValue = null; + protected null | string | Htmlable | Stringable $oldValue = null; protected string $label; - public function __construct(string $key, string | Stringable $value, string $label) + public function __construct(string $key, string | Htmlable | Stringable $value, string $label) { $this->key = $key; $this->value = $value; $this->label = $label; } - public static function make(string $key, string | Stringable $value, string $label): static + public static function make(string $key, string | Htmlable | Stringable $value, string $label): static { return new static($key, $value, $label); } @@ -38,27 +33,20 @@ public function getKey(): string return $this->key; } - /** - * @return string|Stringable - */ - public function getValue(): mixed + public function getValue(): string | Htmlable | Stringable { return $this->value; } - /** - * @return string|Stringable|null - */ - public function getOldValue() + public function getOldValue(): null | string | Htmlable | Stringable { return $this->oldValue; } /** - * @param string|Stringable $oldValue * @return $this */ - public function withOldValue($oldValue): static + public function withOldValue(null | string | Htmlable | Stringable $oldValue): static { $this->oldValue = $oldValue; diff --git a/src/AttributeTable/Builder.php b/src/AttributeTable/Builder.php index 66fbefb..74f0e85 100644 --- a/src/AttributeTable/Builder.php +++ b/src/AttributeTable/Builder.php @@ -3,6 +3,7 @@ namespace Swis\Filament\Activitylog\AttributeTable; use Closure; +use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Collection; use Stringable; use Swis\Filament\Activitylog\AttributeTable\Contracts\LabelProvider; @@ -13,22 +14,22 @@ class Builder { /** - * @var array> + * @var array> */ protected array $valueFormatters = []; /** - * @var array|null + * @var array|null */ protected ?array $sortedValueFormatters = null; /** - * @var array> + * @var array> */ protected array $labelProviders = []; /** - * @var array|null + * @var array|null */ protected ?array $sortedLabelProviders = null; @@ -74,7 +75,7 @@ public function registerValueFormatter(Closure | ValueFormatter $valueFormatter, /** * Get the registered value formatters in order of priority. * - * @return array + * @return array */ protected function getSortedValueFormatters(): array { @@ -98,13 +99,13 @@ protected function getSortedValueFormatters(): array * * @param array $attributes */ - protected function executeValueFormatter(Closure | ValueFormatter $valueFormatter, mixed $value, string $key, array $attributes, string $recordClass): null | Stringable | string + protected function executeValueFormatter(Closure | ValueFormatter $valueFormatter, mixed $value, string $key, array $attributes, string $recordClass): null | Htmlable | Stringable | string { if ($valueFormatter instanceof ValueFormatter) { return $valueFormatter->formatAttributeTableValue($this, $value, $key, $attributes, $recordClass); } - /** @var null | Stringable | string $result */ + /** @var null | Htmlable | Stringable | string $result */ $result = app()->call($valueFormatter, [ 'builder' => $this, 'value' => $value, @@ -124,7 +125,7 @@ protected function executeValueFormatter(Closure | ValueFormatter $valueFormatte * * @param array $attributes */ - public function formatValue(mixed $value, string $key, array $attributes, string $recordClass): Stringable | string + public function formatValue(mixed $value, string $key, array $attributes, string $recordClass): Htmlable | Stringable | string { foreach ($this->getSortedValueFormatters() as $formatter) { $formattedValue = $this->executeValueFormatter($formatter, $value, $key, $attributes, $recordClass); @@ -168,7 +169,7 @@ public function registerLabelProvider(Closure | LabelProvider $labelProvider, in /** * Get the registered label providers in order of priority. * - * @return array + * @return array */ protected function getSortedLabelProviders(): array { @@ -228,7 +229,7 @@ public function getLabel(string $key, string $recordClass): string * * @param array $newAttributes * @param ?array $oldAttributes - * @return \Illuminate\Support\Collection + * @return Collection */ public function buildAttributes(string $recordClass, array $newAttributes, ?array $oldAttributes = null): Collection { diff --git a/src/AttributeTable/Contracts/ValueFormatter.php b/src/AttributeTable/Contracts/ValueFormatter.php index 7ef9999..050a7da 100644 --- a/src/AttributeTable/Contracts/ValueFormatter.php +++ b/src/AttributeTable/Contracts/ValueFormatter.php @@ -2,6 +2,7 @@ namespace Swis\Filament\Activitylog\AttributeTable\Contracts; +use Illuminate\Contracts\Support\Htmlable; use Stringable; use Swis\Filament\Activitylog\AttributeTable\Builder; @@ -10,5 +11,5 @@ interface ValueFormatter /** * @param array $attributes */ - public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Stringable | string | null; + public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Htmlable | Stringable | string | null; } diff --git a/src/AttributeTable/LabelProviders/BaseLabelProvider.php b/src/AttributeTable/LabelProviders/BaseLabelProvider.php new file mode 100644 index 0000000..355e7ad --- /dev/null +++ b/src/AttributeTable/LabelProviders/BaseLabelProvider.php @@ -0,0 +1,19 @@ +configure(); + + return $static; + } +} diff --git a/src/AttributeTable/LabelProviders/HeadlineProvider.php b/src/AttributeTable/LabelProviders/HeadlineProvider.php index e4425bb..d50352b 100644 --- a/src/AttributeTable/LabelProviders/HeadlineProvider.php +++ b/src/AttributeTable/LabelProviders/HeadlineProvider.php @@ -3,9 +3,8 @@ namespace Swis\Filament\Activitylog\AttributeTable\LabelProviders; use Illuminate\Support\Str; -use Swis\Filament\Activitylog\AttributeTable\Contracts\LabelProvider; -class HeadlineProvider implements LabelProvider +class HeadlineProvider extends BaseLabelProvider { public function getAttributeTableLabel(string $key, string $recordClass): ?string { diff --git a/src/AttributeTable/LabelProviders/ModelSpecificProvider.php b/src/AttributeTable/LabelProviders/ModelSpecificProvider.php index d8033b3..50336f6 100644 --- a/src/AttributeTable/LabelProviders/ModelSpecificProvider.php +++ b/src/AttributeTable/LabelProviders/ModelSpecificProvider.php @@ -4,7 +4,7 @@ use Swis\Filament\Activitylog\AttributeTable\Contracts\LabelProvider; -class ModelSpecificProvider implements LabelProvider +class ModelSpecificProvider extends BaseLabelProvider { public function getAttributeTableLabel(string $key, string $recordClass): ?string { diff --git a/src/AttributeTable/ValueFormatters/BaseValueFormatter.php b/src/AttributeTable/ValueFormatters/BaseValueFormatter.php new file mode 100644 index 0000000..8697253 --- /dev/null +++ b/src/AttributeTable/ValueFormatters/BaseValueFormatter.php @@ -0,0 +1,19 @@ +configure(); + + return $static; + } +} diff --git a/src/AttributeTable/ValueFormatters/BelongsToRelationFormatter.php b/src/AttributeTable/ValueFormatters/BelongsToRelationFormatter.php index 8bd31ac..948fdd7 100644 --- a/src/AttributeTable/ValueFormatters/BelongsToRelationFormatter.php +++ b/src/AttributeTable/ValueFormatters/BelongsToRelationFormatter.php @@ -2,15 +2,15 @@ namespace Swis\Filament\Activitylog\AttributeTable\ValueFormatters; +use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\Relation; use Stringable; use Swis\Filament\Activitylog\AttributeTable\Builder; use Swis\Filament\Activitylog\AttributeTable\Contracts\ModelRelationFinder; -use Swis\Filament\Activitylog\AttributeTable\Contracts\ValueFormatter; -class BelongsToRelationFormatter implements ValueFormatter +class BelongsToRelationFormatter extends BaseValueFormatter { protected ModelRelationFinder $modelRelationFinder; @@ -19,7 +19,7 @@ public function __construct(ModelRelationFinder $modelRelationFinder) $this->modelRelationFinder = $modelRelationFinder; } - public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Stringable | string | null + public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Htmlable | Stringable | string | null { if (empty($value) || ! is_scalar($value)) { return null; diff --git a/src/AttributeTable/ValueFormatters/BoolFormatter.php b/src/AttributeTable/ValueFormatters/BoolFormatter.php index cb626db..b12cd6a 100644 --- a/src/AttributeTable/ValueFormatters/BoolFormatter.php +++ b/src/AttributeTable/ValueFormatters/BoolFormatter.php @@ -2,13 +2,13 @@ namespace Swis\Filament\Activitylog\AttributeTable\ValueFormatters; +use Illuminate\Contracts\Support\Htmlable; use Stringable; use Swis\Filament\Activitylog\AttributeTable\Builder; -use Swis\Filament\Activitylog\AttributeTable\Contracts\ValueFormatter; -class BoolFormatter implements ValueFormatter +class BoolFormatter extends BaseValueFormatter { - public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Stringable | string | null + public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Htmlable | Stringable | string | null { if (! is_bool($value)) { return null; diff --git a/src/AttributeTable/ValueFormatters/DateCastFormatter.php b/src/AttributeTable/ValueFormatters/DateCastFormatter.php index 6130c31..e185ed1 100644 --- a/src/AttributeTable/ValueFormatters/DateCastFormatter.php +++ b/src/AttributeTable/ValueFormatters/DateCastFormatter.php @@ -3,16 +3,30 @@ namespace Swis\Filament\Activitylog\AttributeTable\ValueFormatters; use Carbon\CarbonImmutable; +use Closure; use DateTimeInterface; -use Filament\Tables\Table; +use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Model; use Stringable; use Swis\Filament\Activitylog\AttributeTable\Builder; -use Swis\Filament\Activitylog\AttributeTable\Contracts\ValueFormatter; -class DateCastFormatter implements ValueFormatter +class DateCastFormatter extends BaseValueFormatter { - public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Stringable | string | null + protected string | Closure $dateDisplayFormat = 'M j, Y'; + + public function dateDisplayFormat(string | Closure $format): static + { + $this->dateDisplayFormat = $format; + + return $this; + } + + public function getDateDisplayFormat(): string + { + return $this->evaluate($this->dateDisplayFormat); + } + + public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Htmlable | Stringable | string | null { if (! is_a($recordClass, Model::class, true)) { return null; @@ -29,11 +43,11 @@ public function formatAttributeTableValue(Builder $builder, mixed $value, string } if ($value instanceof DateTimeInterface) { - return CarbonImmutable::instance($value)->format(Table::$defaultDateDisplayFormat); + return CarbonImmutable::instance($value)->format($this->getDateDisplayFormat()); } if (is_string($value) || is_int($value) || is_float($value)) { - return CarbonImmutable::parse($value)->format(Table::$defaultDateDisplayFormat); + return CarbonImmutable::parse($value)->format($this->getDateDisplayFormat()); } return null; diff --git a/src/AttributeTable/ValueFormatters/DateTimeCastFormatter.php b/src/AttributeTable/ValueFormatters/DateTimeCastFormatter.php index 9db73a7..cd03916 100644 --- a/src/AttributeTable/ValueFormatters/DateTimeCastFormatter.php +++ b/src/AttributeTable/ValueFormatters/DateTimeCastFormatter.php @@ -3,16 +3,30 @@ namespace Swis\Filament\Activitylog\AttributeTable\ValueFormatters; use Carbon\CarbonImmutable; +use Closure; use DateTimeInterface; -use Filament\Tables\Table; +use Illuminate\Contracts\Support\Htmlable; use Illuminate\Database\Eloquent\Model; use Stringable; use Swis\Filament\Activitylog\AttributeTable\Builder; -use Swis\Filament\Activitylog\AttributeTable\Contracts\ValueFormatter; -class DateTimeCastFormatter implements ValueFormatter +class DateTimeCastFormatter extends BaseValueFormatter { - public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Stringable | string | null + protected string | Closure $dateTimeDisplayFormat = 'M j, Y H:i:s'; + + public function dateTimeDisplayFormat(string | Closure $format): static + { + $this->dateTimeDisplayFormat = $format; + + return $this; + } + + public function getDateTimeDisplayFormat(): string + { + return $this->evaluate($this->dateTimeDisplayFormat); + } + + public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Htmlable | Stringable | string | null { if (! is_a($recordClass, Model::class, true)) { return null; @@ -29,11 +43,11 @@ public function formatAttributeTableValue(Builder $builder, mixed $value, string } if ($value instanceof DateTimeInterface) { - return CarbonImmutable::instance($value)->format(Table::$defaultDateTimeDisplayFormat); + return CarbonImmutable::instance($value)->format($this->getDateTimeDisplayFormat()); } if (is_string($value) || is_int($value) || is_float($value)) { - return CarbonImmutable::parse($value)->format(Table::$defaultDateTimeDisplayFormat); + return CarbonImmutable::parse($value)->format($this->getDateTimeDisplayFormat()); } return null; diff --git a/src/AttributeTable/ValueFormatters/EmptyFormatter.php b/src/AttributeTable/ValueFormatters/EmptyFormatter.php index 05af4c1..71974d0 100644 --- a/src/AttributeTable/ValueFormatters/EmptyFormatter.php +++ b/src/AttributeTable/ValueFormatters/EmptyFormatter.php @@ -2,13 +2,13 @@ namespace Swis\Filament\Activitylog\AttributeTable\ValueFormatters; +use Illuminate\Contracts\Support\Htmlable; use Stringable; use Swis\Filament\Activitylog\AttributeTable\Builder; -use Swis\Filament\Activitylog\AttributeTable\Contracts\ValueFormatter; -class EmptyFormatter implements ValueFormatter +class EmptyFormatter extends BaseValueFormatter { - public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Stringable | string | null + public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Htmlable | Stringable | string | null { if ($value !== '') { return null; diff --git a/src/AttributeTable/ValueFormatters/HasLabelFormatter.php b/src/AttributeTable/ValueFormatters/HasLabelFormatter.php index 33f19ac..df7f1fb 100644 --- a/src/AttributeTable/ValueFormatters/HasLabelFormatter.php +++ b/src/AttributeTable/ValueFormatters/HasLabelFormatter.php @@ -3,13 +3,13 @@ namespace Swis\Filament\Activitylog\AttributeTable\ValueFormatters; use Filament\Support\Contracts\HasLabel; +use Illuminate\Contracts\Support\Htmlable; use Stringable; use Swis\Filament\Activitylog\AttributeTable\Builder; -use Swis\Filament\Activitylog\AttributeTable\Contracts\ValueFormatter; -class HasLabelFormatter implements ValueFormatter +class HasLabelFormatter extends BaseValueFormatter { - public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Stringable | string | null + public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Htmlable | Stringable | string | null { if (! $value instanceof HasLabel) { return null; diff --git a/src/AttributeTable/ValueFormatters/HasValueFormatter.php b/src/AttributeTable/ValueFormatters/HasValueFormatter.php index 8a36118..99fd07a 100644 --- a/src/AttributeTable/ValueFormatters/HasValueFormatter.php +++ b/src/AttributeTable/ValueFormatters/HasValueFormatter.php @@ -2,14 +2,14 @@ namespace Swis\Filament\Activitylog\AttributeTable\ValueFormatters; +use Illuminate\Contracts\Support\Htmlable; use Stringable; use Swis\Filament\Activitylog\AttributeTable\Builder; use Swis\Filament\Activitylog\AttributeTable\Contracts\HasValue; -use Swis\Filament\Activitylog\AttributeTable\Contracts\ValueFormatter; -class HasValueFormatter implements ValueFormatter +class HasValueFormatter extends BaseValueFormatter { - public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Stringable | string | null + public function formatAttributeTableValue(Builder $builder, mixed $value, string $key, array $attributes, string $recordClass): Htmlable | Stringable | string | null { if (! $value instanceof HasValue) { return null; diff --git a/src/AttributeTable/ValueFormatters/HtmlableFormatter.php b/src/AttributeTable/ValueFormatters/HtmlableFormatter.php new file mode 100644 index 0000000..c3e3e41 --- /dev/null +++ b/src/AttributeTable/ValueFormatters/HtmlableFormatter.php @@ -0,0 +1,19 @@ +getRecord(); + if (! $record instanceof Activity) { + throw new Exception('Record should be an instance of ' . Activity::class); + } + return $this->manager->resolveView($record); } diff --git a/src/EntryContent/EntryContentManager.php b/src/EntryContent/EntryContentManager.php index 2177aee..fb21892 100644 --- a/src/EntryContent/EntryContentManager.php +++ b/src/EntryContent/EntryContentManager.php @@ -5,7 +5,6 @@ use Closure; use Exception; use Illuminate\Database\Eloquent\Model; -use InvalidArgumentException; use Spatie\Activitylog\Contracts\Activity; use Swis\Filament\Activitylog\EntryContent\Contracts\ViewResolver; use Swis\Filament\Activitylog\EntryContent\ViewResolver\EventViewResolver; @@ -13,12 +12,12 @@ class EntryContentManager { /** - * @var array> + * @var array> */ protected array $viewResolvers = []; /** - * @var array + * @var array */ protected ?array $sortedViewResolvers = null; @@ -53,7 +52,7 @@ public function registerEventViewResolver(string $event, string $view, int $prio /** * Get the registered value formatters in order of priority. * - * @return array + * @return array */ protected function getSortedViewResolvers(): array { @@ -75,7 +74,7 @@ protected function getSortedViewResolvers(): array /** * Execute a view resolver. */ - protected function executeViewResolver(Closure | ViewResolver $resolver, Activity & Model $activity): ?string + protected function executeViewResolver(Closure | ViewResolver $resolver, Activity $activity): ?string { if ($resolver instanceof ViewResolver) { return $resolver->resolveActivityView($activity); @@ -89,12 +88,8 @@ protected function executeViewResolver(Closure | ViewResolver $resolver, Activit return $result; } - public function resolveView(?Model $activity): string + public function resolveView(Activity $activity): string { - if (! $activity instanceof Activity) { - throw new InvalidArgumentException('The activity must be an instance of ' . Activity::class); - } - foreach ($this->getSortedViewResolvers() as $resolver) { if ($view = $this->executeViewResolver($resolver, $activity)) { return $view; diff --git a/src/EntryContent/ViewResolver/EventViewResolver.php b/src/EntryContent/ViewResolver/EventViewResolver.php index 5f37670..4dbfba7 100644 --- a/src/EntryContent/ViewResolver/EventViewResolver.php +++ b/src/EntryContent/ViewResolver/EventViewResolver.php @@ -18,9 +18,9 @@ public function __construct(string $event, string $view) $this->view = $view; } - public function resolveActivityView(Model & Activity $activity): ?string + public function resolveActivityView(Activity $activity): ?string { - if (isset($activity->event) && $activity->event === $this->event) { + if ($activity instanceof Model && isset($activity->event) && $activity->event === $this->event) { return $this->view; } diff --git a/src/FilamentActivitylogServiceProvider.php b/src/FilamentActivitylogServiceProvider.php index cb41ce5..f74baad 100644 --- a/src/FilamentActivitylogServiceProvider.php +++ b/src/FilamentActivitylogServiceProvider.php @@ -42,31 +42,35 @@ public function packageRegistered(): void app()->afterResolving(AttributeTableBuilder::class, function (AttributeTableBuilder $builder) { // Model specific value formatters - $builder->registerValueFormatter(app(ValueFormatters\ModelSpecificFormatter::class), 256); + $builder->registerValueFormatter(ValueFormatters\ModelSpecificFormatter::make(), 256); // Formatter for specific interfaces and objects - $builder->registerValueFormatter(app(ValueFormatters\HasValueFormatter::class), -10); - $builder->registerValueFormatter(app(ValueFormatters\HasLabelFormatter::class), -10); - $builder->registerValueFormatter(app(ValueFormatters\ModelFormatter::class), -10); + $builder->registerValueFormatter(ValueFormatters\HasValueFormatter::make(), -10); + $builder->registerValueFormatter(ValueFormatters\HasLabelFormatter::make(), -10); + $builder->registerValueFormatter(ValueFormatters\ModelFormatter::make(), -10); // Formatters for casts and relations - $builder->registerValueFormatter(app(ValueFormatters\DateCastFormatter::class), -25); - $builder->registerValueFormatter(app(ValueFormatters\DateTimeCastFormatter::class), -25); - $builder->registerValueFormatter(app(ValueFormatters\BelongsToRelationFormatter::class), -25); + $builder->registerValueFormatter(ValueFormatters\DateCastFormatter::make(), -25); + $builder->registerValueFormatter(ValueFormatters\DateTimeCastFormatter::make(), -25); + $builder->registerValueFormatter(ValueFormatters\BelongsToRelationFormatter::make(), -25); + + // Formatters for generic interfaces + $builder->registerValueFormatter(ValueFormatters\HtmlableFormatter::make(), -49); + $builder->registerValueFormatter(ValueFormatters\StringableFormatter::make(), -50); // Simple formatters for scalar values - $builder->registerValueFormatter(app(ValueFormatters\NullFormatter::class), -50); - $builder->registerValueFormatter(app(ValueFormatters\BoolFormatter::class), -50); - $builder->registerValueFormatter(app(ValueFormatters\EmptyFormatter::class), -50); - $builder->registerValueFormatter(app(ValueFormatters\ScalarFormatter::class), -50); - $builder->registerValueFormatter(app(ValueFormatters\StringableFormatter::class), -50); + $builder->registerValueFormatter(ValueFormatters\NullFormatter::make(), -75); + $builder->registerValueFormatter(ValueFormatters\BoolFormatter::make(), -75); + $builder->registerValueFormatter(ValueFormatters\EmptyFormatter::make(), -75); + $builder->registerValueFormatter(ValueFormatters\ScalarFormatter::make(), -75); + $builder->registerValueFormatter(ValueFormatters\StringableFormatter::make(), -75); // Fallback formatters for objects and arrays - $builder->registerValueFormatter(app(ValueFormatters\JsonFormatter::class), -100); + $builder->registerValueFormatter(ValueFormatters\JsonFormatter::make(), -100); // Label providers - $builder->registerLabelProvider(app(LabelProviders\ModelSpecificProvider::class), 256); - $builder->registerLabelProvider(app(LabelProviders\HeadlineProvider::class), -100); + $builder->registerLabelProvider(LabelProviders\ModelSpecificProvider::make(), 256); + $builder->registerLabelProvider(LabelProviders\HeadlineProvider::make(), -100); }); app()->afterResolving(EntryContentManager::class, function (EntryContentManager $manager) { diff --git a/src/Livewire/Activitylog.php b/src/Livewire/Activitylog.php index 280eb07..edd9ce2 100644 --- a/src/Livewire/Activitylog.php +++ b/src/Livewire/Activitylog.php @@ -3,13 +3,18 @@ namespace Swis\Filament\Activitylog\Livewire; use Carbon\Carbon; -use Filament\Actions; +use Filament\Actions\Concerns\InteractsWithActions; use Filament\Facades\Filament; -use Filament\Forms; -use Filament\Forms\Form; -use Filament\Pages; +use Filament\Forms\Components\MarkdownEditor; +use Filament\Forms\Concerns\InteractsWithForms; +use Filament\Forms\Contracts\HasForms; +use Filament\Pages\Concerns\InteractsWithFormActions; +use Filament\Schemas\Schema; use Filament\Support\Enums\FontWeight; -use Filament\Tables; +use Filament\Tables\Columns\Layout\Stack; +use Filament\Tables\Columns\TextColumn; +use Filament\Tables\Concerns\InteractsWithTable; +use Filament\Tables\Contracts\HasTable; use Filament\Tables\Table; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Contracts\View\View; @@ -22,12 +27,12 @@ use function Filament\authorize; -class Activitylog extends Component implements Forms\Contracts\HasForms, Tables\Contracts\HasTable +class Activitylog extends Component implements HasForms, HasTable { - use Actions\Concerns\InteractsWithActions; - use Forms\Concerns\InteractsWithForms; - use Pages\Concerns\InteractsWithFormActions; - use Tables\Concerns\InteractsWithTable; + use InteractsWithActions; + use InteractsWithFormActions; + use InteractsWithForms; + use InteractsWithTable; #[Locked] public Model $record; @@ -37,10 +42,10 @@ class Activitylog extends Component implements Forms\Contracts\HasForms, Tables\ public string $comment = ''; - public function form(Form $form): Form + public function form(Schema $schema): Schema { - return $form->schema([ - Forms\Components\MarkdownEditor::make('comment') + return $schema->components([ + MarkdownEditor::make('comment') ->label(__('filament-activitylog::activitylog.form.fields.comment.label')) ->helperText(__('filament-activitylog::activitylog.form.fields.comment.helper_text')), ]); @@ -88,8 +93,8 @@ public function table(Table $table): Table ->with(['subject', 'causer']) ) ->columns([ - Tables\Columns\Layout\Stack::make([ - Tables\Columns\TextColumn::make('causer') + Stack::make([ + TextColumn::make('causer') ->formatStateUsing(function ($state) use ($modelClass) { if ($state === null) { return null; @@ -98,11 +103,15 @@ public function table(Table $table): Table return FilamentActivitylog::attributeTableBuilder()->formatValue($state, 'causer', [], $modelClass); }) ->weight(FontWeight::SemiBold), - Tables\Columns\TextColumn::make('created_at') + TextColumn::make('created_at') ->since() ->inline() - ->tooltip(function ($state) { - return Carbon::parse($state)->format(Table::$defaultDateTimeDisplayFormat); + ->tooltip(function ($state, Table $table) { + if (! is_string($table->getDefaultDateTimeDisplayFormat())) { + return null; + } + + return Carbon::parse($state)->format($table->getDefaultDateTimeDisplayFormat()); }) ->color('gray') ->sortable(), diff --git a/src/Tables/Actions/ActivitylogAction.php b/src/Tables/Actions/ActivitylogAction.php deleted file mode 100644 index 599ee4a..0000000 --- a/src/Tables/Actions/ActivitylogAction.php +++ /dev/null @@ -1,68 +0,0 @@ -enableComments = $enableComments; - - return $this; - } - - public function disableComments(Closure | bool $disableComments = true): self - { - if (is_bool($disableComments)) { - return $this->enableComments(! $disableComments); - } - - return $this->enableComments(fn () => ! $this->evaluate($disableComments)); - } - - public function getEnableComments(): bool - { - return (bool) $this->evaluate($this->enableComments); - } - - protected function setUp(): void - { - parent::setUp(); - - $this - ->authorize(function ($record) { - try { - return authorize('viewActivitylog', $record)->allowed(); - } catch (AuthorizationException $exception) { - return $exception->toResponse()->allowed(); - } - }) - ->icon('heroicon-o-chat-bubble-bottom-center-text') - ->label(__('filament-activitylog::activitylog.action.label')) - ->slideOver() - ->modalContent(fn (Model $record): View => view('filament-activitylog::modal-content', [ - 'record' => $record, - 'enableComments' => $this->getEnableComments(), - ])) - ->modalHeading(__('filament-activitylog::activitylog.action.heading')) - ->modalWidth(MaxWidth::ScreenSmall) - ->modalSubmitAction(false) - ->modalCancelAction(false); - } -} diff --git a/tests/AttributeTableFormatterTest.php b/tests/AttributeTableFormatterTest.php index 4c6f299..edff0f1 100644 --- a/tests/AttributeTableFormatterTest.php +++ b/tests/AttributeTableFormatterTest.php @@ -1,6 +1,8 @@ create(['name' => 'foo']); - /** @var \Illuminate\Support\HtmlString $value */ + /** @var HtmlString $value */ $value = app(Builder::class)->formatValue($obj, 'property', [], ModelWithCastsRelations::class); expect($value->toHtml())->toBe('foo'); @@ -165,9 +167,9 @@ $attributes = app(Builder::class)->buildAttributes(ModelWithCastsRelations::class, $newAttributes, $oldAttributes); - expect($attributes)->toBeInstanceOf(\Illuminate\Support\Collection::class) + expect($attributes)->toBeInstanceOf(Collection::class) ->and($attributes->count())->toBe(1) - ->and($attributes->first())->toEqual(\Swis\Filament\Activitylog\AttributeTable\Attribute::make('property', 'foo', 'Property')->withOldValue('bar')); + ->and($attributes->first())->toEqual(Attribute::make('property', 'foo', 'Property')->withOldValue('bar')); }); it('skips attributes', function () { @@ -183,7 +185,7 @@ $attributes = app(Builder::class)->buildAttributes(ModelWithCastsRelations::class, $newAttributes, $oldAttributes); - expect($attributes)->toBeInstanceOf(\Illuminate\Support\Collection::class) + expect($attributes)->toBeInstanceOf(Collection::class) ->and($attributes->count())->toBe(1) ->and($attributes->first()?->getKey())->toBe('property'); }); diff --git a/tests/Models/ModelWithCastsRelations.php b/tests/Models/ModelWithCastsRelations.php index 54ae799..ee87534 100644 --- a/tests/Models/ModelWithCastsRelations.php +++ b/tests/Models/ModelWithCastsRelations.php @@ -10,6 +10,7 @@ use Swis\Filament\Activitylog\AttributeTable\Builder; use Swis\Filament\Activitylog\AttributeTable\Contracts\SkipsAttributes; use Swis\Filament\Activitylog\AttributeTable\Contracts\ValueFormatter; +use Swis\Filament\Activitylog\Tests\Database\Factories\ModelWithCastsRelationsFactory; /** * @property int $id @@ -17,7 +18,7 @@ */ class ModelWithCastsRelations extends Model implements SkipsAttributes, ValueFormatter { - /** @use \Illuminate\Database\Eloquent\Factories\HasFactory<\Swis\Filament\Activitylog\Tests\Database\Factories\ModelWithCastsRelationsFactory> */ + /** @use HasFactory */ use HasFactory; protected $table = 'models_with_casts_relations'; @@ -47,7 +48,7 @@ public function formatAttributeTableValue(Builder $builder, mixed $value, string } /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\Swis\Filament\Activitylog\Tests\Models\ModelWithLabel, $this> + * @return BelongsTo */ public function modelWithLabel(): BelongsTo { @@ -55,7 +56,7 @@ public function modelWithLabel(): BelongsTo } /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\Swis\Filament\Activitylog\Tests\Models\ModelWithLabel, $this> + * @return BelongsTo */ public function customBelongsToRelation(): BelongsTo { @@ -63,7 +64,7 @@ public function customBelongsToRelation(): BelongsTo } /** - * @return \Illuminate\Database\Eloquent\Relations\MorphTo<\Illuminate\Database\Eloquent\Model, $this> + * @return MorphTo */ public function morphedModel(): MorphTo { @@ -71,7 +72,7 @@ public function morphedModel(): MorphTo } /** - * @return \Illuminate\Database\Eloquent\Relations\MorphTo<\Illuminate\Database\Eloquent\Model, $this> + * @return MorphTo */ public function customMorphToRelation(): MorphTo { diff --git a/tests/Models/ModelWithLabel.php b/tests/Models/ModelWithLabel.php index 9f03c81..0054f98 100644 --- a/tests/Models/ModelWithLabel.php +++ b/tests/Models/ModelWithLabel.php @@ -5,6 +5,7 @@ use Filament\Support\Contracts\HasLabel; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Swis\Filament\Activitylog\Tests\Database\Factories\ModelWithLabelFactory; /** * @property int $id @@ -12,7 +13,7 @@ */ class ModelWithLabel extends Model implements HasLabel { - /** @use \Illuminate\Database\Eloquent\Factories\HasFactory<\Swis\Filament\Activitylog\Tests\Database\Factories\ModelWithLabelFactory> */ + /** @use HasFactory */ use HasFactory; protected $table = 'models_with_label'; diff --git a/tests/Models/ModelWithValue.php b/tests/Models/ModelWithValue.php index a375f4b..dcfe608 100644 --- a/tests/Models/ModelWithValue.php +++ b/tests/Models/ModelWithValue.php @@ -7,6 +7,7 @@ use Illuminate\Support\HtmlString; use Stringable; use Swis\Filament\Activitylog\AttributeTable\Contracts\HasValue; +use Swis\Filament\Activitylog\Tests\Database\Factories\ModelWithValueFactory; /** * @property int $id @@ -14,7 +15,7 @@ */ class ModelWithValue extends Model implements HasValue { - /** @use \Illuminate\Database\Eloquent\Factories\HasFactory<\Swis\Filament\Activitylog\Tests\Database\Factories\ModelWithValueFactory> */ + /** @use HasFactory */ use HasFactory; protected $table = 'models_with_value'; diff --git a/tests/TestCase.php b/tests/TestCase.php index 51c7d71..ed49b04 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -13,6 +13,7 @@ use Filament\Tables\TablesServiceProvider; use Filament\Widgets\WidgetsServiceProvider; use Illuminate\Database\Eloquent\Factories\Factory; +use Illuminate\Database\Eloquent\Model; use Livewire\LivewireServiceProvider; use Orchestra\Testbench\TestCase as Orchestra; use RyanChandler\BladeCaptureDirective\BladeCaptureDirectiveServiceProvider; @@ -28,7 +29,7 @@ protected function setUp(): void Factory::guessFactoryNamesUsing( function (string $modelName): string { - /** @var class-string<\Illuminate\Database\Eloquent\Factories\Factory<\Illuminate\Database\Eloquent\Model>> $factory */ + /** @var class-string> $factory */ $factory = 'Swis\\Filament\\Activitylog\\Tests\\Database\\Factories\\' . class_basename($modelName) . 'Factory'; return $factory; diff --git a/tests/database/factories/ModelWithCastsRelationsFactory.php b/tests/database/factories/ModelWithCastsRelationsFactory.php index d871467..def489f 100644 --- a/tests/database/factories/ModelWithCastsRelationsFactory.php +++ b/tests/database/factories/ModelWithCastsRelationsFactory.php @@ -6,7 +6,7 @@ use Swis\Filament\Activitylog\Tests\Models\ModelWithCastsRelations; /** - * @extends \Illuminate\Database\Eloquent\Factories\Factory<\Swis\Filament\Activitylog\Tests\Models\ModelWithCastsRelations> + * @extends Factory */ class ModelWithCastsRelationsFactory extends Factory { diff --git a/tests/database/factories/ModelWithLabelFactory.php b/tests/database/factories/ModelWithLabelFactory.php index cf674a0..6853765 100644 --- a/tests/database/factories/ModelWithLabelFactory.php +++ b/tests/database/factories/ModelWithLabelFactory.php @@ -6,7 +6,7 @@ use Swis\Filament\Activitylog\Tests\Models\ModelWithLabel; /** - * @extends \Illuminate\Database\Eloquent\Factories\Factory<\Swis\Filament\Activitylog\Tests\Models\ModelWithLabel> + * @extends Factory */ class ModelWithLabelFactory extends Factory { diff --git a/tests/database/factories/ModelWithValueFactory.php b/tests/database/factories/ModelWithValueFactory.php index 2390598..174fa66 100644 --- a/tests/database/factories/ModelWithValueFactory.php +++ b/tests/database/factories/ModelWithValueFactory.php @@ -6,7 +6,7 @@ use Swis\Filament\Activitylog\Tests\Models\ModelWithValue; /** - * @extends \Illuminate\Database\Eloquent\Factories\Factory<\Swis\Filament\Activitylog\Tests\Models\ModelWithValue> + * @extends Factory */ class ModelWithValueFactory extends Factory {