├── 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 | 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 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/tapp/filament-auditing.svg?style=flat-square)](https://packagist.org/packages/tapp/filament-auditing) 4 | ![Code Style Action Status](https://github.com/TappNetwork/filament-auditing/actions/workflows/fix-php-code-style-issues.yml/badge.svg) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/tapp/filament-auditing.svg?style=flat-square)](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 = ''; 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 | --------------------------------------------------------------------------------