From f662ff4e4ee7b204c979e9cba4ffca44b49e1e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9ia=20Bohner?= Date: Thu, 14 Mar 2024 17:08:37 -0300 Subject: [PATCH 1/4] Add the ability to customize the presentation --- README.md | 173 +++++++++++++++++- config/filament-auditing.php | 5 + .../tables/custom-audit-content.blade.php | 1 + .../AuditsRelationManager.php | 24 ++- 4 files changed, 195 insertions(+), 8 deletions(-) create mode 100644 resources/views/tables/custom-audit-content.blade.php diff --git a/README.md b/README.md index 9ec5d23..cf4ce82 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ composer require tapp/filament-auditing:"^3.0" > **Note** > For **Filament 2.x** check the **[2.x](https://github.com//TappNetwork/filament-auditing/tree/2.x)** branch -You can publish the view file with: +You can publish the view files with: ```bash php artisan vendor:publish --tag="filament-auditing-views" @@ -63,6 +63,11 @@ return [ // ], ] + 'custom_audits_view' => false, + 'custom_old_and_new_values_column_view' => true, + + 'custom_view_parameters' => [ + ] ]; ``` @@ -113,7 +118,6 @@ return [ ]; ``` - After adding this information in the config, please run this command for changes to take place. ```bash @@ -122,6 +126,171 @@ php artisan optimize As things stand, methods with two required parameters are not supported. +### Custom View Data Formatting + +If you want to modify the content of the audit to display the old and new values in a specific way, such as showing the value of a specific column instead of the ID for relationships, or even customize the entire view to display data in a different way than the default table, you can use one of these methods (first, make sure the plugin views are published): + +#### Customizing the Old and New Values + +To customize the presentation for the old and new values, you can set the `custom_old_and_new_values_column_view` config value to `false` on `config/filament-auditing.php` file: +```php +'custom_old_and_new_values_column_view' => false, +``` + +Then add a `formatAuditFieldsForPresentation($field, $record)` method on the model that is auditable, with two parameters: +- the first parameter contains the name of the field (`old_values` or `new_values`). +- the second parameter contains de current audit record + +This method must return the formatted audit fields. + +For example, let's say you have an `Article` model that is auditable and contains a related user, and added a `formatAuditFieldsForPresentation($field, $record)` method that returns the related user name instead of the id, and the data formatted with some HTML code: + +```php +{$field}); + + $formattedResult = ''; + + return new HtmlString($formattedResult); + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } +} +``` + +#### Customizing the Entire View Content + +If you'd like to customize the entire view content, you may set the `custom_audits_view` config value to `true` on `config/filament-auditing.php` file: + +```php +'custom_audits_view' => true, +``` + +This modification will allow you to take full control of the display and tailor it to your specific requirements. You can now add your custom content on `resources/views/vendor/filament-auditing/tables/custom-audit-content.blade.php` file. For example: + +```php +@php +$type = (string) str(class_basename($owner))->lower(); +@endphp + +@if(isset($records)) + + + @foreach($headers as $header) + + {{$header}} + + @endforeach + + @foreach($records as $audit) + + @foreach ($audit->getModified() as $attribute => $modified) + + @lang($type.'.metadata', $audit->getMetadata()) +
+ @php + $current = $type.'.'.$audit->event.'.modified.'.$attribute; + + $modified['new'] = $owner->formatFieldForPresentation($attribute, $modified['new']); + + if (isset($modified['old'])) { + $modified['old'] = $owner->formatFieldForPresentation($attribute, $modified['old']); + } + @endphp + + @lang($current, $modified) +
+ @endforeach +
+ @endforeach +
+@else +
+ @lang($type.'.unavailable_audits') +
+@endif +``` + +The owner record is available to this view via `$owner` variable. To pass some additional parameters to the view, you may use the `custom_view_parameters` config: + +```php +'custom_view_parameters' => [ + 'headers' => [ + 'Audit', + ], +], +``` + +To format a field, you may also add a `formatFieldForPresentation` method on the owner model, with the field name and value as parameters, like in the example above. This method must return a formatted field. + +For example, in an `Article` model, to return the name of the related user: + +```php +public function formatFieldForPresentation($field, $value) +{ + return match($field) { + 'user_id' => $value ? optional(User::find($value))->name : $value, + default => $value, + }; +} +``` + +An example of the `article.php` lang file content used in the `custom-audit-content.blade.php` view code above: + +```php + 'No article audits available', + + 'metadata' => 'On :audit_created_at, :user_name [:audit_ip_address] :audit_event this record via :audit_url', + + 'updated' => [ + 'modified' => [ + 'order' => 'The Order has been modified from :old to :new', + 'title' => 'The Title has been modified from :old to :new', + 'content' => 'The Content has been modified from :old to :new', + 'user_id' => 'The User has been modified from :old to :new', + ], + ], +]; +``` + ### Permissions Two permissions are registered by default, allowing access to: diff --git a/config/filament-auditing.php b/config/filament-auditing.php index 9e0fa04..e3516c5 100644 --- a/config/filament-auditing.php +++ b/config/filament-auditing.php @@ -27,4 +27,9 @@ // ], ], + 'custom_audits_view' => false, + 'custom_old_and_new_values_column_view' => true, + + 'custom_view_parameters' => [ + ] ]; diff --git a/resources/views/tables/custom-audit-content.blade.php b/resources/views/tables/custom-audit-content.blade.php new file mode 100644 index 0000000..ef0e2de --- /dev/null +++ b/resources/views/tables/custom-audit-content.blade.php @@ -0,0 +1 @@ +{{-- add your custom code here --}} diff --git a/src/RelationManagers/AuditsRelationManager.php b/src/RelationManagers/AuditsRelationManager.php index d9c51ba..aa84045 100644 --- a/src/RelationManagers/AuditsRelationManager.php +++ b/src/RelationManagers/AuditsRelationManager.php @@ -3,14 +3,18 @@ namespace Tapp\FilamentAuditing\RelationManagers; use Filament\Facades\Filament; +use Filament\Forms\Components\Component; use Filament\Notifications\Notification; use Filament\Resources\RelationManagers\RelationManager; use Filament\Tables; +use Filament\Tables\Columns\Column; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Arr; +use Illuminate\View\View; +use Livewire\Component as Livewire; use OwenIt\Auditing\Contracts\Audit; class AuditsRelationManager extends RelationManager @@ -40,6 +44,7 @@ public function table(Table $table): Table { return $table ->modifyQueryUsing(fn (Builder $query) => $query->with('user')->orderBy(config('filament-auditing.audits_sort.column'), config('filament-auditing.audits_sort.direction'))) + ->content(fn (): ?View => config('filament-auditing.custom_audits_view') ? view('filament-auditing::tables.custom-audit-content', Arr::add(self::customViewParameters(), 'owner', $this->getOwnerRecord())) : null) ->columns(Arr::flatten([ Tables\Columns\TextColumn::make('user.name') ->label(trans('filament-auditing::filament-auditing.column.user_name')), @@ -48,12 +53,14 @@ public function table(Table $table): Table Tables\Columns\TextColumn::make('created_at') ->since() ->label(trans('filament-auditing::filament-auditing.column.created_at')), - Tables\Columns\ViewColumn::make('old_values') - ->view('filament-auditing::tables.columns.key-value') - ->label(trans('filament-auditing::filament-auditing.column.old_values')), - Tables\Columns\ViewColumn::make('new_values') - ->view('filament-auditing::tables.columns.key-value') - ->label(trans('filament-auditing::filament-auditing.column.new_values')), + Tables\Columns\TextColumn::make('old_values') + ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state) + ->label(trans('filament-auditing::filament-auditing.column.old_values')) + ->view(config('filament-auditing.custom_old_and_new_values_column_view') ? 'filament-auditing::tables.columns.key-value' : null), + Tables\Columns\TextColumn::make('new_values') + ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state) + ->label(trans('filament-auditing::filament-auditing.column.new_values')) + ->view(config('filament-auditing.custom_old_and_new_values_column_view') ? 'filament-auditing::tables.columns.key-value' : null), self::extraColumns(), ])) ->filters([ @@ -78,6 +85,11 @@ public function table(Table $table): Table ]); } + protected static function customViewParameters(): array + { + return config('filament-auditing.custom_view_parameters'); + } + protected static function extraColumns() { return Arr::map(config('filament-auditing.audits_extend'), function ($buildParameters, $columnName) { From c8a95ea95325a397ae316e48af218aff92f5f7ee Mon Sep 17 00:00:00 2001 From: andreia Date: Thu, 14 Mar 2024 20:09:12 +0000 Subject: [PATCH 2/4] PHP Linting (Pint) --- config/filament-auditing.php | 2 +- src/RelationManagers/AuditsRelationManager.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/config/filament-auditing.php b/config/filament-auditing.php index e3516c5..a11a85f 100644 --- a/config/filament-auditing.php +++ b/config/filament-auditing.php @@ -31,5 +31,5 @@ 'custom_old_and_new_values_column_view' => true, 'custom_view_parameters' => [ - ] + ], ]; diff --git a/src/RelationManagers/AuditsRelationManager.php b/src/RelationManagers/AuditsRelationManager.php index aa84045..d63a650 100644 --- a/src/RelationManagers/AuditsRelationManager.php +++ b/src/RelationManagers/AuditsRelationManager.php @@ -3,7 +3,6 @@ namespace Tapp\FilamentAuditing\RelationManagers; use Filament\Facades\Filament; -use Filament\Forms\Components\Component; use Filament\Notifications\Notification; use Filament\Resources\RelationManagers\RelationManager; use Filament\Tables; @@ -14,7 +13,6 @@ use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Arr; use Illuminate\View\View; -use Livewire\Component as Livewire; use OwenIt\Auditing\Contracts\Audit; class AuditsRelationManager extends RelationManager From f4c7ace4e51dcbc561ffcc77b041ad5ee7194f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9ia=20Bohner?= Date: Tue, 26 Mar 2024 14:59:36 -0300 Subject: [PATCH 3/4] Add mappging config --- README.md | 34 +++++++++---- config/filament-auditing.php | 7 ++- .../views/tables/columns/key-value.blade.php | 38 ++++++++------ .../AuditsRelationManager.php | 50 +++++++++++++++---- 4 files changed, 93 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index cf4ce82..257e9da 100644 --- a/README.md +++ b/README.md @@ -64,10 +64,12 @@ return [ ] 'custom_audits_view' => false, - 'custom_old_and_new_values_column_view' => true, 'custom_view_parameters' => [ - ] + ], + + 'mapping' => [ + ], ]; ``` @@ -128,22 +130,33 @@ As things stand, methods with two required parameters are not supported. ### Custom View Data Formatting -If you want to modify the content of the audit to display the old and new values in a specific way, such as showing the value of a specific column instead of the ID for relationships, or even customize the entire view to display data in a different way than the default table, you can use one of these methods (first, make sure the plugin views are published): +If you want to modify the content of the audit to display the old and new values in a specific way, such as showing the value of a specific column instead of the ID for relationships, or even customize the entire view to display data in a different way than the default table, you can use one of these methods described below (first, make sure the plugin views are published): -#### Customizing the Old and New Values +#### Show a related column instead of foreign id -To customize the presentation for the old and new values, you can set the `custom_old_and_new_values_column_view` config value to `false` on `config/filament-auditing.php` file: -```php -'custom_old_and_new_values_column_view' => false, +To use another field to be displayed for relationships instead of the foreign id, in old and new values, you can add on the `mapping` array, in `filament-auditing.php` config file, the label and field that should be displayed, as well as the related model, using the foreign key as the array key. For example, on an `user` relationship with the `user_id` foreing key, this config will display the user `name` along with the `User` label: + +```bash +'mapping' => [ + 'user_id' => [ + 'model' => App\Models\User::class, + 'field' => 'name', + 'label' => 'User', + ], + ], ``` -Then add a `formatAuditFieldsForPresentation($field, $record)` method on the model that is auditable, with two parameters: +And you'd like to customize the view, you can do it in the published view `views/vendor/filament-auditing/tables/columns/key-value.blade.php` file. + +#### Customizing the Old and New Values + +If you need to customize the presentation for other old and new values, besides the related fields, you can add a `formatAuditFieldsForPresentation($field, $record)` method on the model that is auditable, with two parameters: - the first parameter contains the name of the field (`old_values` or `new_values`). - the second parameter contains de current audit record This method must return the formatted audit fields. -For example, let's say you have an `Article` model that is auditable and contains a related user, and added a `formatAuditFieldsForPresentation($field, $record)` method that returns the related user name instead of the id, and the data formatted with some HTML code: +For example, let's say you have an `Article` model that is auditable and contains a related user, and you added a `formatAuditFieldsForPresentation($field, $record)` method that returns the related user name instead of the id, and the data formatted with some HTML code: ```php true, ``` -This modification will allow you to take full control of the display and tailor it to your specific requirements. You can now add your custom content on `resources/views/vendor/filament-auditing/tables/custom-audit-content.blade.php` file. For example: +This modification will allow you to take full control of the display and tailor it to your specific requirements. You can now add your custom content on `resources/views/vendor/filament-auditing/tables/custom-audit-content.blade.php` file. +For example: ```php @php diff --git a/config/filament-auditing.php b/config/filament-auditing.php index e3516c5..345e72b 100644 --- a/config/filament-auditing.php +++ b/config/filament-auditing.php @@ -28,8 +28,11 @@ ], 'custom_audits_view' => false, - 'custom_old_and_new_values_column_view' => true, 'custom_view_parameters' => [ - ] + ], + + 'mapping' => [ + ], + ]; diff --git a/resources/views/tables/columns/key-value.blade.php b/resources/views/tables/columns/key-value.blade.php index c0b15ec..3c65d6a 100644 --- a/resources/views/tables/columns/key-value.blade.php +++ b/resources/views/tables/columns/key-value.blade.php @@ -1,16 +1,26 @@ +@php + $data = isset($state) ? $state : $getState() +@endphp +
- @foreach($getState() ?? [] as $key => $value) - - {{ $key }} - - @unless(is_array($value)) - {{ $value }} - @else - - @foreach ($value as $nestedValue) - {{$nestedValue['id']}} - @endforeach - - @endunless - @endforeach +
    + @foreach($data ?? [] as $key => $value) +
  • + + {{ Str::title($key) }}: + + + @unless(is_array($value)) + {{ $value }} + @else + + @foreach ($value as $nestedValue) + {{$nestedValue['id']}} + @endforeach + + @endunless + +
  • + @endforeach +
