├── resources
├── views
│ └── tables
│ │ ├── custom-audit-content.blade.php
│ │ └── columns
│ │ └── key-value.blade.php
└── lang
│ ├── en
│ └── filament-auditing.php
│ ├── ko
│ └── filament-auditing.php
│ ├── de
│ └── filament-auditing.php
│ ├── fr
│ └── filament-auditing.php
│ ├── pt_BR
│ └── filament-auditing.php
│ ├── es
│ └── filament-auditing.php
│ └── ar
│ └── filament-auditing.php
├── .github
├── pull_request_template.md
├── SECURITY.md
└── workflows
│ ├── fix-php-code-style-issues.yml
│ ├── phpstan.yml
│ ├── update-changelog.yml
│ ├── dependabot-auto-merge.yml
│ └── run-tests.yml
├── tests
├── ExampleTest.php
├── Pest.php
├── ArchTest.php
└── TestCase.php
├── phpstan.neon.dist
├── .gitignore
├── config
└── filament-auditing.php
├── src
├── FilamentAuditingServiceProvider.php
└── RelationManagers
│ └── AuditsRelationManager.php
├── phpstan-baseline.neon
├── phpunit.xml.dist
├── composer.json
├── CHANGELOG.md
└── README.md
/resources/views/tables/custom-audit-content.blade.php:
--------------------------------------------------------------------------------
1 | {{-- add your custom code here --}}
2 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # Details
2 |
3 | Details of the feature / fix this PR addresses
4 |
--------------------------------------------------------------------------------
/tests/ExampleTest.php:
--------------------------------------------------------------------------------
1 | toBeTrue();
5 | });
6 |
--------------------------------------------------------------------------------
/tests/Pest.php:
--------------------------------------------------------------------------------
1 | in(__DIR__);
6 |
--------------------------------------------------------------------------------
/tests/ArchTest.php:
--------------------------------------------------------------------------------
1 | expect(['dd', 'dump', 'ray'])
5 | ->each->not->toBeUsed();
6 |
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | If you discover any security related issues, please email steve@tappnetwork.com instead of using the issue tracker.
4 |
--------------------------------------------------------------------------------
/phpstan.neon.dist:
--------------------------------------------------------------------------------
1 | includes:
2 | - phpstan-baseline.neon
3 |
4 | parameters:
5 | level: 4
6 | paths:
7 | - src
8 | - config
9 | tmpDir: build/phpstan
10 | checkOctaneCompatibility: true
11 | checkModelProperties: true
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /vendor
3 | .phpunit.result.cache
4 | Homestead.json
5 | Homestead.yaml
6 | auth.json
7 | npm-debug.log
8 | yarn-error.log
9 | /.idea
10 | /.vscode
11 | /build
12 | /coverage
13 | .DS_Store
14 | composer.phar
15 | phpunit.xml
16 | phpstan.neon
17 | composer.lock
18 |
--------------------------------------------------------------------------------
/.github/workflows/fix-php-code-style-issues.yml:
--------------------------------------------------------------------------------
1 | name: Fix PHP code style issues
2 |
3 | on:
4 | push:
5 | paths:
6 | - '**.php'
7 |
8 | permissions:
9 | contents: write
10 |
11 | jobs:
12 | php-code-styling:
13 | runs-on: ubuntu-latest
14 | timeout-minutes: 5
15 |
16 | steps:
17 | - name: Checkout code
18 | uses: actions/checkout@v4
19 | with:
20 | ref: ${{ github.head_ref }}
21 |
22 | - name: Fix PHP code style issues
23 | uses: aglipanci/laravel-pint-action@2.5
24 |
25 | - name: Commit changes
26 | uses: stefanzweifel/git-auto-commit-action@v5
27 | with:
28 | commit_message: Fix styling
29 |
--------------------------------------------------------------------------------
/.github/workflows/phpstan.yml:
--------------------------------------------------------------------------------
1 | name: PHPStan
2 |
3 | on:
4 | push:
5 | paths:
6 | - '**.php'
7 | - 'phpstan.neon.dist'
8 | - '.github/workflows/phpstan.yml'
9 |
10 | jobs:
11 | phpstan:
12 | name: phpstan
13 | runs-on: ubuntu-latest
14 | timeout-minutes: 5
15 | steps:
16 | - uses: actions/checkout@v4
17 |
18 | - name: Setup PHP
19 | uses: shivammathur/setup-php@v2
20 | with:
21 | php-version: '8.3'
22 | coverage: none
23 |
24 | - name: Install composer dependencies
25 | uses: ramsey/composer-install@v3
26 |
27 | - name: Run PHPStan
28 | run: ./vendor/bin/phpstan --error-format=github
29 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | set('database.default', 'testing');
25 |
26 | /*
27 | $migration = include __DIR__.'/../database/migrations/create_filament-maillog_table.php.stub';
28 | $migration->up();
29 | */
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.github/workflows/update-changelog.yml:
--------------------------------------------------------------------------------
1 | name: "Update Changelog"
2 |
3 | on:
4 | release:
5 | types: [released]
6 |
7 | permissions:
8 | contents: write
9 |
10 | jobs:
11 | update:
12 | runs-on: ubuntu-latest
13 | timeout-minutes: 5
14 |
15 | steps:
16 | - name: Checkout code
17 | uses: actions/checkout@v4
18 | with:
19 | ref: main
20 |
21 | - name: Update Changelog
22 | uses: stefanzweifel/changelog-updater-action@v1
23 | with:
24 | latest-version: ${{ github.event.release.name }}
25 | release-notes: ${{ github.event.release.body }}
26 |
27 | - name: Commit updated CHANGELOG
28 | uses: stefanzweifel/git-auto-commit-action@v5
29 | with:
30 | branch: main
31 | commit_message: Update CHANGELOG
32 | file_pattern: CHANGELOG.md
33 |
--------------------------------------------------------------------------------
/config/filament-auditing.php:
--------------------------------------------------------------------------------
1 | [
6 | 'column' => 'created_at',
7 | 'direction' => 'desc',
8 | ],
9 |
10 | 'is_lazy' => true,
11 |
12 | /**
13 | * Extending Columns
14 | * --------------------------------------------------------------------------
15 | * In case you need to add a column to the AuditsRelationManager that does
16 | * not already exist in the table, you can add it here, and it will be
17 | * prepended to the table builder.
18 | */
19 | 'audits_extend' => [
20 | // 'url' => [
21 | // 'class' => \Filament\Tables\Columns\TextColumn::class,
22 | // 'methods' => [
23 | // 'sortable',
24 | // 'searchable' => true,
25 | // 'default' => 'N/A'
26 | // ]
27 | // ],
28 | ],
29 |
30 | 'custom_audits_view' => false,
31 |
32 | 'custom_view_parameters' => [
33 | ],
34 |
35 | 'mapping' => [
36 | ],
37 |
38 | ];
39 |
--------------------------------------------------------------------------------
/resources/views/tables/columns/key-value.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $data = isset($state) ? $state : $getState()
3 | @endphp
4 |
5 |
6 |
7 | @foreach($data ?? [] as $key => $value)
8 |
9 |
10 | {{ Str::title($key) }}:
11 |
12 |
13 | @unless(is_array($value))
14 | {{ $value }}
15 | @else
16 |
17 | @foreach ($value as $nestedValue)
18 | {{$nestedValue['id']}}
19 | @endforeach
20 |
21 | @endunless
22 |
23 |
24 | @endforeach
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/FilamentAuditingServiceProvider.php:
--------------------------------------------------------------------------------
1 | name('filament-auditing')
16 | ->hasConfigFile('filament-auditing')
17 | ->hasTranslations('filament-auditing')
18 | ->hasViews('filament-auditing');
19 | }
20 |
21 | public function packageBooted(): void
22 | {
23 | parent::packageBooted();
24 |
25 | // Default values for view and restore audits. Add a policy to override these values
26 | Gate::define('audit', function ($user, $resource) {
27 | return true;
28 | });
29 |
30 | Gate::define('restoreAudit', function ($user, $resource) {
31 | return true;
32 | });
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.github/workflows/dependabot-auto-merge.yml:
--------------------------------------------------------------------------------
1 | name: dependabot-auto-merge
2 | on: pull_request_target
3 |
4 | permissions:
5 | pull-requests: write
6 | contents: write
7 |
8 | jobs:
9 | dependabot:
10 | runs-on: ubuntu-latest
11 | timeout-minutes: 5
12 | if: ${{ github.actor == 'dependabot[bot]' }}
13 | steps:
14 |
15 | - name: Dependabot metadata
16 | id: metadata
17 | uses: dependabot/fetch-metadata@v2.3.0
18 | with:
19 | github-token: "${{ secrets.GITHUB_TOKEN }}"
20 |
21 | - name: Auto-merge Dependabot PRs for semver-minor updates
22 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}}
23 | run: gh pr merge --auto --merge "$PR_URL"
24 | env:
25 | PR_URL: ${{github.event.pull_request.html_url}}
26 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
27 |
28 | - name: Auto-merge Dependabot PRs for semver-patch updates
29 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}}
30 | run: gh pr merge --auto --merge "$PR_URL"
31 | env:
32 | PR_URL: ${{github.event.pull_request.html_url}}
33 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
34 |
--------------------------------------------------------------------------------
/phpstan-baseline.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | ignoreErrors:
3 | -
4 | message: '#^Method Spatie\\LaravelPackageTools\\Package\:\:hasTranslations\(\) invoked with 1 parameter, 0 required\.$#'
5 | identifier: arguments.count
6 | count: 1
7 | path: src/FilamentAuditingServiceProvider.php
8 |
9 | -
10 | message: '#^Access to an undefined property OwenIt\\Auditing\\Contracts\\Audit\:\:\$event\.$#'
11 | identifier: property.notFound
12 | count: 1
13 | path: src/RelationManagers/AuditsRelationManager.php
14 |
15 | -
16 | message: '#^Call to function is_array\(\) with array will always evaluate to true\.$#'
17 | identifier: function.alreadyNarrowedType
18 | count: 1
19 | path: src/RelationManagers/AuditsRelationManager.php
20 |
21 | -
22 | message: '#^Call to function method_exists\(\) with Illuminate\\Database\\Eloquent\\Model and ''formatAuditFieldsFo…'' will always evaluate to true\.$#'
23 | identifier: function.alreadyNarrowedType
24 | count: 2
25 | path: src/RelationManagers/AuditsRelationManager.php
26 |
27 | -
28 | message: '#^Unreachable statement \- code above always terminates\.$#'
29 | identifier: deadCode.unreachable
30 | count: 1
31 | path: src/RelationManagers/AuditsRelationManager.php
32 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 | tests
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | ./src
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/resources/lang/en/filament-auditing.php:
--------------------------------------------------------------------------------
1 | 'Audits',
12 | 'table.empty_state_heading' => 'No audits',
13 |
14 | /*
15 | |--------------------------------------------------------------------------
16 | | Table Columns
17 | |--------------------------------------------------------------------------
18 | */
19 |
20 | 'column.user_name' => 'User',
21 | 'column.event' => 'Event',
22 | 'column.created_at' => 'Created',
23 | 'column.old_values' => 'Old Values',
24 | 'column.new_values' => 'New Values',
25 |
26 | /*
27 | |--------------------------------------------------------------------------
28 | | Table Actions
29 | |--------------------------------------------------------------------------
30 | */
31 |
32 | 'action.restore' => 'Restore',
33 |
34 | /*
35 | |--------------------------------------------------------------------------
36 | | Notifications
37 | |--------------------------------------------------------------------------
38 | */
39 |
40 | 'notification.restored' => 'Audit restored',
41 | 'notification.unchanged' => 'Nothing to change',
42 |
43 | ];
44 |
--------------------------------------------------------------------------------
/.github/workflows/run-tests.yml:
--------------------------------------------------------------------------------
1 | name: run-tests
2 |
3 | on:
4 | push:
5 | paths:
6 | - '**.php'
7 | - '.github/workflows/run-tests.yml'
8 | - 'phpunit.xml.dist'
9 | - 'composer.json'
10 | - 'composer.lock'
11 |
12 | jobs:
13 | test:
14 | runs-on: ${{ matrix.os }}
15 | timeout-minutes: 5
16 | strategy:
17 | fail-fast: true
18 | matrix:
19 | os: [ubuntu-latest]
20 | php: [8.4, 8.3, 8.2]
21 | laravel: [12.*, 11.*,10.*]
22 | stability: [prefer-lowest, prefer-stable]
23 | include:
24 | - laravel: 12.*
25 | testbench: 10.*
26 | - laravel: 11.*
27 | testbench: 9.*
28 | - laravel: 10.*
29 | testbench: 8.*
30 |
31 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}
32 |
33 | steps:
34 | - name: Checkout code
35 | uses: actions/checkout@v4
36 |
37 | - name: Setup PHP
38 | uses: shivammathur/setup-php@v2
39 | with:
40 | php-version: ${{ matrix.php }}
41 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
42 | coverage: none
43 |
44 | - name: Setup problem matchers
45 | run: |
46 | echo "::add-matcher::${{ runner.tool_cache }}/php.json"
47 | echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
48 |
49 | - name: Install dependencies
50 | run: |
51 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
52 | composer update --${{ matrix.stability }} --prefer-dist --no-interaction
53 |
54 | - name: List Installed Dependencies
55 | run: composer show -D
56 |
57 | - name: Execute tests
58 | run: vendor/bin/pest --ci
59 |
--------------------------------------------------------------------------------
/resources/lang/ko/filament-auditing.php:
--------------------------------------------------------------------------------
1 | '변경이력',
12 | 'table.empty_state_heading' => '감사 없음',
13 |
14 | /*
15 | |--------------------------------------------------------------------------
16 | | Table Columns
17 | |--------------------------------------------------------------------------
18 | */
19 |
20 | 'column.user_name' => '사용자',
21 | 'column.event' => '이벤트',
22 | 'column.created_at' => '등록됨',
23 | 'column.old_values' => '기존 내용',
24 | 'column.new_values' => '신규 내용',
25 | 'column.auditable_type' => '감사됨',
26 |
27 | /*
28 | |--------------------------------------------------------------------------
29 | | Table Filters
30 | |--------------------------------------------------------------------------
31 | */
32 |
33 | 'filter.created_at' => '등록됨',
34 | 'filter.created_from' => '시작일',
35 | 'filter.created_until' => '종료일',
36 |
37 | /*
38 | |--------------------------------------------------------------------------
39 | | Table Actions
40 | |--------------------------------------------------------------------------
41 | */
42 |
43 | 'action.restore' => '복원',
44 |
45 | /*
46 | |--------------------------------------------------------------------------
47 | | Resource Infolist
48 | |--------------------------------------------------------------------------
49 | */
50 |
51 | 'infolist.tab.info' => '정보',
52 | 'infolist.tab.old-values' => '기존 내용',
53 | 'infolist.tab.new-values' => '신규 내용',
54 | 'infolist.user' => '사용자',
55 | 'infolist.created-at' => '등록됨',
56 | 'infolist.audited' => '감사됨',
57 | 'infolist.event' => '이벤트',
58 | 'infolist.url' => 'URL',
59 | 'infolist.ip-address' => 'IP 주소',
60 | 'infolist.user-agent' => '사용자 에이전트',
61 | 'infolist.tags' => '태그',
62 |
63 | /*
64 | |--------------------------------------------------------------------------
65 | | Notifications
66 | |--------------------------------------------------------------------------
67 | */
68 |
69 | 'notification.restored' => '변경이력 복원',
70 | 'notification.unchanged' => '변경할 사항이 없습니다.',
71 |
72 | ];
73 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tapp/filament-auditing",
3 | "description": "Filament Laravel Auditing plugin.",
4 | "keywords": [
5 | "tapp network",
6 | "filament",
7 | "laravel",
8 | "auditing",
9 | "audit"
10 | ],
11 | "license": "MIT",
12 | "authors": [
13 | {
14 | "name": "Tapp Network",
15 | "email": "steve@tappnetwork.com",
16 | "role": "Developer"
17 | },
18 | {
19 | "name": "Tapp Network",
20 | "email": "andreia.bohner@tappnetwork.com",
21 | "role": "Developer"
22 | }
23 | ],
24 | "homepage": "https://github.com/TappNetwork/filament-auditing",
25 | "support": {
26 | "issues": "https://github.com/TappNetwork/filament-auditing/issues",
27 | "source": "https://github.com/TappNetwork/filament-auditing"
28 | },
29 | "require": {
30 | "php": "^8.2",
31 | "filament/filament": "^3.0-stable",
32 | "owen-it/laravel-auditing": "^14.0||^13.0",
33 | "spatie/laravel-package-tools": "^1.16"
34 | },
35 | "require-dev": {
36 | "larastan/larastan": "^2.9||^3.0",
37 | "laravel/pint": "^1.14",
38 | "nunomaduro/collision": "^8.1.1||^7.10.0",
39 | "orchestra/testbench": "^10.0.0||^9.0.0||^8.22.0",
40 | "pestphp/pest": "^3.0||^2.34",
41 | "pestphp/pest-plugin-arch": "^3.0||^2.7",
42 | "pestphp/pest-plugin-laravel": "^3.0||^2.3",
43 | "phpstan/extension-installer": "^1.3||^2.0",
44 | "phpstan/phpstan-deprecation-rules": "^1.1||^2.0",
45 | "phpstan/phpstan-phpunit": "^1.3||^2.0",
46 | "spatie/laravel-ray": "^1.35"
47 | },
48 | "autoload": {
49 | "psr-4": {
50 | "Tapp\\FilamentAuditing\\": "src"
51 | }
52 | },
53 | "autoload-dev": {
54 | "psr-4": {
55 | "Tapp\\FilamentAuditing\\Tests\\": "tests/",
56 | "Workbench\\App\\": "workbench/app/"
57 | }
58 | },
59 | "config": {
60 | "sort-packages": true,
61 | "allow-plugins": {
62 | "pestphp/pest-plugin": true,
63 | "phpstan/extension-installer": true
64 | }
65 | },
66 | "extra": {
67 | "laravel": {
68 | "providers": [
69 | "Tapp\\FilamentAuditing\\FilamentAuditingServiceProvider"
70 | ]
71 | }
72 | },
73 | "minimum-stability": "dev",
74 | "prefer-stable": true
75 | }
76 |
--------------------------------------------------------------------------------
/resources/lang/de/filament-auditing.php:
--------------------------------------------------------------------------------
1 | 'Audits',
12 | 'table.empty_state_heading' => 'Keine Audits',
13 |
14 | /*
15 | |--------------------------------------------------------------------------
16 | | Table Columns
17 | |--------------------------------------------------------------------------
18 | */
19 |
20 | 'column.user_name' => 'Benutzer',
21 | 'column.event' => 'Event',
22 | 'column.created_at' => 'Erstellt am',
23 | 'column.old_values' => 'Alter Wert',
24 | 'column.new_values' => 'Neuer Wert',
25 | 'column.auditable_type' => 'Auditiert',
26 |
27 | /*
28 | |--------------------------------------------------------------------------
29 | | Table Filters
30 | |--------------------------------------------------------------------------
31 | */
32 |
33 | 'filter.created_at' => 'Erstellt am',
34 | 'filter.created_from' => 'Von',
35 | 'filter.created_until' => 'Bis',
36 |
37 | /*
38 | |--------------------------------------------------------------------------
39 | | Table Actions
40 | |--------------------------------------------------------------------------
41 | */
42 |
43 | 'action.restore' => 'Wiederherstellen',
44 |
45 | /*
46 | |--------------------------------------------------------------------------
47 | | Resource Infolist
48 | |--------------------------------------------------------------------------
49 | */
50 |
51 | 'infolist.tab.info' => 'Info',
52 | 'infolist.tab.old-values' => 'Alter Wert',
53 | 'infolist.tab.new-values' => 'Neuer Wert',
54 | 'infolist.user' => 'Benutzer',
55 | 'infolist.created-at' => 'Erstellt am',
56 | 'infolist.audited' => 'Auditiert',
57 | 'infolist.event' => 'Event',
58 | 'infolist.url' => 'URL',
59 | 'infolist.ip-address' => 'IP-Adresse',
60 | 'infolist.user-agent' => 'User-Agent',
61 | 'infolist.tags' => 'Tags',
62 |
63 | /*
64 | |--------------------------------------------------------------------------
65 | | Notifications
66 | |--------------------------------------------------------------------------
67 | */
68 |
69 | 'notification.restored' => 'Audit wiederhergestellt',
70 | 'notification.unchanged' => 'Es gibt nichts zu ändern',
71 |
72 | ];
73 |
--------------------------------------------------------------------------------
/resources/lang/fr/filament-auditing.php:
--------------------------------------------------------------------------------
1 | 'Audits',
12 | 'table.empty_state_heading' => "Pas d'audits",
13 |
14 | /*
15 | |--------------------------------------------------------------------------
16 | | Table Columns
17 | |--------------------------------------------------------------------------
18 | */
19 |
20 | 'column.user_name' => 'Utilisateur',
21 | 'column.event' => 'Événement',
22 | 'column.created_at' => 'Créé',
23 | 'column.old_values' => 'Anciennes valeurs',
24 | 'column.new_values' => 'Nouvelles valeurs',
25 | 'column.auditable_type' => 'Audité',
26 |
27 | /*
28 | |--------------------------------------------------------------------------
29 | | Table Filters
30 | |--------------------------------------------------------------------------
31 | */
32 |
33 | 'filter.created_at' => 'Créé',
34 | 'filter.created_from' => 'Depuis',
35 | 'filter.created_until' => "Jusqu'à",
36 |
37 | /*
38 | |--------------------------------------------------------------------------
39 | | Table Actions
40 | |--------------------------------------------------------------------------
41 | */
42 |
43 | 'action.restore' => 'Restaurer',
44 |
45 | /*
46 | |--------------------------------------------------------------------------
47 | | Resource Infolist
48 | |--------------------------------------------------------------------------
49 | */
50 |
51 | 'infolist.tab.info' => 'Info',
52 | 'infolist.tab.old-values' => 'Anciennes valeurs',
53 | 'infolist.tab.new-values' => 'Nouvelles valeurs',
54 | 'infolist.user' => 'Utilisateur',
55 | 'infolist.created-at' => 'Créé',
56 | 'infolist.audited' => 'Audité',
57 | 'infolist.event' => 'Événement',
58 | 'infolist.url' => 'URL',
59 | 'infolist.ip-address' => 'Adresse IP',
60 | 'infolist.user-agent' => 'User-Agent',
61 | 'infolist.tags' => 'Tags',
62 |
63 | /*
64 | |--------------------------------------------------------------------------
65 | | Notifications
66 | |--------------------------------------------------------------------------
67 | */
68 |
69 | 'notification.restored' => 'Audit restauré',
70 | 'notification.unchanged' => 'Rien à modifier',
71 |
72 | ];
73 |
--------------------------------------------------------------------------------
/resources/lang/pt_BR/filament-auditing.php:
--------------------------------------------------------------------------------
1 | 'Auditorias',
12 | 'table.empty_state_heading' => 'Nenhuma auditoria',
13 |
14 | /*
15 | |--------------------------------------------------------------------------
16 | | Table Columns
17 | |--------------------------------------------------------------------------
18 | */
19 |
20 | 'column.user_name' => 'Usuário',
21 | 'column.event' => 'Evento',
22 | 'column.created_at' => 'Criado em',
23 | 'column.old_values' => 'Valores Antigos',
24 | 'column.new_values' => 'Novos Valores',
25 | 'column.auditable_type' => 'Auditado',
26 |
27 | /*
28 | |--------------------------------------------------------------------------
29 | | Table Filters
30 | |--------------------------------------------------------------------------
31 | */
32 |
33 | 'filter.created_at' => 'Criado',
34 | 'filter.created_from' => 'De',
35 | 'filter.created_until' => 'Até',
36 |
37 | /*
38 | |--------------------------------------------------------------------------
39 | | Table Actions
40 | |--------------------------------------------------------------------------
41 | */
42 |
43 | 'action.restore' => 'Restaurar',
44 |
45 | /*
46 | |--------------------------------------------------------------------------
47 | | Resource Infolist
48 | |--------------------------------------------------------------------------
49 | */
50 |
51 | 'infolist.tab.info' => 'Info',
52 | 'infolist.tab.old-values' => 'Valores Antigos',
53 | 'infolist.tab.new-values' => 'Novos Valores',
54 | 'infolist.user' => 'Usuário',
55 | 'infolist.created-at' => 'Criado em',
56 | 'infolist.audited' => 'Auditado',
57 | 'infolist.event' => 'Evento',
58 | 'infolist.url' => 'URL',
59 | 'infolist.ip-address' => 'Endereço IP',
60 | 'infolist.user-agent' => 'User Agent',
61 | 'infolist.tags' => 'Tags',
62 |
63 | /*
64 | |--------------------------------------------------------------------------
65 | | Notifications
66 | |--------------------------------------------------------------------------
67 | */
68 |
69 | 'notification.restored' => 'Auditoria restaurada',
70 | 'notification.unchanged' => 'Nada a alterar',
71 |
72 | ];
73 |
--------------------------------------------------------------------------------
/resources/lang/es/filament-auditing.php:
--------------------------------------------------------------------------------
1 | 'Auditorías',
12 | 'table.empty_state_heading' => 'Sin auditorías',
13 |
14 | /*
15 | |--------------------------------------------------------------------------
16 | | Table Columns
17 | |--------------------------------------------------------------------------
18 | */
19 |
20 | 'column.user_name' => 'Usuario',
21 | 'column.event' => 'Evento',
22 | 'column.created_at' => 'Creado en',
23 | 'column.old_values' => 'Valores antiguos',
24 | 'column.new_values' => 'Nuevos valores',
25 | 'column.auditable_type' => 'Auditado',
26 |
27 | /*
28 | |--------------------------------------------------------------------------
29 | | Table Filters
30 | |--------------------------------------------------------------------------
31 | */
32 |
33 | 'filter.created_at' => 'Creado en',
34 | 'filter.created_from' => 'Desde',
35 | 'filter.created_until' => 'Hasta',
36 |
37 | /*
38 | |--------------------------------------------------------------------------
39 | | Table Actions
40 | |--------------------------------------------------------------------------
41 | */
42 |
43 | 'action.restore' => 'Restaurar',
44 |
45 | /*
46 | |--------------------------------------------------------------------------
47 | | Resource Infolist
48 | |--------------------------------------------------------------------------
49 | */
50 |
51 | 'infolist.tab.info' => 'Info',
52 | 'infolist.tab.old-values' => 'Valores antiguos',
53 | 'infolist.tab.new-values' => 'Nuevos valores',
54 | 'infolist.user' => 'Usuario',
55 | 'infolist.created-at' => 'Creado en',
56 | 'infolist.audited' => 'Auditado',
57 | 'infolist.event' => 'Evento',
58 | 'infolist.url' => 'URL',
59 | 'infolist.ip-address' => 'Dirección IP',
60 | 'infolist.user-agent' => 'User Agent',
61 | 'infolist.tags' => 'Tags',
62 |
63 | /*
64 | |--------------------------------------------------------------------------
65 | | Notifications
66 | |--------------------------------------------------------------------------
67 | */
68 |
69 | 'notification.restored' => 'Auditoría restaurada',
70 | 'notification.unchanged' => 'Nada que cambiar',
71 |
72 | ];
73 |
--------------------------------------------------------------------------------
/resources/lang/ar/filament-auditing.php:
--------------------------------------------------------------------------------
1 | 'سجل التعديلات',
12 | 'table.empty_state_heading' => 'لا توجد عمليات تدقيق',
13 |
14 | /*
15 | |--------------------------------------------------------------------------
16 | | Table Columns
17 | |--------------------------------------------------------------------------
18 | */
19 |
20 | 'column.user_name' => 'المستخدم',
21 | 'column.event' => 'العملية',
22 | 'column.created_at' => 'تاريخ التعديل',
23 | 'column.old_values' => 'القيم السابقة',
24 | 'column.new_values' => 'القيم الجديدة',
25 | 'column.auditable_type' => 'تم التدقيق',
26 |
27 | /*
28 | |--------------------------------------------------------------------------
29 | | Table Filters
30 | |--------------------------------------------------------------------------
31 | */
32 |
33 | 'filter.created_at' => 'تاريخ التعديل',
34 | 'filter.created_from' => 'من',
35 | 'filter.created_until' => 'إلى',
36 |
37 | /*
38 | |--------------------------------------------------------------------------
39 | | Table Actions
40 | |--------------------------------------------------------------------------
41 | */
42 |
43 | 'action.restore' => 'استعادة',
44 |
45 | /*
46 | |--------------------------------------------------------------------------
47 | | Resource Infolist
48 | |--------------------------------------------------------------------------
49 | */
50 |
51 | 'infolist.tab.info' => 'معلومات',
52 | 'infolist.tab.old-values' => 'القيم السابقة',
53 | 'infolist.tab.new-values' => 'القيم الجديدة',
54 | 'infolist.user' => 'المستخدم',
55 | 'infolist.created-at' => 'تاريخ التعديل',
56 | 'infolist.audited' => 'تم التدقيق',
57 | 'infolist.event' => 'العملية',
58 | 'infolist.url' => 'الرابط',
59 | 'infolist.ip-address' => 'عنوان IP',
60 | 'infolist.user-agent' => 'متصفح المستخدم',
61 | 'infolist.tags' => 'الوسوم',
62 |
63 | /*
64 | |--------------------------------------------------------------------------
65 | | Notifications
66 | |--------------------------------------------------------------------------
67 | */
68 |
69 | 'notification.restored' => 'تمت الاستعادة',
70 | 'notification.unchanged' => 'لا توجد تعديلات',
71 |
72 | ];
73 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to the "Filament Laravel Auditing" will be documented in this file.
4 |
5 | ## v4.0.5 - 2025-09-28
6 |
7 | ### What's Changed
8 |
9 | * Language updates by @andreia in https://github.com/TappNetwork/filament-auditing/pull/52
10 |
11 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v4.0.4...v4.0.5
12 |
13 | ## v3.1.2 - 2025-09-28
14 |
15 | ### What's Changed
16 |
17 | * Update README Filament 4 by @andreia in https://github.com/TappNetwork/filament-auditing/pull/44
18 |
19 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.1.1...v3.1.2
20 |
21 | ## v4.0.4 - 2025-09-28
22 |
23 | ### What's Changed
24 |
25 | * fix(translations): add missing translations by @andrefedalto in https://github.com/TappNetwork/filament-auditing/pull/48
26 |
27 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v4.0.3...v4.0.4
28 |
29 | ## v4.0.3 - 2025-09-17
30 |
31 | ### What's Changed
32 |
33 | * fix: hardcoded label in infolist by @Pronesti in https://github.com/TappNetwork/filament-auditing/pull/51
34 |
35 | ### New Contributors
36 |
37 | * @Pronesti made their first contribution in https://github.com/TappNetwork/filament-auditing/pull/51
38 |
39 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v4.0.2...v4.0.3
40 |
41 | ## v4.0.2 - 2025-09-15
42 |
43 | ### What's Changed
44 |
45 | * Phpstan by @andreia in https://github.com/TappNetwork/filament-auditing/pull/50
46 |
47 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v4.0.1...v4.0.2
48 |
49 | ## v4.0.1 - 2025-09-08
50 |
51 | ### What's Changed
52 |
53 | * fix(relation-manager): eager load auditable relation to properly parse restoreAudit permission by @andrefedalto in https://github.com/TappNetwork/filament-auditing/pull/47
54 |
55 | ### New Contributors
56 |
57 | * @andrefedalto made their first contribution in https://github.com/TappNetwork/filament-auditing/pull/47
58 |
59 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v4.0.0...v4.0.1
60 |
61 | ## v4.0.0 - 2025-06-20
62 |
63 | ### What's Changed
64 |
65 | * Filament 4 upgrade by @andreia in https://github.com/TappNetwork/filament-auditing/pull/43
66 |
67 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.1.1...v4.0.0
68 |
69 | ## v3.1.1 - 2025-06-04
70 |
71 | ### What's Changed
72 |
73 | * feat: add support to pt_BR by @samuelterra22 in https://github.com/TappNetwork/filament-auditing/pull/42
74 |
75 | ### New Contributors
76 |
77 | * @samuelterra22 made their first contribution in https://github.com/TappNetwork/filament-auditing/pull/42
78 |
79 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.1.0...v3.1.1
80 |
81 | ## v3.1.0 - 2025-03-15
82 |
83 | ### What's Changed
84 |
85 | * Laravel 12 Support by @swilla in https://github.com/TappNetwork/filament-auditing/pull/39
86 |
87 | ### New Contributors
88 |
89 | * @swilla made their first contribution in https://github.com/TappNetwork/filament-auditing/pull/39
90 |
91 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.0.9...v3.1.0
92 |
93 | ## v3.0.9 - 2025-03-08
94 |
95 | ### What's Changed
96 |
97 | * add empty state heading by @erossdev in https://github.com/TappNetwork/filament-auditing/pull/38
98 |
99 | ### New Contributors
100 |
101 | * @erossdev made their first contribution in https://github.com/TappNetwork/filament-auditing/pull/38
102 |
103 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.0.8...v3.0.9
104 |
105 | ## v3.0.8 - 2024-12-12
106 |
107 | ### What's Changed
108 |
109 | * Allow multiple parameter methods when extending columns by @intrepidws in https://github.com/TappNetwork/filament-auditing/pull/34
110 |
111 | ### New Contributors
112 |
113 | * @intrepidws made their first contribution in https://github.com/TappNetwork/filament-auditing/pull/34
114 |
115 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.0.7...v3.0.8
116 |
117 | ## v3.0.7 - 2024-08-15
118 |
119 | ### What's Changed
120 |
121 | * Add the ability to customize the presentation by @andreia in https://github.com/TappNetwork/filament-auditing/pull/26
122 |
123 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.0.6...v3.0.7
124 |
125 | ## v3.0.6 - 2024-05-31
126 |
127 | ### What's Changed
128 |
129 | * German translation add by @DGINXREAL in https://github.com/TappNetwork/filament-auditing/pull/28
130 |
131 | ### New Contributors
132 |
133 | * @DGINXREAL made their first contribution in https://github.com/TappNetwork/filament-auditing/pull/28
134 |
135 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.0.5...v3.0.6
136 |
137 | ## v3.0.5 - 2024-03-24
138 |
139 | ### What's Changed
140 |
141 | * Korean translations add by @corean in https://github.com/TappNetwork/filament-auditing/pull/27
142 |
143 | ### New Contributors
144 |
145 | * @corean made their first contribution in https://github.com/TappNetwork/filament-auditing/pull/27
146 |
147 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.0.4...v3.0.5
148 |
149 | ## v3.0.4 - 2024-02-05
150 |
151 | ### What's Changed
152 |
153 | * use Filament::auth() instead of auth() by @eelco2k in https://github.com/TappNetwork/filament-auditing/pull/23
154 | * Add is_lazy configuration by @andreia in https://github.com/TappNetwork/filament-auditing/pull/24
155 |
156 | ### New Contributors
157 |
158 | * @eelco2k made their first contribution in https://github.com/TappNetwork/filament-auditing/pull/23
159 |
160 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.0.3...v3.0.4
161 |
162 | ## v3.0.3 - 2024-01-10
163 |
164 | ### What's Changed
165 |
166 | * Added fr_FR translation file for 3.x by @loanbesson in https://github.com/TappNetwork/filament-auditing/pull/19
167 |
168 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.0.2...v3.0.3
169 |
170 | ## v3.0.2 - 2023-09-24
171 |
172 | ### What's Changed
173 |
174 | - Add updateAuditsRelationManager event listener by @andreia in https://github.com/TappNetwork/filament-auditing/pull/17
175 |
176 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.0.1...v3.0.2
177 |
178 | ## v3.0.1 - 2023-09-24
179 |
180 | ### What's Changed
181 |
182 | - Ensure it does not break with null values. by @haringsrob in https://github.com/TappNetwork/filament-auditing/pull/16
183 |
184 | ### New Contributors
185 |
186 | - @haringsrob made their first contribution in https://github.com/TappNetwork/filament-auditing/pull/16
187 |
188 | **Full Changelog**: https://github.com/TappNetwork/filament-auditing/compare/v3.0.0...v3.0.1
189 |
190 | ## 1.0
191 |
192 | - Initial release
193 |
--------------------------------------------------------------------------------
/src/RelationManagers/AuditsRelationManager.php:
--------------------------------------------------------------------------------
1 | '$refresh'];
25 |
26 | public static function isLazy(): bool
27 | {
28 | return config('filament-auditing.is_lazy');
29 | }
30 |
31 | public static function canViewForRecord(Model $ownerRecord, string $pageClass): bool
32 | {
33 | return Filament::auth()->user()->can('audit', $ownerRecord);
34 | }
35 |
36 | public static function getTitle(Model $ownerRecord, string $pageClass): string
37 | {
38 | return trans('filament-auditing::filament-auditing.table.heading');
39 | }
40 |
41 | public function table(Table $table): Table
42 | {
43 | $oldValuesColumn =
44 | method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation')
45 | ?
46 | Tables\Columns\TextColumn::make('old_values')
47 | ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state)
48 | ->label(trans('filament-auditing::filament-auditing.column.old_values'))
49 | :
50 | Tables\Columns\TextColumn::make('old_values')
51 | ->formatStateUsing(fn (Column $column, $record, $state): View => view('filament-auditing::tables.columns.key-value', ['state' => $this->mapRelatedColumns($column->getState(), $record)]))
52 | ->label(trans('filament-auditing::filament-auditing.column.old_values'));
53 |
54 | $newValuesColumn =
55 | method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation')
56 | ?
57 | Tables\Columns\TextColumn::make('new_values')
58 | ->formatStateUsing(fn (Column $column, $record, $state) => method_exists($this->getOwnerRecord(), 'formatAuditFieldsForPresentation') ? $this->getOwnerRecord()->formatAuditFieldsForPresentation($column->getName(), $record) : $state)
59 | ->label(trans('filament-auditing::filament-auditing.column.new_values'))
60 | :
61 | Tables\Columns\TextColumn::make('new_values')
62 | ->formatStateUsing(fn (Column $column, $record, $state): View => view('filament-auditing::tables.columns.key-value', ['state' => $this->mapRelatedColumns($column->getState(), $record)]))
63 | ->label(trans('filament-auditing::filament-auditing.column.new_values'));
64 |
65 | return $table
66 | ->modifyQueryUsing(fn (Builder $query) => $query->with('user')->orderBy(config('filament-auditing.audits_sort.column'), config('filament-auditing.audits_sort.direction')))
67 | ->content(fn (): ?View => config('filament-auditing.custom_audits_view') ? view('filament-auditing::tables.custom-audit-content', Arr::add(self::customViewParameters(), 'owner', $this->getOwnerRecord())) : null)
68 | ->emptyStateHeading(trans('filament-auditing::filament-auditing.table.empty_state_heading'))
69 | ->columns(Arr::flatten([
70 | Tables\Columns\TextColumn::make('user.name')
71 | ->label(trans('filament-auditing::filament-auditing.column.user_name')),
72 | Tables\Columns\TextColumn::make('event')
73 | ->label(trans('filament-auditing::filament-auditing.column.event')),
74 | Tables\Columns\TextColumn::make('created_at')
75 | ->since()
76 | ->label(trans('filament-auditing::filament-auditing.column.created_at')),
77 | $oldValuesColumn,
78 | $newValuesColumn,
79 | self::extraColumns(),
80 | ]))
81 | ->filters([
82 | //
83 | ])
84 | ->headerActions([
85 | //
86 | ])
87 | ->actions([
88 | Tables\Actions\Action::make('restore')
89 | ->label(trans('filament-auditing::filament-auditing.action.restore'))
90 | ->action(fn (Audit $record) => static::restoreAuditSelected($record))
91 | ->icon('heroicon-o-arrow-path')
92 | ->requiresConfirmation()
93 | ->visible(fn (Audit $record, RelationManager $livewire): bool => Filament::auth()->user()->can('restoreAudit', $livewire->ownerRecord) && $record->event === 'updated')
94 | ->after(function ($livewire) {
95 | $livewire->dispatch('auditRestored');
96 | }),
97 | ])
98 | ->bulkActions([
99 | //
100 | ]);
101 | }
102 |
103 | protected static function customViewParameters(): array
104 | {
105 | return config('filament-auditing.custom_view_parameters');
106 | }
107 |
108 | protected function mapRelatedColumns($state, $record)
109 | {
110 | $relationshipsToUpdate = Arr::wrap(config('filament-auditing.mapping'));
111 |
112 | if (count($relationshipsToUpdate) !== 0) {
113 | foreach ($relationshipsToUpdate as $key => $relationship) {
114 | if (array_key_exists($key, $state)) {
115 | $state[$relationship['label']] = $relationship['model']::find($state[$key])?->{$relationship['field']};
116 | unset($state[$key]);
117 | }
118 | }
119 | }
120 |
121 | return $state;
122 | }
123 |
124 | protected static function extraColumns()
125 | {
126 | return Arr::map(config('filament-auditing.audits_extend'), function ($buildParameters, $columnName) {
127 | return collect($buildParameters)->pipeThrough([
128 | function ($collection) use ($columnName) {
129 | $columnClass = (string) $collection->get('class');
130 |
131 | if (! is_null($collection->get('methods'))) {
132 | $columnClass = $columnClass::make($columnName);
133 |
134 | collect($collection->get('methods'))->transform(function ($value, $key) use ($columnClass) {
135 | if (is_numeric($key)) {
136 | return $columnClass->$value();
137 | }
138 |
139 | return $columnClass->$key(...Arr::wrap($value));
140 | });
141 |
142 | return $columnClass;
143 | }
144 |
145 | return $columnClass::make($columnName);
146 | },
147 | ]);
148 | });
149 | }
150 |
151 | protected static function restoreAuditSelected($audit)
152 | {
153 | $morphClass = Relation::getMorphedModel($audit->auditable_type) ?? $audit->auditable_type;
154 |
155 | $record = $morphClass::find($audit->auditable_id);
156 |
157 | if (! $record) {
158 | self::unchangedAuditNotification();
159 |
160 | return;
161 | }
162 |
163 | if ($audit->event !== 'updated') {
164 | self::unchangedAuditNotification();
165 |
166 | return;
167 | }
168 |
169 | $restore = $audit->old_values;
170 |
171 | Arr::pull($restore, 'id');
172 |
173 | if (is_array($restore)) {
174 |
175 | foreach ($restore as $key => $item) {
176 | $decode = json_decode($item);
177 |
178 | if (json_last_error() === JSON_ERROR_NONE) {
179 | $restore[$key] = $decode;
180 | }
181 | }
182 |
183 | $record->fill($restore);
184 | $record->save();
185 |
186 | self::restoredAuditNotification();
187 |
188 | return;
189 | }
190 |
191 | self::unchangedAuditNotification();
192 | }
193 |
194 | protected static function restoredAuditNotification()
195 | {
196 | Notification::make()
197 | ->title(trans('filament-auditing::filament-auditing.notification.restored'))
198 | ->success()
199 | ->send();
200 | }
201 |
202 | protected static function unchangedAuditNotification()
203 | {
204 | Notification::make()
205 | ->title(trans('filament-auditing::filament-auditing.notification.unchanged'))
206 | ->warning()
207 | ->send();
208 | }
209 |
210 | protected function canCreate(): bool
211 | {
212 | return false;
213 | }
214 |
215 | protected function canEdit(Model $record): bool
216 | {
217 | return false;
218 | }
219 |
220 | protected function canDelete(Model $record): bool
221 | {
222 | return false;
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Filament Laravel Auditing
2 |
3 | [](https://packagist.org/packages/tapp/filament-auditing)
4 | 
5 | [](https://packagist.org/packages/tapp/filament-auditing)
6 |
7 | A Filament plugin for [Laravel Auditing](https://laravel-auditing.com/) package.
8 | This plugin contains a relation manager for audits that you can add to your Filament resources.
9 |
10 | This package provides a Filament resource manager that shows a table with all audits on view and edit pages and allows
11 | restore audits.
12 |
13 | ## Version Compatibility
14 |
15 | Filament | Filament Auditing
16 | :---------|:-----------------
17 | 2.x | 2.x
18 | 3.x | 3.x
19 | 4.x | 4.x
20 |
21 | ## Installation
22 |
23 | > [!IMPORTANT]
24 | > Please check the **Filament Auditing** plugin version you should use in the **Version Compatibility** table above.
25 |
26 | > **Note**
27 | > This plugin uses the [Laravel Auditing](https://laravel-auditing.com/) package. First install and configure this
28 | > package.
29 |
30 | You can install the plugin via Composer.
31 |
32 | ### For Filament 3
33 |
34 | ```bash
35 | composer require tapp/filament-auditing:"^3.0"
36 | ```
37 |
38 | ### For Filament 4
39 |
40 | Please visit the **[4.x](https://github.com//TappNetwork/filament-auditing/tree/4.x)** branch for a detailed documention of the new features available in version 4.
41 |
42 | ```bash
43 | composer require tapp/filament-auditing:"^4.0"
44 | ```
45 |
46 | ### For Filament 2
47 |
48 | Please visit the **[2.x](https://github.com//TappNetwork/filament-auditing/tree/2.x)** branch for a detailed documention about version 2.
49 |
50 | ```bash
51 | composer require tapp/filament-auditing:"^2.0"
52 | ```
53 |
54 | You can publish the view files with:
55 |
56 | ```bash
57 | php artisan vendor:publish --tag="filament-auditing-views"
58 | ```
59 | You can publish the translation files with:
60 |
61 | ```bash
62 | php artisan vendor:publish --tag="filament-auditing-translations"
63 | ```
64 |
65 | You can publish the config file with:
66 |
67 | ```bash
68 | php artisan vendor:publish --tag="filament-auditing-config"
69 | ```
70 |
71 | This is the content of the published config file:
72 |
73 | ```php
74 | [
79 | 'column' => 'created_at',
80 | 'direction' => 'desc',
81 | ],
82 |
83 | 'is_lazy' => true,
84 |
85 | 'audits_extend' => [
86 | // 'url' => [
87 | // 'class' => \Filament\Tables\Columns\TextColumn::class,
88 | // 'methods' => [
89 | // 'sortable',
90 | // 'searchable' => true,
91 | // 'default' => 'N/A'
92 | // ]
93 | // ],
94 | ]
95 |
96 | 'custom_audits_view' => false,
97 |
98 | 'custom_view_parameters' => [
99 | ],
100 |
101 | 'mapping' => [
102 | ],
103 | ];
104 | ```
105 |
106 | The `audits_sort` can be used to change the default sort on the audits table.
107 |
108 | ## Usage
109 |
110 | To show the audits table in your Filament resource, just add `AuditsRelationManager::class` on your
111 | resource's `getRelations` method:
112 |
113 | ```php
114 | use Tapp\FilamentAuditing\RelationManagers\AuditsRelationManager;
115 |
116 | public static function getRelations(): array
117 | {
118 | return [
119 | // ...
120 | AuditsRelationManager::class,
121 | ];
122 | }
123 | ```
124 |
125 | That's it, you're all set!
126 |
127 | If you access your resource, and edit some data, you will now see the audits table on edit and view pages.
128 |
129 | ### Extending Columns
130 |
131 | In case you need to add a column to the AuditsRelationManager that does
132 | not already exist in the table, you can add it in the config using the format denoted in the example below, and it will be
133 | prepended to the table builder. The name of the column to be added is the key of an associative array that contains other information about the class, as shown in the example below. The class instance of the column must be added, but the methods can be left out if not required, or added wherever necessary.
134 |
135 | ```php
136 | [
141 | 'url' => [
142 | 'class' => \Filament\Tables\Columns\TextColumn::class, // required
143 | 'methods' => [
144 | 'sortable',
145 | 'default' => 'NIL',
146 | ],
147 | ],
148 | ]
149 |
150 | ];
151 | ```
152 |
153 | After adding this information in the config, please run this command for changes to take place.
154 |
155 | ```bash
156 | php artisan optimize
157 | ```
158 |
159 | Methods with two or more parameters can be specified with an array like so:
160 |
161 | ```php
162 | [
167 | 'created_at' => [
168 | 'class' => \Filament\Tables\Columns\TextColumn::class, // required
169 | 'methods' => [
170 | 'sortable',
171 | 'date' => ['Y-m-d H:i:s', 'America/New_York'],
172 | ],
173 | ],
174 | ]
175 |
176 | ];
177 | ```
178 |
179 | ### Custom View Data Formatting
180 |
181 | 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):
182 |
183 | #### Show a related column instead of foreign id
184 |
185 | 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:
186 |
187 | ```bash
188 | 'mapping' => [
189 | 'user_id' => [
190 | 'model' => App\Models\User::class,
191 | 'field' => 'name',
192 | 'label' => 'User',
193 | ],
194 | ],
195 | ```
196 |
197 | 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.
198 |
199 | #### Customizing the Old and New Values
200 |
201 | 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:
202 | - the first parameter contains the name of the field (`old_values` or `new_values`).
203 | - the second parameter contains de current audit record
204 |
205 | This method must return the formatted audit fields.
206 |
207 | 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:
208 |
209 | ```php
210 | {$field});
230 |
231 | $formattedResult = '';
232 |
233 | foreach ($fields as $key => $value) {
234 | $formattedResult .= '';
235 | $formattedResult .= match ($key) {
236 | 'user_id' => 'User : '.User::find($record->{$field}['user_id'])?->name.' ',
237 | 'title' => 'Title : '.(string) str($record->{$field}['title'])->title().' ',
238 | 'order' => 'Order : '.$record->{$field}['order'].' ',
239 | 'content' => 'Content : '.$record->{$field}['content'].' ',
240 | default => ' - ',
241 | };
242 | $formattedResult .= ' ';
243 | }
244 |
245 | $formattedResult .= ' ';
246 |
247 | return new HtmlString($formattedResult);
248 | }
249 |
250 | public function user(): BelongsTo
251 | {
252 | return $this->belongsTo(User::class);
253 | }
254 | }
255 | ```
256 |
257 | #### Customizing the Entire View Content
258 |
259 | 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:
260 |
261 | ```php
262 | 'custom_audits_view' => true,
263 | ```
264 |
265 | 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.
266 | For example:
267 |
268 | ```php
269 | @php
270 | $type = (string) str(class_basename($owner))->lower();
271 | @endphp
272 |
273 | @if(isset($records))
274 |
275 |
276 | @foreach($headers as $header)
277 |
278 | {{$header}}
279 |
280 | @endforeach
281 |
282 | @foreach($records as $audit)
283 |
284 | @foreach ($audit->getModified() as $attribute => $modified)
285 |
286 | @lang($type.'.metadata', $audit->getMetadata())
287 |
288 | @php
289 | $current = $type.'.'.$audit->event.'.modified.'.$attribute;
290 |
291 | $modified['new'] = $owner->formatFieldForPresentation($attribute, $modified['new']);
292 |
293 | if (isset($modified['old'])) {
294 | $modified['old'] = $owner->formatFieldForPresentation($attribute, $modified['old']);
295 | }
296 | @endphp
297 |
298 | @lang($current, $modified)
299 |
300 | @endforeach
301 |
302 | @endforeach
303 |
304 | @else
305 |
306 | @lang($type.'.unavailable_audits')
307 |
308 | @endif
309 | ```
310 |
311 | 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:
312 |
313 | ```php
314 | 'custom_view_parameters' => [
315 | 'headers' => [
316 | 'Audit',
317 | ],
318 | ],
319 | ```
320 |
321 | 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.
322 |
323 | For example, in an `Article` model, to return the name of the related user:
324 |
325 | ```php
326 | public function formatFieldForPresentation($field, $value)
327 | {
328 | return match($field) {
329 | 'user_id' => $value ? optional(User::find($value))->name : $value,
330 | default => $value,
331 | };
332 | }
333 | ```
334 |
335 | An example of the `article.php` lang file content used in the `custom-audit-content.blade.php` view code above:
336 |
337 | ```php
338 | 'No article audits available',
342 |
343 | 'metadata' => 'On :audit_created_at, :user_name [:audit_ip_address] :audit_event this record via :audit_url',
344 |
345 | 'updated' => [
346 | 'modified' => [
347 | 'order' => 'The Order has been modified from :old to :new ',
348 | 'title' => 'The Title has been modified from :old to :new ',
349 | 'content' => 'The Content has been modified from :old to :new ',
350 | 'user_id' => 'The User has been modified from :old to :new ',
351 | ],
352 | ],
353 | ];
354 | ```
355 |
356 | ### Permissions
357 |
358 | Two permissions are registered by default, allowing access to:
359 |
360 | - `audit`: view audits
361 | - `restoreAudit`: restore audits
362 |
363 | You can override these permissions by adding a policy with `audit` and `restoreAudit`.
364 |
365 | ### Event emitted
366 |
367 | The `auditRestored` event is emitted when an audit is restored, so you could register a listener using the $listeners property to execute some extra code after the audit is restored.
368 |
369 | E.g.: on Edit page of your resource:
370 |
371 | ```php
372 | protected $listeners = [
373 | 'auditRestored',
374 | ];
375 |
376 | public function auditRestored()
377 | {
378 | // your code
379 | }
380 | ```
381 |
382 | ### Event listener
383 |
384 | The audits relation manager listen to the `updateAuditsRelationManager` event to refresh the audits table.
385 |
386 | So you can dispatch this event in the Edit page of your resource (e.g.: in a edit page of a `PostResource` -> `app/Filament/Resources/PostResource/Pages/EditPost.php`) when the form is updated:
387 |
388 | ```php
389 | protected function afterSave(): void
390 | {
391 | $this->dispatch('updateAuditsRelationManager');
392 | }
393 | ```
394 |
395 | > [!WARNING]
396 | > When dispaching this event, set the [is_lazy](https://filamentphp.com/docs/3.x/panels/resources/relation-managers#disabling-lazy-loading) configuration to `false`, on `filament-auditing.php`
397 | > config file, to avoid this exception: "Typed property Filament\Resources\RelationManagers\RelationManager::$table
398 | > must not be accessed before initialization"
399 |
--------------------------------------------------------------------------------