[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: pxlrbt\n"
  },
  {
    "path": ".github/workflows/code-style.yml",
    "content": "name: Code Style\non:\n  pull_request:\n  push:\n    branches:\n      - main\n\njobs:\n  php-cs-fixer:\n    name: Run Laravel Pint\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n\n    steps:\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: '8.4'\n\n      - name: Git checkout\n        uses: actions/checkout@v3\n        with:\n          ref: ${{ github.head_ref }}\n\n      - name: Install dependencies\n        run: composer install -n --prefer-dist\n\n      - name: Run Laravel Pint\n        run: ./vendor/bin/pint\n\n      - name: Commit changes\n        uses: stefanzweifel/git-auto-commit-action@v4\n        with:\n          commit_message: Apply style changes\n          file_pattern: '*.php'\n"
  },
  {
    "path": ".gitignore",
    "content": "/vendor\ncomposer.phar\ncomposer.lock\n.DS_Store\n.idea\nphpunit.xml\n.phpunit.result.cache\n.php-cs-fixer.cache\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) [2022] [Dennis Koch]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"pxlrbt/filament-activity-log\",\n    \"description\": \"Spatie's Laravel Activity Log integrated into Filament\",\n    \"license\": \"MIT\",\n    \"keywords\": [\n        \"activity log\",\n        \"filament\",\n        \"laravel-filament\"\n    ],\n    \"authors\": [\n        {\n            \"name\": \"Dennis Koch\",\n            \"email\": \"info@pixelarbeit.de\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^8.4\",\n        \"filament/filament\": \"^4.0|^5.0\",\n        \"spatie/laravel-activitylog\": \"^5.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"pxlrbt\\\\FilamentActivityLog\\\\\": \"src/\"\n        }\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"providers\": [\n                \"\\\\pxlrbt\\\\FilamentActivityLog\\\\FilamentActivityLogServiceProvider\"\n            ]\n        }\n    },\n    \"require-dev\": {\n        \"laravel/pint\": \"^1.5\"\n    },\n    \"scripts\": {\n        \"pint\": \"vendor/bin/pint\"\n    }\n}\n"
  },
  {
    "path": "readme.md",
    "content": "![header](./.github/resources/header.png)\n\n# Filament Activity Log\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/pxlrbt/filament-activity-log.svg?include_prereleases)](https://packagist.org/packages/pxlrbt/filament-activity-log)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE.md)\n![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/pxlrbt/filament-activity-log/code-style.yml?branch=main&label=Code%20style&style=flat-square)\n[![Total Downloads](https://img.shields.io/packagist/dt/pxlrbt/filament-activity-log.svg)](https://packagist.org/packages/pxlrbt/filament-activity-log)\n\nThis package adds pages to the Filament Admin panel to view the activity log generated by [`spatie/laravel-activitylog`](https://github.com/spatie/laravel-activitylog).\n\n![Screenshot](./.github/resources/screenshot.png)\n\n## Installation\n\n| Plugin Version | Filament Version | Activitylog | PHP Version |\n|----------------|------------------|-------------|-------------|\n| 0.1.x          | 2.x              | 4.x         | \\> 8.0      |\n| 1.x            | 3.x              | 4.x         | \\> 8.1      |\n| 2.x            | 4.x, 5.x         | 4.x         | \\> 8.1      |\n| 3.x            | 5.x              | 5.x         | \\> 8.4      |\n\nInstall via Composer.\n\n**Requires PHP 8.1, Filament 4.0 or 5.0, and spatie/laravel-activitylog 4.7 or 5.0**\n\n```bash\ncomposer require pxlrbt/filament-activity-log\n```\n\n> **Warning**\n> This plugin offers two pages: one listing activities **on a subject** (use `ListActivitiesBySubject`) and one listing activities **caused by** a record such as a user (use `ListActivitiesByCauser`). You need [`spatie/laravel-activitylog`](https://github.com/spatie/laravel-activitylog) installed and configured for it to work. The subject page uses the `LogsActivity` trait's `activitiesAsSubject()` relation; the causer page uses the `CausesActivity` trait's `activitiesAsCauser()` relation.\n\n## Filament v4 Upgrade\nMake sure you have a custom theme, add this line and recompile: `@import '../../../../vendor/pxlrbt/filament-activity-log/resources/css/styles.css';`\n\n## Usage\n\nMake sure you use a **custom theme** and the vendor folder for this plugins is published, so that it includes the Tailwind CSS classes.\n\n## Listing activities for a subject\n\n![Screenshot](./.github/resources/screenshot.png)\n\nUse `ListActivitiesBySubject` to show all activities recorded **on** a record (e.g. every change to an order).\n\n### Setup spatie/laravel-activitylog\n\nMake sure your resource model uses the `LogsActivity` trait.\n\n```php\n<?php\n\nuse Spatie\\Activitylog\\Models\\Concerns\\LogsActivity;\n\nclass Order extends Model\n{\n    use LogsActivity;\n}\n```\n\n### Create a ListActivitiesBySubject page\n\nCreate the page inside your resource's `Pages/` directory. Replace `OrderResource` with your resource.\n\n```php\n<?php\n\nnamespace App\\Filament\\Resources\\Orders\\Pages;\n\nuse pxlrbt\\FilamentActivityLog\\Pages\\ListActivitiesBySubject;\n\nclass ListOrderActivities extends ListActivitiesBySubject\n{\n    protected static string $resource = OrderResource::class;\n}\n```\n\n> **Note**\n> The legacy class `ListActivities` is kept as an abstract alias of `ListActivitiesBySubject`, so existing subclasses continue to work.\n\n### Register the page\n\nAdd the page to your resource's `getPages()` method.\n\n```php\npublic static function getPages(): array\n{\n    return [\n        'index' => Pages\\ListOrders::route('/'),\n        'create' => Pages\\CreateOrder::route('/create'),\n        'activities' => Pages\\ListOrderActivities::route('/{record}/activities'),\n        'edit' => Pages\\EditOrder::route('/{record}/edit'),\n    ];\n}\n```\n\n\n## Listing activities caused by a record\n\nUse `ListActivitiesByCauser` to show all activities a record (typically a user) has caused across every subject. Each row links to the affected subject's resource when one is registered.\n\n### Setup spatie/laravel-activitylog\n\nMake sure your user model uses the `CausesActivity` trait.\n\n```php\n<?php\n\nuse Spatie\\Activitylog\\Models\\Concerns\\CausesActivity;\n\nclass User extends Authenticatable implements FilamentUser\n{\n    use CausesActivity;\n}\n```\n\n### Create a ListActivitiesByCauser page\n\nCreate the page inside your `UserResource`'s `Pages/` directory.\n\n```php\n<?php\n\nnamespace App\\Filament\\Resources\\Users\\Pages;\n\nuse pxlrbt\\FilamentActivityLog\\Pages\\ListActivitiesByCauser;\n\nclass ListUserActivities extends ListActivitiesByCauser\n{\n    protected static string $resource = UserResource::class;\n}\n```\n\nSee https://spatie.be/docs/laravel-activitylog/v5/advanced-usage/logging-model-events for more information on the topic.\n\n### Register the page\n\nAdd the page to your resource's `getPages()` method.\n\n```php\npublic static function getPages(): array\n{\n    return [\n        'index' => Pages\\ListUsers::route('/'),\n        'create' => Pages\\CreateUser::route('/create'),\n        'activities' => Pages\\ListUserActivities::route('/{record}/activities'),\n        'edit' => Pages\\EditUser::route('/{record}/edit'),\n    ];\n}\n```\n\n## Contributing\n\nIf you want to contribute to this packages, you may want to test it in a real Filament project:\n\n- Fork this repository to your GitHub account.\n- Create a Filament app locally.\n- Clone your fork in your Filament app's root directory.\n- In the `/filament-activity-log` directory, create a branch for your fix, e.g. `fix/error-message`.\n\nInstall the packages in your app's `composer.json`:\n\n```json\n\"require\": {\n    \"pxlrbt/filament-activity-log\": \"dev-fix/error-message as main-dev\",\n},\n\"repositories\": [\n    {\n        \"type\": \"path\",\n        \"url\": \"filament-activity-log\"\n    }\n]\n```\n\nNow, run `composer update`.\n"
  },
  {
    "path": "resources/css/styles.css",
    "content": "@source '../views/**'\n"
  },
  {
    "path": "resources/lang/ar/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'سجل عمليات',\n\n    'title' => 'سجل عمليات :record',\n\n    'default_datetime_format' => 'Y-m-d, H:i:s',\n\n    'table' => [\n        'field' => 'الحقل',\n        'old' => 'سابقاً',\n        'new' => 'حالياً',\n        'restore' => 'أسترجاع',\n    ],\n\n    'events' => [\n        'updated' => 'تحديث',\n        'created' => 'إنشاء',\n        'deleted' => 'حذف',\n        'restored' => 'استعادة',\n        'restore_successful' => 'تم الاسترجاع بنجاح',\n        'restore_failed' => 'فشل الاستراجع',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/ckb/activities.php",
    "content": "<?php\n\nreturn [\n\n    'breadcrumb' => 'نرخی پێشوو',\n\n    'title' => 'نرخەکانی پێشووی :record',\n\n    'default_datetime_format' => 'Y-m-d, H:i:s',\n\n    'table' => [\n        'field' => 'خانە',\n        'old' => 'کۆن',\n        'new' => 'نوێ',\n    ],\n\n    'events' => [\n        'updated' => 'نوێکراوەتەوە',\n        'Created' => 'دروستکراوە',\n        'deleted' => 'سڕایەوە',\n        'restored' => 'گەڕاندنەوە',\n        'restore_successful' => 'بە سەرکەوتوویی گەڕێنرایەوە',\n        'restore_failed' => 'گەڕاندنەوە شکستی هێنا',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/cs/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'Log',\n\n    'title' => 'Log entity \":record\"',\n\n    'default_datetime_format' => 'j.n.Y H:i:s',\n\n    'table' => [\n        'field' => 'Pole',\n        'old' => 'Původní',\n        'new' => 'Nové',\n        'restore' => 'Obnovit',\n    ],\n\n    'events' => [\n        'updated' => 'Upraveno',\n        'created' => 'Vytvořeno',\n        'deleted' => 'Smazáno',\n        'restored' => 'Obnoveno',\n        'restore_successful' => 'Úspěšně obnoveno',\n        'restore_failed' => 'Obnovení selhalo',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/de/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'Historie',\n\n    'title' => 'Historie :record',\n\n    'default_datetime_format' => 'd.m.Y, H:i:s \\U\\h\\r',\n\n    'table' => [\n        'field' => 'Feld',\n        'old' => 'Alt',\n        'new' => 'Neu',\n        'restore' => 'Wiederherstellen',\n    ],\n\n    'events' => [\n        'updated' => 'Aktualisiert',\n        'created' => 'Erstellt',\n        'deleted' => 'Gelöscht',\n        'restored' => 'Wiederhergestellt',\n        'restore_successful' => 'Erfolgreich wiederhergestellt',\n        'restore_failed' => 'Wiederherstellung fehlgeschlagen',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/en/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'History',\n\n    'title' => 'History :record',\n\n    'default_datetime_format' => 'Y-m-d, H:i:s',\n\n    'table' => [\n        'field' => 'Field',\n        'old' => 'Old',\n        'new' => 'New',\n        'restore' => 'Restore',\n    ],\n\n    'events' => [\n        'updated' => 'Updated',\n        'created' => 'Created',\n        'deleted' => 'Deleted',\n        'restored' => 'Restored',\n        'restore_successful' => 'Restored successfully',\n        'restore_failed' => 'Restore failed',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/es/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'Historial',\n\n    'title' => 'Historial :record',\n\n    'default_datetime_format' => 'd/m/Y, H:i:s',\n\n    'table' => [\n        'field' => 'Campo',\n        'old' => 'Anterior',\n        'new' => 'Nuevo',\n        'restore' => 'Restaurar',\n    ],\n\n    'events' => [\n        'updated' => 'Actualizado',\n        'created' => 'Creado',\n        'deleted' => 'Eliminado',\n        'restored' => 'Restaurado',\n        'restore_successful' => 'Restauración exitosa',\n        'restore_failed' => 'Restauración fallida',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/fa/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'تاریخچه',\n\n    'title' => 'تاریخچه :record',\n\n    'default_datetime_format' => 'Y-m-d، H:i:s',\n\n    'table' => [\n        'field' => 'فیلد',\n        'old' => 'قدیمی',\n        'new' => 'جدید',\n        'restore' => 'بازیابی',\n    ],\n\n    'events' => [\n        'updated' => 'به‌روزرسانی شد',\n        'created' => 'ایجاد شد',\n        'deleted' => 'حذف شد',\n        'restored' => 'بازیابی شد',\n        'restore_successful' => 'با موفقیت بازیابی شد',\n        'restore_failed' => 'بازیابی ناموفق بود',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/fr/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'Historique',\n\n    'title' => 'Historique :record',\n\n    'default_datetime_format' => 'd/m/Y, H:i:s',\n\n    'table' => [\n        'field' => 'Champ',\n        'old' => 'Ancien',\n        'new' => 'Nouveau',\n        'restore' => 'Restaurer',\n    ],\n\n    'events' => [\n        'updated' => 'Mis à jour',\n        'created' => 'Créé',\n        'deleted' => 'Effacé',\n        'restored' => 'Restauré',\n        'restore_successful' => 'Restauré avec succès',\n        'restore_failed' => 'Échec de la restauration',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/id/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'Riwayat',\n\n    'title' => 'Riwayat :record',\n\n    'default_datetime_format' => 'd/m/Y H:i:s',\n\n    'table' => [\n        'field' => 'Bagian',\n        'old' => 'Sebelum',\n        'new' => 'Sesudah',\n        'restore' => 'Pulihkan',\n    ],\n\n    'events' => [\n        'updated' => 'Terbarui',\n        'created' => 'Terbuat',\n        'deleted' => 'Terhapus',\n        'restored' => 'Terpulihkan',\n        'restore_successful' => 'Sukses memulihkan',\n        'restore_failed' => 'Gagal memulihkan',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/it/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'Cronologia',\n\n    'title' => 'Cronologia :record',\n\n    'default_datetime_format' => 'd/m/Y, H:i:s',\n\n    'table' => [\n        'field' => 'Campo',\n        'old' => 'Vecchio',\n        'new' => 'Nuovo',\n        'restore' => 'Ripristina',\n    ],\n\n    'events' => [\n        'updated' => 'Aggiornato',\n        'created' => 'Creato',\n        'deleted' => 'Eliminato',\n        'restored' => 'Ripristinato',\n        'restore_successful' => 'Ripristinato con successo',\n        'restore_failed' => 'Ripristino fallito',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/nl/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'Geschiedenis',\n\n    'title' => 'Geschiedenis :record',\n\n    'default_datetime_format' => 'Y-m-d, H:i:s',\n\n    'table' => [\n        'field' => 'Veld',\n        'old' => 'Oud',\n        'new' => 'Nieuw',\n        'restore' => 'Herstellen',\n    ],\n\n    'events' => [\n        'updated' => 'Bewerkt',\n        'created' => 'Aangemaakt',\n        'deleted' => 'Verwijderd',\n        'restored' => 'Hersteld',\n        'restore_successful' => 'Succesvol hersteld',\n        'restore_failed' => 'Herstellen mislukt',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/pt_BR/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'Histórico',\n\n    'title' => 'Histórico :record',\n\n    'default_datetime_format' => 'd/m/Y H:i:s',\n\n    'table' => [\n        'field' => 'Campo',\n        'old' => 'Antes',\n        'new' => 'Depois',\n        'restore' => 'Restaurado',\n    ],\n\n    'events' => [\n        'updated' => 'Atualizado',\n        'created' => 'Criado',\n        'deleted' => 'Excluído',\n        'restored' => 'Restaurado',\n        'restore_successful' => 'Restaurado com sucesso',\n        'restore_failed' => 'Falha na restauração',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/tr/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => 'Geçmiş',\n\n    'title' => ':record Geçmişi',\n\n    'default_datetime_format' => 'd.m.Y, H:i:s',\n\n    'table' => [\n        'field' => 'Alan',\n        'old' => 'Eski Değer',\n        'new' => 'Yeni Değer',\n        'restore' => 'Geri Yükle',\n    ],\n\n    'events' => [\n        'updated' => 'Güncellendi',\n        'created' => 'Oluşturuldu',\n        'deleted' => 'Silindi',\n        'restored' => 'Geri Yüklendi',\n        'restore_successful' => 'Başarıyla Geri Yüklendi',\n        'restore_failed' => 'Geri Yükleme Başarısız',\n    ],\n];\n"
  },
  {
    "path": "resources/lang/zh_TW/activities.php",
    "content": "<?php\n\nreturn [\n    'breadcrumb' => '歷史記錄',\n\n    'title' => '歷史記錄：:record',\n\n    'default_datetime_format' => 'Y-m-d H:i:s',\n\n    'table' => [\n        'field' => '欄位',\n        'old' => '舊值',\n        'new' => '新值',\n        'restore' => '還原',\n    ],\n\n    'events' => [\n        'updated' => '已更新',\n        'created' => '已建立',\n        'deleted' => '已刪除',\n        'restored' => '已還原',\n        'restore_successful' => '還原成功',\n        'restore_failed' => '還原失敗',\n    ],\n];\n"
  },
  {
    "path": "resources/views/pages/list-activities-by-causer.blade.php",
    "content": "<x-filament-panels::page>\n    <div class=\"space-y-6\">\n        @foreach($this->getActivities() as $activityItem)\n\n            @php\n                /* @var \\Spatie\\Activitylog\\Models\\Activity $activityItem */\n                $changes = $activityItem->attribute_changes ?? collect();\n                $resource = $this->getSubjectResource($activityItem->subject_type);\n            @endphp\n\n            <div @class([\n                'p-2 space-y-2 bg-white rounded-xl shadow',\n                'dark:border-gray-600 dark:bg-gray-800',\n            ])>\n                <div class=\"p-2\">\n                    <div class=\"flex justify-between\">\n                        <div class=\"flex flex-col text-start\">\n                            <span class=\"font-bold\">\n                                @if ($resource)\n                                    {{ $resource::getModelLabel() }}:\n                                    @if ($activityItem->subject && $resource::hasRecordTitle())\n                                        @php\n                                            $url = $activityItem->subject->exists\n                                                ? $resource::getUrl('edit', ['record' => $activityItem->subject])\n                                                : null;\n                                        @endphp\n                                        @if ($url)\n                                            <a href=\"{{ $url }}\" class=\"underline\">{{ $resource::getRecordTitle($activityItem->subject) }}</a>\n                                        @else\n                                            {{ $resource::getRecordTitle($activityItem->subject) }}\n                                        @endif\n                                    @else\n                                        {{ $activityItem->subject_id }}\n                                    @endif\n                                @else\n                                    {{ $activityItem->subject_type }}: {{ $activityItem->subject_id }}\n                                @endif\n                            </span>\n                            <span class=\"text-xs text-gray-500\">\n                                {{ __('filament-activity-log::activities.events.' . $activityItem->event) }} {{ $activityItem->created_at->format(__('filament-activity-log::activities.default_datetime_format')) }}\n                            </span>\n                        </div>\n                    </div>\n                </div>\n\n                @if ($changes->isNotEmpty())\n                    <table class=\"fi-ta-table w-full overflow-hidden text-sm\">\n                        <thead>\n                            <th class=\"fi-ta-header-cell\">\n                                {{ __('filament-activity-log::activities.table.field') }}\n                            </th>\n                            <th class=\"fi-ta-header-cell\">\n                                {{ __('filament-activity-log::activities.table.old') }}\n                            </th>\n                            <th class=\"fi-ta-header-cell\">\n                                {{ __('filament-activity-log::activities.table.new') }}\n                            </th>\n                        </thead>\n\n                        <tbody>\n                            @foreach (data_get($changes, 'attributes', []) as $field => $change)\n                                @php\n                                    $oldValue = data_get($changes, \"old.{$field}\", '');\n                                    $newValue = data_get($changes, \"attributes.{$field}\", '');\n                                @endphp\n                            <tr\n                                @class([\n                                    'fi-ta-row',\n                                    'bg-gray-100/30' => $loop->even\n                                ])\n                            >\n                                <td class=\"fi-ta-cell px-4 py-2 align-top sm:first-of-type:ps-6 sm:last-of-type:pe-6\" width=\"20%\">\n                                    {{ $this->getFieldLabel($resource, $field) }}\n                                </td>\n                                <td width=\"40%\" class=\"fi-ta-cell px-4 py-2 align-top break-all whitespace-normal\">\n                                    @if(is_array($oldValue))\n                                        <pre class=\"text-xs text-gray-500\">{{ json_encode($oldValue, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) }}</pre>\n                                    @elseif (is_bool($oldValue))\n                                        <span class=\"text-xs text-gray-500\">{{ $oldValue ? 'true' : 'false' }}</span>\n                                    @else\n                                        {{ $oldValue }}\n                                    @endif\n                                </td>\n                                <td width=\"40%\" class=\"fi-ta-cell px-4 py-2 align-top break-all whitespace-normal\">\n                                    @if (is_bool($newValue))\n                                        <span class=\"text-xs text-gray-500\">{{ $newValue ? 'true' : 'false' }}</span>\n                                    @elseif(is_array($newValue))\n                                        <pre class=\"text-xs text-gray-500\">{{ json_encode($newValue, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) }}</pre>\n                                    @else\n                                        {{ $newValue }}\n                                    @endif\n                                </td>\n                            </tr>\n                            @endforeach\n                        </tbody>\n                    </table>\n                @endif\n            </div>\n        @endforeach\n\n        <x-filament::pagination\n            currentPageOptionProperty=\"recordsPerPage\"\n            :page-options=\"$this->getRecordsPerPageSelectOptions()\"\n            :paginator=\"$this->getActivities()\"\n        />\n    </div>\n</x-filament-panels::page>\n"
  },
  {
    "path": "resources/views/pages/list-activities-by-subject.blade.php",
    "content": "@php\n    use \\Illuminate\\Support\\Js;\n@endphp\n<x-filament-panels::page>\n    <div class=\"space-y-6\">\n        @foreach($this->getActivities() as $activityItem)\n\n            @php\n                /* @var \\Spatie\\Activitylog\\Models\\Activity $activityItem */\n                $changes = $activityItem->attribute_changes ?? collect();\n            @endphp\n\n            <div @class([\n                'p-2 space-y-2 bg-white rounded-xl shadow',\n                'dark:border-gray-600 dark:bg-gray-800',\n            ])>\n                <div class=\"p-2\">\n                    <div class=\"flex justify-between\">\n                        <div class=\"flex items-center gap-4\">\n                            @if ($activityItem->causer)\n                                <x-filament-panels::avatar.user :user=\"$activityItem->causer\" class=\"!w-7 !h-7\"/>\n                            @endif\n                            <div class=\"flex flex-col text-start\">\n                                <span class=\"font-bold\">{{ $activityItem->causer?->name }}</span>\n                                <span class=\"text-xs text-gray-500\">\n                                    {{ __('filament-activity-log::activities.events.' . $activityItem->event) }} {{ $activityItem->created_at->format(__('filament-activity-log::activities.default_datetime_format')) }}\n                                </span>\n                            </div>\n                        </div>\n                        <div class=\"flex flex-col text-xs text-gray-500 justify-end\">\n                            @if ($this->canRestoreActivity() && $changes->isNotEmpty())\n                                <x-filament::button\n                                    tag=\"button\"\n                                    icon=\"heroicon-o-arrow-path-rounded-square\"\n                                    labeled-from=\"sm\"\n                                    color=\"gray\"\n                                    class=\"right\"\n                                    wire:click=\"restoreActivity({{ Js::from($activityItem->getKey()) }})\"\n                                >\n                                    @lang('filament-activity-log::activities.table.restore')\n                                </x-filament::button>\n                            @endif\n                        </div>\n                    </div>\n                </div>\n\n                @if ($changes->isNotEmpty())\n                    <table class=\"fi-ta-table w-full overflow-hidden text-sm\">\n                        <thead>\n                            <th class=\"fi-ta-header-cell\">\n                                {{ __('filament-activity-log::activities.table.field') }}\n                            </th>\n                            <th class=\"fi-ta-header-cell\">\n                                {{ __('filament-activity-log::activities.table.old') }}\n                            </th>\n                            <th class=\"fi-ta-header-cell\">\n                                {{ __('filament-activity-log::activities.table.new') }}\n                            </th>\n                        </thead>\n\n                        <tbody>\n                            @foreach (data_get($changes, 'attributes', []) as $field => $change)\n                                @php\n                                    $oldValue = isset($changes['old'][$field]) ? $changes['old'][$field] : '';\n                                    $newValue = isset($changes['attributes'][$field]) ? $changes['attributes'][$field] : '';\n                                @endphp\n                            <tr\n                                @class([\n                                    'fi-ta-row',\n                                    'bg-gray-100/30' => $loop->even\n                                ])\n                            >\n                                <td class=\"fi-ta-cell px-4 py-2 align-top sm:first-of-type:ps-6 sm:last-of-type:pe-6\" width=\"20%\">\n                                    {{ $this->getFieldLabel($field) }}\n                                </td>\n                                <td width=\"40%\" class=\"fi-ta-cell px-4 py-2 align-top break-all whitespace-normal\">\n                                    @if(is_array($oldValue))\n                                        <pre class=\"text-xs text-gray-500\">{{ json_encode($oldValue, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) }}</pre>\n                                    @else\n                                        {{ $oldValue }}\n                                    @endif\n                                </td>\n                                <td width=\"40%\" class=\"fi-ta-cell px-4 py-2 align-top break-all whitespace-normal\">\n                                    @if (is_bool($newValue))\n                                        <span class=\"text-xs text-gray-500\">{{ $newValue ? 'true' : 'false' }}</span>\n                                    @elseif(is_array($newValue))\n                                        <pre class=\"text-xs text-gray-500\">{{ json_encode($newValue, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) }}</pre>\n                                    @else\n                                        {{ $newValue }}\n                                    @endif\n                                </td>\n                            </tr>\n                            @endforeach\n                        </tbody>\n                    </table>\n                @endif\n            </div>\n        @endforeach\n\n        <x-filament::pagination\n            currentPageOptionProperty=\"recordsPerPage\"\n            :page-options=\"$this->getRecordsPerPageSelectOptions()\"\n            :paginator=\"$this->getActivities()\"\n        />\n    </div>\n</x-filament-panels::page>\n"
  },
  {
    "path": "src/FilamentActivityLogServiceProvider.php",
    "content": "<?php\n\nnamespace pxlrbt\\FilamentActivityLog;\n\nuse Spatie\\LaravelPackageTools\\Package;\nuse Spatie\\LaravelPackageTools\\PackageServiceProvider;\n\nclass FilamentActivityLogServiceProvider extends PackageServiceProvider\n{\n    public static string $name = 'filament-activity-log';\n\n    public function configurePackage(Package $package): void\n    {\n        $package\n            ->name(static::$name)\n            ->hasViews()\n            ->hasTranslations();\n    }\n}\n"
  },
  {
    "path": "src/Pages/Concerns/CanPaginate.php",
    "content": "<?php\n\nnamespace pxlrbt\\FilamentActivityLog\\Pages\\Concerns;\n\nuse Filament\\Tables\\Enums\\PaginationMode;\nuse Illuminate\\Contracts\\Pagination\\CursorPaginator;\nuse Illuminate\\Contracts\\Pagination\\Paginator;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Pagination\\LengthAwarePaginator;\n\ntrait CanPaginate\n{\n    /**\n     * @var int | string | null\n     */\n    public $recordsPerPage = null;\n\n    protected int|string|null $defaultRecordsPerPageSelectOption = null;\n\n    public function updatedRecordsPerPage(): void\n    {\n        session()->put([\n            $this->getPerPageSessionKey() => $this->getRecordsPerPage(),\n        ]);\n\n        $this->resetPage();\n    }\n\n    protected function paginateQuery(Builder $query): Paginator|CursorPaginator\n    {\n        $perPage = $this->getRecordsPerPage();\n\n        $mode = $this->getPaginationMode();\n\n        if ($mode === PaginationMode::Simple) {\n            return $query->simplePaginate(\n                perPage: ($perPage === 'all') ? $query->toBase()->getCountForPagination() : $perPage,\n                pageName: $this->getPaginationPageName(),\n            );\n        }\n\n        if ($mode === PaginationMode::Cursor) {\n            return $query->cursorPaginate(\n                perPage: ($perPage === 'all') ? $query->toBase()->getCountForPagination() : $perPage,\n                cursorName: $this->getPaginationPageName(),\n            );\n        }\n\n        $total = $query->toBase()->getCountForPagination();\n\n        /** @var LengthAwarePaginator $records */\n        $records = $query->paginate(\n            perPage: ($perPage === 'all') ? $total : $perPage,\n            pageName: $this->getPaginationPageName(),\n            total: $total,\n        );\n\n        return $records->onEachSide(0);\n    }\n\n    public function getRecordsPerPage(): int|string|null\n    {\n        return $this->recordsPerPage;\n    }\n\n    public function getTablePage(): int\n    {\n        return $this->getPage($this->getPaginationPageName());\n    }\n\n    public function getDefaultRecordsPerPageSelectOption(): int|string\n    {\n        $option = session()->get(\n            $this->getPerPageSessionKey(),\n            $this->defaultRecordsPerPageSelectOption,\n        );\n\n        $pageOptions = $this->getRecordsPerPageSelectOptions();\n\n        if (in_array($option, $pageOptions)) {\n            return $option;\n        }\n\n        session()->remove($this->getPerPageSessionKey());\n\n        return $pageOptions[0];\n    }\n\n    public function getPaginationPageName(): string\n    {\n        return 'recordsPerPage';\n    }\n\n    public function getPerPageSessionKey(): string\n    {\n        $name = md5($this::class);\n\n        return \"pages.{$name}_per_page\";\n    }\n\n    /**\n     * @return array<int | string> | null\n     */\n    protected function getRecordsPerPageSelectOptions(): ?array\n    {\n        return [10, 25, 50];\n    }\n}\n"
  },
  {
    "path": "src/Pages/ListActivities.php",
    "content": "<?php\n\nnamespace pxlrbt\\FilamentActivityLog\\Pages;\n\n/**\n * @deprecated Use ListActivitiesBySubject directly\n */\nabstract class ListActivities extends ListActivitiesBySubject {}\n"
  },
  {
    "path": "src/Pages/ListActivitiesByCauser.php",
    "content": "<?php\n\nnamespace pxlrbt\\FilamentActivityLog\\Pages;\n\nuse Filament\\Facades\\Filament;\nuse Filament\\Forms\\Components\\Field;\nuse Filament\\Forms\\Components\\MorphToSelect;\nuse Filament\\Forms\\Contracts\\HasForms;\nuse Filament\\Pages\\Concerns\\InteractsWithFormActions;\nuse Filament\\Resources\\Pages\\Concerns\\InteractsWithRecord;\nuse Filament\\Resources\\Pages\\Page;\nuse Filament\\Schemas\\Schema;\nuse Filament\\Tables\\Enums\\PaginationMode;\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\nuse Illuminate\\Support\\Collection;\nuse Livewire\\WithPagination;\nuse pxlrbt\\FilamentActivityLog\\Pages\\Concerns\\CanPaginate;\n\nabstract class ListActivitiesByCauser extends Page implements HasForms\n{\n    use CanPaginate;\n    use InteractsWithFormActions;\n    use InteractsWithRecord;\n    use WithPagination;\n\n    protected string $view = 'filament-activity-log::pages.list-activities-by-causer';\n\n    /** @var array<class-string, Collection<string, string>> */\n    protected static array $fieldLabelMaps = [];\n\n    public function mount($record)\n    {\n        $this->record = $this->resolveRecord($record);\n        $this->recordsPerPage = $this->getDefaultRecordsPerPageSelectOption();\n    }\n\n    public function getBreadcrumb(): string\n    {\n        return static::$breadcrumb ?? __('filament-activity-log::activities.breadcrumb');\n    }\n\n    public function getTitle(): string\n    {\n        return __('filament-activity-log::activities.title', ['record' => $this->getRecordTitle()]);\n    }\n\n    public function getActivities()\n    {\n        return $this->paginateQuery(\n            $this->record->activitiesAsCauser()->with('subject')->latest()->getQuery()\n        );\n    }\n\n    public function getPaginationMode(): PaginationMode\n    {\n        return PaginationMode::Default;\n    }\n\n    public function getSubjectResource(string $subjectType): ?string\n    {\n        $modelClass = Relation::getMorphedModel($subjectType) ?? $subjectType;\n\n        return Filament::getModelResource($modelClass);\n    }\n\n    public function getFieldLabel(?string $resourceClass, string $name): string\n    {\n        if ($resourceClass === null) {\n            return $name;\n        }\n\n        static::$fieldLabelMaps[$resourceClass] ??= $this->createFieldLabelMap($resourceClass);\n\n        return static::$fieldLabelMaps[$resourceClass][$name] ?? $name;\n    }\n\n    /** @param  class-string  $resourceClass */\n    protected function createFieldLabelMap(string $resourceClass): Collection\n    {\n        $schema = $resourceClass::form(new Schema($this));\n\n        $components = collect($schema->getComponents());\n        $extracted = collect();\n\n        while (($component = $components->shift()) !== null) {\n            if ($component instanceof Field || $component instanceof MorphToSelect) {\n                $extracted->push($component);\n\n                continue;\n            }\n\n            $children = $component->getChildComponents();\n\n            if (count($children) > 0) {\n                $components = $components->merge($children);\n\n                continue;\n            }\n\n            $extracted->push($component);\n        }\n\n        return $extracted\n            ->filter(fn ($field) => $field instanceof Field)\n            ->mapWithKeys(fn (Field $field) => [\n                $field->getName() => $field->getLabel(),\n            ]);\n    }\n}\n"
  },
  {
    "path": "src/Pages/ListActivitiesBySubject.php",
    "content": "<?php\n\nnamespace pxlrbt\\FilamentActivityLog\\Pages;\n\nuse Exception;\nuse Filament\\Forms\\Components\\Field;\nuse Filament\\Forms\\Components\\MorphToSelect;\nuse Filament\\Forms\\Contracts\\HasForms;\nuse Filament\\Notifications\\Notification;\nuse Filament\\Pages\\Concerns\\InteractsWithFormActions;\nuse Filament\\Resources\\Pages\\Concerns\\InteractsWithRecord;\nuse Filament\\Resources\\Pages\\Page;\nuse Filament\\Schemas\\Schema;\nuse Filament\\Tables\\Enums\\PaginationMode;\nuse Illuminate\\Support\\Collection;\nuse Livewire\\WithPagination;\nuse pxlrbt\\FilamentActivityLog\\Pages\\Concerns\\CanPaginate;\n\nabstract class ListActivitiesBySubject extends Page implements HasForms\n{\n    use CanPaginate;\n    use InteractsWithFormActions;\n    use InteractsWithRecord;\n    use WithPagination;\n\n    protected string $view = 'filament-activity-log::pages.list-activities-by-subject';\n\n    protected static Collection $fieldLabelMap;\n\n    public function mount($record)\n    {\n        $this->record = $this->resolveRecord($record);\n        $this->recordsPerPage = $this->getDefaultRecordsPerPageSelectOption();\n    }\n\n    public function getBreadcrumb(): string\n    {\n        return static::$breadcrumb ?? __('filament-activity-log::activities.breadcrumb');\n    }\n\n    public function getTitle(): string\n    {\n        return __('filament-activity-log::activities.title', ['record' => $this->getRecordTitle()]);\n    }\n\n    public function getActivities()\n    {\n        return $this->paginateQuery(\n            $this->record->activitiesAsSubject()->with('causer')->latest()->getQuery()\n        );\n    }\n\n    public function getPaginationMode(): PaginationMode\n    {\n        return PaginationMode::Default;\n    }\n\n    public function getFieldLabel(string $name): string\n    {\n        static::$fieldLabelMap ??= $this->createFieldLabelMap();\n\n        return static::$fieldLabelMap[$name] ?? $name;\n    }\n\n    protected function createFieldLabelMap(): Collection\n    {\n        $schema = static::getResource()::form(new Schema($this));\n\n        $components = collect($schema->getComponents());\n        $extracted = collect();\n\n        while (($component = $components->shift()) !== null) {\n            if ($component instanceof Field || $component instanceof MorphToSelect) {\n                $extracted->push($component);\n\n                continue;\n            }\n\n            $children = $component->getChildComponents();\n\n            if (count($children) > 0) {\n                $components = $components->merge($children);\n\n                continue;\n            }\n\n            $extracted->push($component);\n        }\n\n        return $extracted\n            ->filter(fn ($field) => $field instanceof Field)\n            ->mapWithKeys(fn (Field $field) => [\n                $field->getName() => $field->getLabel(),\n            ]);\n    }\n\n    public function canRestoreActivity(): bool\n    {\n        return static::getResource()::canRestore($this->record);\n    }\n\n    public function restoreActivity(int|string $key)\n    {\n        if (! $this->canRestoreActivity()) {\n            abort(403);\n        }\n\n        $activity = $this->record->activitiesAsSubject()\n            ->whereKey($key)\n            ->first();\n\n        $oldAttributes = data_get($activity, 'attribute_changes.old');\n\n        if ($oldAttributes === null) {\n            $this->sendRestoreFailureNotification();\n\n            return;\n        }\n\n        try {\n            $this->record->update($oldAttributes);\n\n            $this->sendRestoreSuccessNotification();\n        } catch (Exception $e) {\n            $this->sendRestoreFailureNotification($e->getMessage());\n        }\n    }\n\n    protected function sendRestoreSuccessNotification(): Notification\n    {\n        return Notification::make()\n            ->title(__('filament-activity-log::activities.events.restore_successful'))\n            ->success()\n            ->send();\n    }\n\n    protected function sendRestoreFailureNotification(?string $message = null): Notification\n    {\n        return Notification::make()\n            ->title(__('filament-activity-log::activities.events.restore_failed'))\n            ->body($message)\n            ->danger()\n            ->send();\n    }\n}\n"
  }
]