diff --git a/src/RelationManagers/AuditsRelationManager.php b/src/RelationManagers/AuditsRelationManager.php index aa84045..ca43ac5 100644 --- a/src/RelationManagers/AuditsRelationManager.php +++ b/src/RelationManagers/AuditsRelationManager.php @@ -3,7 +3,6 @@ namespace Tapp\FilamentAuditing\RelationManagers; use Filament\Facades\Filament; -use Filament\Forms\Components\Component; use Filament\Notifications\Notification; use Filament\Resources\RelationManagers\RelationManager; use Filament\Tables; @@ -14,7 +13,6 @@ use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Arr; use Illuminate\View\View; -use Livewire\Component as Livewire; use OwenIt\Auditing\Contracts\Audit; class AuditsRelationManager extends RelationManager @@ -42,6 +40,28 @@ public static function getTitle(Model $ownerRecord, string $pageClass): string public function table(Table $table): Table { + $oldValuesColumn = + method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') + ? + Tables\Columns\TextColumn::make('old_values') + ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state) + ->label(trans('filament-auditing::filament-auditing.column.old_values')) + : + Tables\Columns\TextColumn::make('old_values') + ->formatStateUsing(fn (Column $column, $record, $state): View => view('filament-auditing::tables.columns.key-value', ['state' => $this->mapRelatedColumns($column->getState(), $record)])) + ->label(trans('filament-auditing::filament-auditing.column.old_values')); + + $newValuesColumn = + method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') + ? + Tables\Columns\TextColumn::make('new_values') + ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state) + ->label(trans('filament-auditing::filament-auditing.column.new_values')) + : + Tables\Columns\TextColumn::make('new_values') + ->formatStateUsing(fn (Column $column, $record, $state): View => view('filament-auditing::tables.columns.key-value', ['state' => $this->mapRelatedColumns($column->getState(), $record)])) + ->label(trans('filament-auditing::filament-auditing.column.new_values')); + return $table ->modifyQueryUsing(fn (Builder $query) => $query->with('user')->orderBy(config('filament-auditing.audits_sort.column'), config('filament-auditing.audits_sort.direction'))) ->content(fn (): ?View => config('filament-auditing.custom_audits_view') ? view('filament-auditing::tables.custom-audit-content', Arr::add(self::customViewParameters(), 'owner', $this->getOwnerRecord())) : null) @@ -53,14 +73,8 @@ public function table(Table $table): Table Tables\Columns\TextColumn::make('created_at') ->since() ->label(trans('filament-auditing::filament-auditing.column.created_at')), - Tables\Columns\TextColumn::make('old_values') - ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state) - ->label(trans('filament-auditing::filament-auditing.column.old_values')) - ->view(config('filament-auditing.custom_old_and_new_values_column_view') ? 'filament-auditing::tables.columns.key-value' : null), - Tables\Columns\TextColumn::make('new_values') - ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state) - ->label(trans('filament-auditing::filament-auditing.column.new_values')) - ->view(config('filament-auditing.custom_old_and_new_values_column_view') ? 'filament-auditing::tables.columns.key-value' : null), + $oldValuesColumn, + $newValuesColumn, self::extraColumns(), ])) ->filters([ @@ -90,6 +104,22 @@ protected static function customViewParameters(): array return config('filament-auditing.custom_view_parameters'); } + protected function mapRelatedColumns($state, $record) + { + $relationshipsToUpdate = Arr::wrap(config('filament-auditing.mapping')); + + if (count($relationshipsToUpdate) !== 0) { + foreach ($relationshipsToUpdate as $key => $relationship) { + if (array_key_exists($key, $state)) { + $state[$relationship['label']] = $relationship['model']::find($state[$key])?->{$relationship['field']}; + unset($state[$key]); + } + } + } + + return $state; + } + protected static function extraColumns() { return Arr::map(config('filament-auditing.audits_extend'), function ($buildParameters, $columnName) { From 32052e3a1972187c67e6875e10f96ecbc0cdb232 Mon Sep 17 00:00:00 2001 From: andreia Date: Tue, 26 Mar 2024 18:03:06 +0000 Subject: [PATCH 4/4] PHP Linting (Pint) --- src/RelationManagers/AuditsRelationManager.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/RelationManagers/AuditsRelationManager.php b/src/RelationManagers/AuditsRelationManager.php index ca43ac5..b65563d 100644 --- a/src/RelationManagers/AuditsRelationManager.php +++ b/src/RelationManagers/AuditsRelationManager.php @@ -44,23 +44,23 @@ public function table(Table $table): Table method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? Tables\Columns\TextColumn::make('old_values') - ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state) - ->label(trans('filament-auditing::filament-auditing.column.old_values')) + ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state) + ->label(trans('filament-auditing::filament-auditing.column.old_values')) : Tables\Columns\TextColumn::make('old_values') - ->formatStateUsing(fn (Column $column, $record, $state): View => view('filament-auditing::tables.columns.key-value', ['state' => $this->mapRelatedColumns($column->getState(), $record)])) - ->label(trans('filament-auditing::filament-auditing.column.old_values')); + ->formatStateUsing(fn (Column $column, $record, $state): View => view('filament-auditing::tables.columns.key-value', ['state' => $this->mapRelatedColumns($column->getState(), $record)])) + ->label(trans('filament-auditing::filament-auditing.column.old_values')); $newValuesColumn = method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? Tables\Columns\TextColumn::make('new_values') - ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state) - ->label(trans('filament-auditing::filament-auditing.column.new_values')) + ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state) + ->label(trans('filament-auditing::filament-auditing.column.new_values')) : Tables\Columns\TextColumn::make('new_values') - ->formatStateUsing(fn (Column $column, $record, $state): View => view('filament-auditing::tables.columns.key-value', ['state' => $this->mapRelatedColumns($column->getState(), $record)])) - ->label(trans('filament-auditing::filament-auditing.column.new_values')); + ->formatStateUsing(fn (Column $column, $record, $state): View => view('filament-auditing::tables.columns.key-value', ['state' => $this->mapRelatedColumns($column->getState(), $record)])) + ->label(trans('filament-auditing::filament-auditing.column.new_values')); return $table ->modifyQueryUsing(fn (Builder $query) => $query->with('user')->orderBy(config('filament-auditing.audits_sort.column'), config('filament-auditing.audits_sort.direction')))