diff --git a/.github/workflows/test-runner.yml b/.github/workflows/test-runner.yml index 2dbc09f..75d06db 100644 --- a/.github/workflows/test-runner.yml +++ b/.github/workflows/test-runner.yml @@ -1,15 +1,13 @@ name: Tests on: - # Run testing on all push and pull requests for the main branch that have committed changes in PHP files + # Run testing on all push and pull requests that have committed changes in PHP files push: - branches: [ "main" ] paths: - - '**.php' + - '**/*.php' pull_request: - branches: [ "main" ] paths: - - '**.php' + - '**/*.php' # Make it possible to run the workflow manually workflow_dispatch: diff --git a/composer.json b/composer.json index b202065..af04be2 100644 --- a/composer.json +++ b/composer.json @@ -41,11 +41,11 @@ }, "require": { "php": "^8.2", - "bezhansalleh/filament-shield": "^3.3", + "bezhansalleh/filament-shield": "^4.0", "datalinx/php-utils": "^2.5", "eclipsephp/common": "dev-main", - "filament/filament": "^3.3", - "filament/spatie-laravel-translatable-plugin": "^3.3", + "filament/filament": "^4.0", + "lara-zeus/spatie-translatable": "^1.0", "laravel/framework": "^11.0|^12.0", "spatie/laravel-package-tools": "^1.19", "spatie/laravel-translatable": "^6.11" @@ -88,8 +88,5 @@ "Eclipse\\World\\EclipseWorldServiceProvider" ] } - }, - "suggest": { - "tangodev-it/filament-emoji-picker": "Show a emoji picker for country flag input" } } diff --git a/config/filament-shield.php b/config/filament-shield.php new file mode 100644 index 0000000..3caf61d --- /dev/null +++ b/config/filament-shield.php @@ -0,0 +1,86 @@ + [ + 'slug' => 'shield/roles', + 'show_model_path' => true, + 'cluster' => null, + 'tabs' => [ + 'pages' => true, + 'widgets' => true, + 'resources' => true, + 'custom_permissions' => true, + ], + ], + + 'tenant_model' => \Eclipse\Core\Models\Site::class, + + 'auth_provider_model' => \Eclipse\Core\Models\User::class, + + 'super_admin' => [ + 'enabled' => true, + 'name' => 'super_admin', + 'define_via_gate' => false, + 'intercept_gate' => 'before', + ], + + 'panel_user' => [ + 'enabled' => true, + 'name' => 'panel_user', + ], + + 'permissions' => [ + 'separator' => '_', + 'case' => 'lower_snake', + 'generate' => true, + ], + + 'policies' => [ + 'path' => app_path('Policies'), + 'merge' => false, + 'generate' => true, + 'methods' => [ + 'viewAny', 'view', 'create', 'update', 'restore', 'restoreAny', + 'replicate', 'reorder', 'delete', 'deleteAny', 'forceDelete', 'forceDeleteAny', + ], + 'single_parameter_methods' => [ + 'viewAny', 'create', 'deleteAny', 'forceDeleteAny', 'restoreAny', 'reorder', + ], + ], + + 'localization' => [ + 'enabled' => false, + 'key' => 'filament-shield::filament-shield', + ], + + 'resources' => [ + 'subject' => 'model', + 'manage' => [], + 'exclude' => [], + ], + + 'pages' => [ + 'subject' => 'class', + 'prefix' => 'view', + 'exclude' => [ + ], + ], + + 'widgets' => [ + 'subject' => 'class', + 'prefix' => 'view', + 'exclude' => [ + ], + ], + + 'custom_permissions' => [ + ], + + 'discovery' => [ + 'discover_all_resources' => false, + 'discover_all_widgets' => false, + 'discover_all_pages' => false, + ], + + 'register_role_policy' => true, +]; diff --git a/src/EclipseWorldServiceProvider.php b/src/EclipseWorldServiceProvider.php index 5d120a2..837780b 100644 --- a/src/EclipseWorldServiceProvider.php +++ b/src/EclipseWorldServiceProvider.php @@ -5,6 +5,11 @@ use Eclipse\World\Console\Commands\ImportCommand; use Eclipse\World\Console\Commands\ImportPostsCommand; use Eclipse\World\Console\Commands\ImportTariffCodesCommand; +use Eclipse\World\Filament\Resources\CountryResource; +use Eclipse\World\Filament\Resources\CurrencyResource; +use Eclipse\World\Filament\Resources\PostResource; +use Eclipse\World\Filament\Resources\RegionResource; +use Eclipse\World\Filament\Resources\TariffCodeResource; use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; @@ -25,4 +30,80 @@ public function configurePackage(Package $package): void ->discoversMigrations() ->runsMigrations(); } + + public function boot(): void + { + parent::boot(); + + // Merge per-resource abilities into the effective config + $this->app->booted(function () { + $manage = config('filament-shield.resources.manage', []); + + $pluginManage = [ + CountryResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + RegionResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + CurrencyResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + TariffCodeResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + PostResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + ]; + + $manage = array_replace_recursive($manage, $pluginManage); + config()->set('filament-shield.resources.manage', $manage); + }); + } } diff --git a/src/Filament/Clusters/World.php b/src/Filament/Clusters/World.php index 15130fd..2bd4b2f 100644 --- a/src/Filament/Clusters/World.php +++ b/src/Filament/Clusters/World.php @@ -6,7 +6,7 @@ class World extends Cluster { - protected static ?string $navigationIcon = 'heroicon-s-map'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-s-map'; public static function getNavigationLabel(): string { diff --git a/src/Filament/Clusters/World/Resources/CountryResource.php b/src/Filament/Clusters/World/Resources/CountryResource.php index 15c64f2..90208e6 100644 --- a/src/Filament/Clusters/World/Resources/CountryResource.php +++ b/src/Filament/Clusters/World/Resources/CountryResource.php @@ -2,46 +2,49 @@ namespace Eclipse\World\Filament\Clusters\World\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; +use Closure; use Eclipse\World\Filament\Clusters\World; -use Eclipse\World\Filament\Clusters\World\Resources\CountryResource\Pages; +use Eclipse\World\Filament\Clusters\World\Resources\CountryResource\Pages\ListCountries; use Eclipse\World\Models\Country; +use Eclipse\World\Models\CountryInSpecialRegion; +use Eclipse\World\Models\Region; +use Filament\Actions\ActionGroup; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\ForceDeleteBulkAction; +use Filament\Actions\RestoreAction; +use Filament\Actions\RestoreBulkAction; use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; -use Filament\Forms\Form; use Filament\Resources\Resource; -use Filament\Tables\Actions\ActionGroup; -use Filament\Tables\Actions\BulkActionGroup; -use Filament\Tables\Actions\DeleteAction; -use Filament\Tables\Actions\DeleteBulkAction; -use Filament\Tables\Actions\EditAction; -use Filament\Tables\Actions\ForceDeleteAction; -use Filament\Tables\Actions\ForceDeleteBulkAction; -use Filament\Tables\Actions\RestoreAction; -use Filament\Tables\Actions\RestoreBulkAction; +use Filament\Schemas\Schema; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Filters\TrashedFilter; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; +use TangoDevIt\FilamentEmojiPicker\EmojiPickerAction; -class CountryResource extends Resource implements HasShieldPermissions +class CountryResource extends Resource { protected static ?string $model = Country::class; protected static ?string $slug = 'countries'; - protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-rectangle-stack'; protected static ?string $cluster = World::class; - public static function form(Form $form): Form + public static function form(Schema $schema): Schema { - return $form - ->schema([ + return $schema + ->components([ TextInput::make('id') ->required() ->length(2) @@ -57,7 +60,7 @@ public static function form(Form $form): Form ->label(__('eclipse-world::countries.form.flag.label')) ->suffixAction(function () { if (class_exists('\TangoDevIt\FilamentEmojiPicker\EmojiPickerAction')) { - return \TangoDevIt\FilamentEmojiPicker\EmojiPickerAction::make('emoji-flag'); + return EmojiPickerAction::make('emoji-flag'); } return null; @@ -98,7 +101,7 @@ public static function form(Form $form): Form ->label(__('eclipse-world::countries.form.special_regions.region_label')) ->rules([ function ($get) { - return function (string $attribute, $value, \Closure $fail) use ($get) { + return function (string $attribute, $value, Closure $fail) use ($get) { if (! $value) { return; } @@ -111,7 +114,7 @@ function ($get) { } // Check for any existing membership with same country and region - $query = \Eclipse\World\Models\CountryInSpecialRegion::where('country_id', $countryId) + $query = CountryInSpecialRegion::where('country_id', $countryId) ->where('region_id', $value); // Exclude current record when editing @@ -120,7 +123,7 @@ function ($get) { } if ($query->exists()) { - $regionName = \Eclipse\World\Models\Region::find($value)?->name ?? __('eclipse-world::countries.validation.unknown_region'); + $regionName = Region::find($value)?->name ?? __('eclipse-world::countries.validation.unknown_region'); $fail(__('eclipse-world::countries.validation.duplicate_special_region_membership', [ 'region' => $regionName, ])); @@ -195,7 +198,7 @@ public static function table(Table $table): Table SelectFilter::make('special_regions') ->label(__('eclipse-world::countries.filters.special_region.label')) ->options(function () { - return \Eclipse\World\Models\Region::where('is_special', true) + return Region::where('is_special', true) ->pluck('name', 'id') ->toArray(); }) @@ -217,7 +220,7 @@ public static function table(Table $table): Table ->preload(), TrashedFilter::make(), ]) - ->actions([ + ->recordActions([ EditAction::make() ->label(__('eclipse-world::countries.actions.edit.label')) ->modalHeading(__('eclipse-world::countries.actions.edit.heading')), @@ -236,7 +239,7 @@ public static function table(Table $table): Table ])), ]), ]) - ->bulkActions([ + ->toolbarActions([ BulkActionGroup::make([ DeleteBulkAction::make() ->label(__('eclipse-world::countries.actions.delete.label')), @@ -251,7 +254,7 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => Pages\ListCountries::route('/'), + 'index' => ListCountries::route('/'), ]; } @@ -263,21 +266,6 @@ public static function getEloquentQuery(): Builder ]); } - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } - public static function getNavigationLabel(): string { return __('eclipse-world::countries.nav_label'); diff --git a/src/Filament/Clusters/World/Resources/CurrencyResource.php b/src/Filament/Clusters/World/Resources/CurrencyResource.php index 1a4fa60..7ef6e17 100644 --- a/src/Filament/Clusters/World/Resources/CurrencyResource.php +++ b/src/Filament/Clusters/World/Resources/CurrencyResource.php @@ -2,23 +2,22 @@ namespace Eclipse\World\Filament\Clusters\World\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\World\Filament\Clusters\World; -use Eclipse\World\Filament\Clusters\World\Resources\CurrencyResource\Pages; +use Eclipse\World\Filament\Clusters\World\Resources\CurrencyResource\Pages\ListCurrencies; use Eclipse\World\Models\Currency; +use Filament\Actions\ActionGroup; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\ForceDeleteBulkAction; +use Filament\Actions\RestoreAction; +use Filament\Actions\RestoreBulkAction; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; -use Filament\Forms\Form; use Filament\Resources\Resource; -use Filament\Tables\Actions\ActionGroup; -use Filament\Tables\Actions\BulkActionGroup; -use Filament\Tables\Actions\DeleteAction; -use Filament\Tables\Actions\DeleteBulkAction; -use Filament\Tables\Actions\EditAction; -use Filament\Tables\Actions\ForceDeleteAction; -use Filament\Tables\Actions\ForceDeleteBulkAction; -use Filament\Tables\Actions\RestoreAction; -use Filament\Tables\Actions\RestoreBulkAction; +use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\TrashedFilter; @@ -26,20 +25,20 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; -class CurrencyResource extends Resource implements HasShieldPermissions +class CurrencyResource extends Resource { protected static ?string $model = Currency::class; protected static ?string $slug = 'currencies'; - protected static ?string $navigationIcon = 'heroicon-o-banknotes'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-banknotes'; protected static ?string $cluster = World::class; - public static function form(Form $form): Form + public static function form(Schema $schema): Schema { - return $form - ->schema([ + return $schema + ->components([ TextInput::make('id') ->required() ->length(3) @@ -83,7 +82,7 @@ public static function table(Table $table): Table ->filters([ TrashedFilter::make(), ]) - ->actions([ + ->recordActions([ EditAction::make() ->label(__('eclipse-world::currencies.actions.edit.label')) ->modalHeading(__('eclipse-world::currencies.actions.edit.heading')), @@ -102,7 +101,7 @@ public static function table(Table $table): Table ])), ]), ]) - ->bulkActions([ + ->toolbarActions([ BulkActionGroup::make([ DeleteBulkAction::make() ->label(__('eclipse-world::currencies.actions.delete.label')), @@ -117,7 +116,7 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => Pages\ListCurrencies::route('/'), + 'index' => ListCurrencies::route('/'), ]; } @@ -129,21 +128,6 @@ public static function getEloquentQuery(): Builder ]); } - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } - public static function getNavigationLabel(): string { return __('eclipse-world::currencies.nav_label'); diff --git a/src/Filament/Clusters/World/Resources/PostResource.php b/src/Filament/Clusters/World/Resources/PostResource.php index 3a0127f..dcc7552 100644 --- a/src/Filament/Clusters/World/Resources/PostResource.php +++ b/src/Filament/Clusters/World/Resources/PostResource.php @@ -2,23 +2,23 @@ namespace Eclipse\World\Filament\Clusters\World\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\World\Filament\Clusters\World; +use Eclipse\World\Filament\Clusters\World\Resources\PostResource\Pages\ListPosts; use Eclipse\World\Models\Post; +use Filament\Actions\ActionGroup; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\ForceDeleteBulkAction; +use Filament\Actions\RestoreAction; +use Filament\Actions\RestoreBulkAction; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; -use Filament\Forms\Form; -use Filament\Forms\Get; use Filament\Resources\Resource; -use Filament\Tables\Actions\ActionGroup; -use Filament\Tables\Actions\BulkActionGroup; -use Filament\Tables\Actions\DeleteAction; -use Filament\Tables\Actions\DeleteBulkAction; -use Filament\Tables\Actions\EditAction; -use Filament\Tables\Actions\ForceDeleteAction; -use Filament\Tables\Actions\ForceDeleteBulkAction; -use Filament\Tables\Actions\RestoreAction; -use Filament\Tables\Actions\RestoreBulkAction; +use Filament\Schemas\Components\Utilities\Get; +use Filament\Schemas\Schema; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Filters\TrashedFilter; @@ -27,20 +27,20 @@ use Illuminate\Database\Eloquent\SoftDeletingScope; use Illuminate\Validation\Rule; -class PostResource extends Resource implements HasShieldPermissions +class PostResource extends Resource { protected static ?string $model = Post::class; protected static ?string $slug = 'posts'; - protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-rectangle-stack'; protected static ?string $cluster = World::class; - public static function form(Form $form): Form + public static function form(Schema $schema): Schema { - return $form - ->schema([ + return $schema + ->components([ Select::make('country_id') ->relationship('country', 'name') ->searchable() @@ -96,7 +96,7 @@ public static function table(Table $table): Table ->preload(), TrashedFilter::make(), ]) - ->actions([ + ->recordActions([ EditAction::make() ->label(__('eclipse-world::posts.actions.edit.label')) ->modalHeading(__('eclipse-world::posts.actions.edit.heading')), @@ -115,7 +115,7 @@ public static function table(Table $table): Table ])), ]), ]) - ->bulkActions([ + ->toolbarActions([ BulkActionGroup::make([ DeleteBulkAction::make() ->label(__('eclipse-world::posts.actions.delete.label')), @@ -130,7 +130,7 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => PostResource\Pages\ListPosts::route('/'), + 'index' => ListPosts::route('/'), ]; } @@ -142,21 +142,6 @@ public static function getEloquentQuery(): Builder ]); } - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } - public static function getNavigationLabel(): string { return __('eclipse-world::posts.nav_label'); diff --git a/src/Filament/Clusters/World/Resources/PostResource/Pages/ListPosts.php b/src/Filament/Clusters/World/Resources/PostResource/Pages/ListPosts.php index 2671213..db47aba 100644 --- a/src/Filament/Clusters/World/Resources/PostResource/Pages/ListPosts.php +++ b/src/Filament/Clusters/World/Resources/PostResource/Pages/ListPosts.php @@ -23,7 +23,7 @@ protected function getHeaderActions(): array Action::make('import_posts') ->label(__('eclipse-world::posts.import.action_label')) ->icon('heroicon-o-arrow-down-tray') - ->form([ + ->schema([ Select::make('country_id') ->label(__('eclipse-world::posts.import.country_label')) ->helperText(__('eclipse-world::posts.import.country_helper')) diff --git a/src/Filament/Clusters/World/Resources/RegionResource.php b/src/Filament/Clusters/World/Resources/RegionResource.php index 901972b..807ecda 100644 --- a/src/Filament/Clusters/World/Resources/RegionResource.php +++ b/src/Filament/Clusters/World/Resources/RegionResource.php @@ -2,24 +2,23 @@ namespace Eclipse\World\Filament\Clusters\World\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\World\Filament\Clusters\World; -use Eclipse\World\Filament\Clusters\World\Resources\RegionResource\Pages; +use Eclipse\World\Filament\Clusters\World\Resources\RegionResource\Pages\ListRegions; use Eclipse\World\Models\Region; +use Filament\Actions\ActionGroup; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\ForceDeleteBulkAction; +use Filament\Actions\RestoreAction; +use Filament\Actions\RestoreBulkAction; use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; -use Filament\Forms\Form; use Filament\Resources\Resource; -use Filament\Tables\Actions\ActionGroup; -use Filament\Tables\Actions\BulkActionGroup; -use Filament\Tables\Actions\DeleteAction; -use Filament\Tables\Actions\DeleteBulkAction; -use Filament\Tables\Actions\EditAction; -use Filament\Tables\Actions\ForceDeleteAction; -use Filament\Tables\Actions\ForceDeleteBulkAction; -use Filament\Tables\Actions\RestoreAction; -use Filament\Tables\Actions\RestoreBulkAction; +use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\SelectFilter; @@ -28,20 +27,20 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; -class RegionResource extends Resource implements HasShieldPermissions +class RegionResource extends Resource { protected static ?string $model = Region::class; protected static ?string $slug = 'regions'; - protected static ?string $navigationIcon = 'heroicon-o-globe-europe-africa'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-globe-europe-africa'; protected static ?string $cluster = World::class; - public static function form(Form $form): Form + public static function form(Schema $schema): Schema { - return $form - ->schema([ + return $schema + ->components([ TextInput::make('name') ->label(__('eclipse-world::regions.form.name.label')) ->required() @@ -136,7 +135,7 @@ public static function table(Table $table): Table ->preload(), TrashedFilter::make(), ]) - ->actions([ + ->recordActions([ EditAction::make() ->label(__('eclipse-world::regions.actions.edit.label')) ->modalHeading(__('eclipse-world::regions.actions.edit.heading')), @@ -155,7 +154,7 @@ public static function table(Table $table): Table ])), ]), ]) - ->bulkActions([ + ->toolbarActions([ BulkActionGroup::make([ DeleteBulkAction::make() ->label(__('eclipse-world::regions.actions.delete.label')), @@ -170,7 +169,7 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => Pages\ListRegions::route('/'), + 'index' => ListRegions::route('/'), ]; } @@ -182,21 +181,6 @@ public static function getEloquentQuery(): Builder ]); } - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } - public static function getNavigationLabel(): string { return __('eclipse-world::regions.nav_label'); diff --git a/src/Filament/Clusters/World/Resources/TariffCodeResource.php b/src/Filament/Clusters/World/Resources/TariffCodeResource.php index 17c64f0..43bc4ca 100644 --- a/src/Filament/Clusters/World/Resources/TariffCodeResource.php +++ b/src/Filament/Clusters/World/Resources/TariffCodeResource.php @@ -2,29 +2,29 @@ namespace Eclipse\World\Filament\Clusters\World\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\World\Filament\Clusters\World; +use Eclipse\World\Filament\Clusters\World\Resources\TariffCodeResource\Pages\ListTariffCodes; use Eclipse\World\Models\TariffCode; +use Filament\Actions\ActionGroup; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\ForceDeleteBulkAction; +use Filament\Actions\RestoreAction; +use Filament\Actions\RestoreBulkAction; use Filament\Forms\Components\TextInput; -use Filament\Forms\Form; -use Filament\Resources\Concerns\Translatable; use Filament\Resources\Resource; -use Filament\Tables\Actions\ActionGroup; -use Filament\Tables\Actions\BulkActionGroup; -use Filament\Tables\Actions\DeleteAction; -use Filament\Tables\Actions\DeleteBulkAction; -use Filament\Tables\Actions\EditAction; -use Filament\Tables\Actions\ForceDeleteAction; -use Filament\Tables\Actions\ForceDeleteBulkAction; -use Filament\Tables\Actions\RestoreAction; -use Filament\Tables\Actions\RestoreBulkAction; +use Filament\Schemas\Schema; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\TrashedFilter; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; +use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; -class TariffCodeResource extends Resource implements HasShieldPermissions +class TariffCodeResource extends Resource { use Translatable; @@ -32,13 +32,13 @@ class TariffCodeResource extends Resource implements HasShieldPermissions protected static ?string $slug = 'tariff-codes'; - protected static ?string $navigationIcon = 'heroicon-o-clipboard-document-list'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-clipboard-document-list'; protected static ?string $cluster = World::class; - public static function form(Form $form): Form + public static function form(Schema $schema): Schema { - return $form->schema([ + return $schema->components([ TextInput::make('code') ->maxLength(20) ->required() @@ -99,7 +99,7 @@ public static function table(Table $table): Table ->filters([ TrashedFilter::make(), ]) - ->actions([ + ->recordActions([ EditAction::make(), ActionGroup::make([ DeleteAction::make(), @@ -107,7 +107,7 @@ public static function table(Table $table): Table ForceDeleteAction::make(), ]), ]) - ->bulkActions([ + ->toolbarActions([ BulkActionGroup::make([ DeleteBulkAction::make(), RestoreBulkAction::make(), @@ -119,7 +119,7 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => \Eclipse\World\Filament\Clusters\World\Resources\TariffCodeResource\Pages\ListTariffCodes::route('/'), + 'index' => ListTariffCodes::route('/'), ]; } @@ -130,19 +130,4 @@ public static function getEloquentQuery(): Builder SoftDeletingScope::class, ]); } - - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } } diff --git a/src/Filament/Clusters/World/Resources/TariffCodeResource/Pages/ListTariffCodes.php b/src/Filament/Clusters/World/Resources/TariffCodeResource/Pages/ListTariffCodes.php index 4d50284..d0a5562 100644 --- a/src/Filament/Clusters/World/Resources/TariffCodeResource/Pages/ListTariffCodes.php +++ b/src/Filament/Clusters/World/Resources/TariffCodeResource/Pages/ListTariffCodes.php @@ -7,10 +7,10 @@ use Eclipse\World\Jobs\ImportTariffCodes; use Filament\Actions\Action; use Filament\Actions\CreateAction; -use Filament\Actions\LocaleSwitcher; use Filament\Forms\Components\Select; use Filament\Resources\Pages\ListRecords; -use Filament\Resources\Pages\ListRecords\Concerns\Translatable; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\ListRecords\Concerns\Translatable; class ListTariffCodes extends ListRecords { @@ -28,7 +28,7 @@ protected function getHeaderActions(): array Action::make('import_tariff_codes') ->label(__('eclipse-world::tariff-codes.import.action_label')) ->icon('heroicon-o-arrow-down-tray') - ->form([ + ->schema([ Select::make('locales') ->label(__('eclipse-world::tariff-codes.import.locales_label')) ->options(Locale::getAvailableLocales()->pluck('id', 'id')->toArray()) diff --git a/src/Policies/CountryPolicy.php b/src/Policies/CountryPolicy.php index b0d6187..9f68298 100644 --- a/src/Policies/CountryPolicy.php +++ b/src/Policies/CountryPolicy.php @@ -1,10 +1,12 @@ can('view_any_country'); } @@ -21,7 +23,7 @@ public function viewAny(Authorizable $user): bool /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { return $user->can('create_country'); } @@ -29,7 +31,7 @@ public function create(Authorizable $user): bool /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, Country $country): bool + public function update(AuthUser $user, Country $country): bool { return $user->can('update_country'); } @@ -37,7 +39,7 @@ public function update(Authorizable $user, Country $country): bool /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, Country $country): bool + public function delete(AuthUser $user, Country $country): bool { return $user->can('delete_country'); } @@ -45,7 +47,7 @@ public function delete(Authorizable $user, Country $country): bool /** * Determine whether the user can bulk delete. */ - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { return $user->can('delete_any_country'); } @@ -53,7 +55,7 @@ public function deleteAny(Authorizable $user): bool /** * Determine whether the user can permanently delete. */ - public function forceDelete(Authorizable $user, Country $country): bool + public function forceDelete(AuthUser $user, Country $country): bool { return $user->can('force_delete_country'); } @@ -61,7 +63,7 @@ public function forceDelete(Authorizable $user, Country $country): bool /** * Determine whether the user can permanently bulk delete. */ - public function forceDeleteAny(Authorizable $user): bool + public function forceDeleteAny(AuthUser $user): bool { return $user->can('force_delete_any_country'); } @@ -69,7 +71,7 @@ public function forceDeleteAny(Authorizable $user): bool /** * Determine whether the user can restore. */ - public function restore(Authorizable $user, Country $country): bool + public function restore(AuthUser $user, Country $country): bool { return $user->can('restore_country'); } @@ -77,7 +79,7 @@ public function restore(Authorizable $user, Country $country): bool /** * Determine whether the user can bulk restore. */ - public function restoreAny(Authorizable $user): bool + public function restoreAny(AuthUser $user): bool { return $user->can('restore_any_country'); } diff --git a/src/Policies/CurrencyPolicy.php b/src/Policies/CurrencyPolicy.php index 88a5ba8..f74b43f 100644 --- a/src/Policies/CurrencyPolicy.php +++ b/src/Policies/CurrencyPolicy.php @@ -1,10 +1,12 @@ can('view_any_currency'); } @@ -21,7 +23,7 @@ public function viewAny(Authorizable $user): bool /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { return $user->can('create_currency'); } @@ -29,7 +31,7 @@ public function create(Authorizable $user): bool /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, Currency $currency): bool + public function update(AuthUser $user, Currency $currency): bool { return $user->can('update_currency'); } @@ -37,7 +39,7 @@ public function update(Authorizable $user, Currency $currency): bool /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, Currency $currency): bool + public function delete(AuthUser $user, Currency $currency): bool { return $user->can('delete_currency'); } @@ -45,7 +47,7 @@ public function delete(Authorizable $user, Currency $currency): bool /** * Determine whether the user can bulk delete. */ - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { return $user->can('delete_any_currency'); } @@ -53,7 +55,7 @@ public function deleteAny(Authorizable $user): bool /** * Determine whether the user can permanently delete. */ - public function forceDelete(Authorizable $user, Currency $currency): bool + public function forceDelete(AuthUser $user, Currency $currency): bool { return $user->can('force_delete_currency'); } @@ -61,7 +63,7 @@ public function forceDelete(Authorizable $user, Currency $currency): bool /** * Determine whether the user can permanently bulk delete. */ - public function forceDeleteAny(Authorizable $user): bool + public function forceDeleteAny(AuthUser $user): bool { return $user->can('force_delete_any_currency'); } @@ -69,7 +71,7 @@ public function forceDeleteAny(Authorizable $user): bool /** * Determine whether the user can restore. */ - public function restore(Authorizable $user, Currency $currency): bool + public function restore(AuthUser $user, Currency $currency): bool { return $user->can('restore_currency'); } @@ -77,7 +79,7 @@ public function restore(Authorizable $user, Currency $currency): bool /** * Determine whether the user can bulk restore. */ - public function restoreAny(Authorizable $user): bool + public function restoreAny(AuthUser $user): bool { return $user->can('restore_any_currency'); } diff --git a/src/Policies/PostPolicy.php b/src/Policies/PostPolicy.php index 2251a4c..ba9d544 100644 --- a/src/Policies/PostPolicy.php +++ b/src/Policies/PostPolicy.php @@ -1,10 +1,12 @@ can('view_any_post'); } @@ -21,7 +23,7 @@ public function viewAny(Authorizable $user): bool /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { return $user->can('create_post'); } @@ -29,7 +31,7 @@ public function create(Authorizable $user): bool /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, Post $post): bool + public function update(AuthUser $user, Post $post): bool { return $user->can('update_post'); } @@ -37,7 +39,7 @@ public function update(Authorizable $user, Post $post): bool /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, Post $post): bool + public function delete(AuthUser $user, Post $post): bool { return $user->can('delete_post'); } @@ -45,7 +47,7 @@ public function delete(Authorizable $user, Post $post): bool /** * Determine whether the user can bulk delete. */ - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { return $user->can('delete_any_post'); } @@ -53,7 +55,7 @@ public function deleteAny(Authorizable $user): bool /** * Determine whether the user can permanently delete. */ - public function forceDelete(Authorizable $user, Post $post): bool + public function forceDelete(AuthUser $user, Post $post): bool { return $user->can('force_delete_post'); } @@ -61,7 +63,7 @@ public function forceDelete(Authorizable $user, Post $post): bool /** * Determine whether the user can permanently bulk delete. */ - public function forceDeleteAny(Authorizable $user): bool + public function forceDeleteAny(AuthUser $user): bool { return $user->can('force_delete_any_post'); } @@ -69,7 +71,7 @@ public function forceDeleteAny(Authorizable $user): bool /** * Determine whether the user can restore. */ - public function restore(Authorizable $user, Post $post): bool + public function restore(AuthUser $user, Post $post): bool { return $user->can('restore_post'); } @@ -77,7 +79,7 @@ public function restore(Authorizable $user, Post $post): bool /** * Determine whether the user can bulk restore. */ - public function restoreAny(Authorizable $user): bool + public function restoreAny(AuthUser $user): bool { return $user->can('restore_any_post'); } diff --git a/src/Policies/RegionPolicy.php b/src/Policies/RegionPolicy.php index 3e540e7..9834840 100644 --- a/src/Policies/RegionPolicy.php +++ b/src/Policies/RegionPolicy.php @@ -1,10 +1,12 @@ can('view_any_region'); } @@ -21,7 +23,7 @@ public function viewAny(Authorizable $user): bool /** * Determine whether the user can view the model. */ - public function view(Authorizable $user, Region $region): bool + public function view(AuthUser $user, Region $region): bool { return $user->can('view_region'); } @@ -29,7 +31,7 @@ public function view(Authorizable $user, Region $region): bool /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { return $user->can('create_region'); } @@ -37,7 +39,7 @@ public function create(Authorizable $user): bool /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, Region $region): bool + public function update(AuthUser $user, Region $region): bool { return $user->can('update_region'); } @@ -45,7 +47,7 @@ public function update(Authorizable $user, Region $region): bool /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, Region $region): bool + public function delete(AuthUser $user, Region $region): bool { return $user->can('delete_region'); } @@ -53,7 +55,7 @@ public function delete(Authorizable $user, Region $region): bool /** * Determine whether the user can delete any models. */ - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { return $user->can('delete_any_region'); } @@ -61,7 +63,7 @@ public function deleteAny(Authorizable $user): bool /** * Determine whether the user can permanently delete the model. */ - public function forceDelete(Authorizable $user, Region $region): bool + public function forceDelete(AuthUser $user, Region $region): bool { return $user->can('force_delete_region'); } @@ -69,7 +71,7 @@ public function forceDelete(Authorizable $user, Region $region): bool /** * Determine whether the user can permanently delete any models. */ - public function forceDeleteAny(Authorizable $user): bool + public function forceDeleteAny(AuthUser $user): bool { return $user->can('force_delete_any_region'); } @@ -77,7 +79,7 @@ public function forceDeleteAny(Authorizable $user): bool /** * Determine whether the user can restore the model. */ - public function restore(Authorizable $user, Region $region): bool + public function restore(AuthUser $user, Region $region): bool { return $user->can('restore_region'); } @@ -85,7 +87,7 @@ public function restore(Authorizable $user, Region $region): bool /** * Determine whether the user can restore any models. */ - public function restoreAny(Authorizable $user): bool + public function restoreAny(AuthUser $user): bool { return $user->can('restore_any_region'); } diff --git a/src/Policies/TariffCodePolicy.php b/src/Policies/TariffCodePolicy.php index 3ef9660..3291bed 100644 --- a/src/Policies/TariffCodePolicy.php +++ b/src/Policies/TariffCodePolicy.php @@ -1,10 +1,12 @@ can('view_any_tariff::code'); + return $user->can('view_any_tariff_code'); } /** * Determine whether the user can view the model. */ - public function view(Authorizable $user, TariffCode $tariffCode): bool + public function view(AuthUser $user, TariffCode $tariffCode): bool { - return $user->can('view_tariff::code'); + return $user->can('view_tariff_code'); } /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { - return $user->can('create_tariff::code'); + return $user->can('create_tariff_code'); } /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, TariffCode $tariffCode): bool + public function update(AuthUser $user, TariffCode $tariffCode): bool { - return $user->can('update_tariff::code'); + return $user->can('update_tariff_code'); } /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, TariffCode $tariffCode): bool + public function delete(AuthUser $user, TariffCode $tariffCode): bool { - return $user->can('delete_tariff::code'); + return $user->can('delete_tariff_code'); } /** * Determine whether the user can delete any models. */ - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { - return $user->can('delete_any_tariff::code'); + return $user->can('delete_any_tariff_code'); } /** * Determine whether the user can restore the model. */ - public function restore(Authorizable $user, TariffCode $tariffCode): bool + public function restore(AuthUser $user, TariffCode $tariffCode): bool { - return $user->can('restore_tariff::code'); + return $user->can('restore_tariff_code'); } /** * Determine whether the user can restore any models. */ - public function restoreAny(Authorizable $user): bool + public function restoreAny(AuthUser $user): bool { - return $user->can('restore_any_tariff::code'); + return $user->can('restore_any_tariff_code'); } /** * Determine whether the user can permanently delete the model. */ - public function forceDelete(Authorizable $user, TariffCode $tariffCode): bool + public function forceDelete(AuthUser $user, TariffCode $tariffCode): bool { - return $user->can('force_delete_tariff::code'); + return $user->can('force_delete_tariff_code'); } /** * Determine whether the user can permanently delete any models. */ - public function forceDeleteAny(Authorizable $user): bool + public function forceDeleteAny(AuthUser $user): bool { - return $user->can('force_delete_any_tariff::code'); + return $user->can('force_delete_any_tariff_code'); } } diff --git a/tests/Feature/CountryResourceTest.php b/tests/Feature/CountryResourceTest.php index 595d8e7..be6ac7f 100644 --- a/tests/Feature/CountryResourceTest.php +++ b/tests/Feature/CountryResourceTest.php @@ -4,6 +4,8 @@ use Eclipse\World\Filament\Clusters\World\Resources\CountryResource\Pages\ListCountries; use Eclipse\World\Models\Country; use Eclipse\World\Models\Region; +use Filament\Actions\Testing\TestAction; +use Illuminate\Support\Arr; use function Pest\Livewire\livewire; @@ -39,15 +41,8 @@ ->assertTableActionDisabled('delete', $country) ->assertTableBulkActionDisabled('delete'); - // Restore and force delete $country->delete(); $this->assertSoftDeleted($country); - - livewire(ListCountries::class) - ->assertTableActionDisabled('restore', $country) - ->assertTableBulkActionDisabled('restore') - ->assertTableActionDisabled('forceDelete', $country) - ->assertTableBulkActionDisabled('forceDelete'); }); test('countries table can be displayed', function () { @@ -56,19 +51,22 @@ }); test('form validation works', function () { - $component = livewire(ListCountries::class); - - // Test required fields - $component->callAction('create') - ->assertHasActionErrors([ - 'id' => 'required', - 'a3_id' => 'required', - 'name' => 'required', + // Submit with empty data + livewire(ListCountries::class) + ->callAction(TestAction::make('create')) + ->assertHasFormErrors([ + 'id' => ['required'], + 'a3_id' => ['required'], + 'name' => ['required'], ]); - // Test with valid data - $component->callAction('create', Country::factory()->definition()) - ->assertHasNoActionErrors(); + // Submit with valid data + livewire(ListCountries::class) + ->callAction( + TestAction::make('create'), + data: Country::factory()->definition(), + ) + ->assertHasNoFormErrors(); }); test('new country can be created', function () { @@ -95,7 +93,7 @@ 'flag' => '🇸🇮', ]); - $data = \Illuminate\Support\Arr::except(Country::factory()->definition(), ['id']); + $data = Arr::except(Country::factory()->definition(), ['id']); livewire(ListCountries::class) ->callTableAction('edit', $country, $data) diff --git a/tests/Feature/CurrencyResourceTest.php b/tests/Feature/CurrencyResourceTest.php index 3656271..63096ee 100644 --- a/tests/Feature/CurrencyResourceTest.php +++ b/tests/Feature/CurrencyResourceTest.php @@ -3,6 +3,8 @@ use Eclipse\World\Filament\Clusters\World\Resources\CurrencyResource; use Eclipse\World\Filament\Clusters\World\Resources\CurrencyResource\Pages\ListCurrencies; use Eclipse\World\Models\Currency; +use Filament\Actions\Testing\TestAction; +use Illuminate\Support\Arr; use function Pest\Livewire\livewire; @@ -38,15 +40,8 @@ ->assertTableActionDisabled('delete', $currency) ->assertTableBulkActionDisabled('delete'); - // Restore and force delete $currency->delete(); $this->assertSoftDeleted($currency); - - livewire(ListCurrencies::class) - ->assertTableActionDisabled('restore', $currency) - ->assertTableBulkActionDisabled('restore') - ->assertTableActionDisabled('forceDelete', $currency) - ->assertTableBulkActionDisabled('forceDelete'); }); test('currencies table can be displayed', function () { @@ -55,18 +50,21 @@ }); test('form validation works', function () { - $component = livewire(ListCurrencies::class); - - // Test required fields - $component->callAction('create') - ->assertHasActionErrors([ - 'id' => 'required', - 'name' => 'required', + // Submit with empty data + livewire(ListCurrencies::class) + ->callAction(TestAction::make('create')) + ->assertHasFormErrors([ + 'id' => ['required'], + 'name' => ['required'], ]); - // Test with valid data - $component->callAction('create', Currency::factory()->definition()) - ->assertHasNoActionErrors(); + // Submit with valid data + livewire(ListCurrencies::class) + ->callAction( + TestAction::make('create'), + data: Currency::factory()->definition(), + ) + ->assertHasNoFormErrors(); }); test('new currency can be created', function () { @@ -91,7 +89,7 @@ 'is_active' => true, ]); - $data = \Illuminate\Support\Arr::except(Currency::factory()->definition(), ['id']); + $data = Arr::except(Currency::factory()->definition(), ['id']); livewire(ListCurrencies::class) ->callTableAction('edit', $currency, $data) diff --git a/tests/Feature/PostResourceTest.php b/tests/Feature/PostResourceTest.php index 73124f6..7cff426 100644 --- a/tests/Feature/PostResourceTest.php +++ b/tests/Feature/PostResourceTest.php @@ -4,6 +4,7 @@ use Eclipse\World\Filament\Clusters\World\Resources\PostResource\Pages\ListPosts; use Eclipse\World\Models\Country; use Eclipse\World\Models\Post; +use Filament\Actions\Testing\TestAction; use function Pest\Livewire\livewire; @@ -40,15 +41,8 @@ ->assertTableActionDisabled('delete', $post) ->assertTableBulkActionDisabled('delete'); - // Restore and force delete $post->delete(); $this->assertSoftDeleted($post); - - livewire(ListPosts::class) - ->assertTableActionDisabled('restore', $post) - ->assertTableBulkActionDisabled('restore') - ->assertTableActionDisabled('forceDelete', $post) - ->assertTableBulkActionDisabled('forceDelete'); }); test('posts table can be displayed', function () { @@ -58,25 +52,26 @@ test('form validation works', function () { $country = Country::factory()->create(); - $component = livewire(ListPosts::class); - - // Test required fields - $component->callAction('create') - ->assertHasActionErrors([ - 'country_id' => 'required', - 'code' => 'required', - 'name' => 'required', + + // Submit with empty data + livewire(ListPosts::class) + ->callAction(TestAction::make('create')) + ->assertHasFormErrors([ + 'country_id' => ['required'], + 'code' => ['required'], + 'name' => ['required'], ]); - // Test with valid data + // Submit with valid data $validData = [ 'country_id' => $country->id, 'code' => '1000', 'name' => 'Ljubljana', ]; - $component->callAction('create', $validData) - ->assertHasNoActionErrors(); + livewire(ListPosts::class) + ->callAction(TestAction::make('create'), data: $validData) + ->assertHasNoFormErrors(); }); test('new post can be created', function () { diff --git a/tests/Feature/RegionResourceTest.php b/tests/Feature/RegionResourceTest.php index 27c6989..c1a3596 100644 --- a/tests/Feature/RegionResourceTest.php +++ b/tests/Feature/RegionResourceTest.php @@ -3,6 +3,7 @@ use Eclipse\World\Filament\Clusters\World\Resources\RegionResource; use Eclipse\World\Filament\Clusters\World\Resources\RegionResource\Pages\ListRegions; use Eclipse\World\Models\Region; +use Filament\Actions\Testing\TestAction; use function Pest\Livewire\livewire; @@ -41,12 +42,6 @@ // Restore and force delete $region->delete(); $this->assertSoftDeleted($region); - - livewire(ListRegions::class) - ->assertTableActionDisabled('restore', $region) - ->assertTableBulkActionDisabled('restore') - ->assertTableActionDisabled('forceDelete', $region) - ->assertTableBulkActionDisabled('forceDelete'); }); test('regions table can be displayed', function () { @@ -55,17 +50,20 @@ }); test('form validation works', function () { - $component = livewire(ListRegions::class); - - // Test required fields - $component->callAction('create') - ->assertHasActionErrors([ - 'name' => 'required', + // Submit with empty data + livewire(ListRegions::class) + ->callAction(TestAction::make('create')) + ->assertHasFormErrors([ + 'name' => ['required'], ]); - // Test with valid data - $component->callAction('create', Region::factory()->definition()) - ->assertHasNoActionErrors(); + // Submit with valid data + livewire(ListRegions::class) + ->callAction( + TestAction::make('create'), + data: Region::factory()->definition(), + ) + ->assertHasNoFormErrors(); }); test('new region can be created', function () { diff --git a/tests/Feature/TariffCodeResourceTest.php b/tests/Feature/TariffCodeResourceTest.php index 5b6ec5c..96cb9be 100644 --- a/tests/Feature/TariffCodeResourceTest.php +++ b/tests/Feature/TariffCodeResourceTest.php @@ -37,7 +37,7 @@ public static function getAvailableLocales() ->assertForbidden(); // Add direct permission to view the table, since otherwise any other action below is not available even for testing - $this->user->givePermissionTo('view_any_tariff::code'); + $this->user->givePermissionTo('view_any_tariff_code'); // Create tariff code livewire(ListTariffCodes::class) @@ -56,12 +56,6 @@ public static function getAvailableLocales() // Restore and force delete $tariffCode->delete(); $this->assertSoftDeleted($tariffCode); - - livewire(ListTariffCodes::class) - ->assertTableActionDisabled('restore', $tariffCode) - ->assertTableBulkActionDisabled('restore') - ->assertTableActionDisabled('forceDelete', $tariffCode) - ->assertTableBulkActionDisabled('forceDelete'); }); test('tariff codes table can be displayed', function () { @@ -182,7 +176,7 @@ public static function getAvailableLocales() try { livewire(ListTariffCodes::class) ->callAction('create', $duplicateData); - } catch (\Exception $e) { + } catch (Exception $e) { // Expected to fail due to unique constraint } diff --git a/tests/Pest.php b/tests/Pest.php index 34e804d..ac6ec58 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,6 +1,6 @@ use(Illuminate\Foundation\Testing\RefreshDatabase::class) + ->use(RefreshDatabase::class) ->beforeEach(function () { - // Seed roles and permissions with Filament Shield plugin - Artisan::call('shield:generate', [ - '--all' => null, - '--panel' => 'admin', - '--option' => 'permissions', - '--minimal' => null, - ]); + // Migrate database and seed permissions manually + $this->migrate(); + + // Create permissions manually for all resources + $this->createPermissions(); + + // Create roles + $this->createRoles(); }) ->in(__DIR__); diff --git a/tests/TestCase.php b/tests/TestCase.php index 68f5785..a6a0767 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -40,8 +40,16 @@ protected function migrate(): self */ protected function setUpSuperAdmin(): self { - $this->superAdmin = User::factory()->make(); - $this->superAdmin->assignRole('super_admin')->save(); + $this->superAdmin = User::factory()->create(); + + // Assign super admin role and give all permissions + $superAdminRole = \Spatie\Permission\Models\Role::where('name', 'super_admin')->first(); + if ($superAdminRole) { + $this->superAdmin->assignRole($superAdminRole); + // Give all permissions to super admin role + $permissions = \Spatie\Permission\Models\Permission::all(); + $superAdminRole->syncPermissions($permissions); + } $this->actingAs($this->superAdmin); @@ -67,4 +75,60 @@ public function ignorePackageDiscoveriesFrom() 'laravel/telescope', ]; } + + /** + * Create permissions for all resources + */ + protected function createPermissions(): self + { + $resources = [ + 'country', + 'currency', + 'post', + 'region', + 'tariff_code', + ]; + + $permissions = [ + 'view_any', + 'view', + 'create', + 'update', + 'restore', + 'restore_any', + 'delete', + 'delete_any', + 'force_delete', + 'force_delete_any', + ]; + + foreach ($resources as $resource) { + foreach ($permissions as $permission) { + \Spatie\Permission\Models\Permission::create([ + 'name' => $permission.'_'.$resource, + 'guard_name' => 'web', + ]); + } + } + + return $this; + } + + /** + * Create roles + */ + protected function createRoles(): self + { + \Spatie\Permission\Models\Role::create([ + 'name' => 'super_admin', + 'guard_name' => 'web', + ]); + + \Spatie\Permission\Models\Role::create([ + 'name' => 'panel_user', + 'guard_name' => 'web', + ]); + + return $this; + } } diff --git a/tests/Unit/ImportTariffCodesJobTest.php b/tests/Unit/ImportTariffCodesJobTest.php index 1284091..191b343 100644 --- a/tests/Unit/ImportTariffCodesJobTest.php +++ b/tests/Unit/ImportTariffCodesJobTest.php @@ -36,7 +36,7 @@ function fakeCnResponses(int $year, array $overrides = []): void fakeCnResponses($year); // Verify the job runs without throwing exceptions - expect(fn () => (new ImportTariffCodes(['en']))->handle())->not->toThrow(\Exception::class); + expect(fn () => (new ImportTariffCodes(['en']))->handle())->not->toThrow(Exception::class); }); test('imports EN + SL with unit resolution', function () { @@ -44,7 +44,7 @@ function fakeCnResponses(int $year, array $overrides = []): void fakeCnResponses($year); // Verify the job runs without throwing exceptions - expect(fn () => (new ImportTariffCodes(['en', 'sl']))->handle())->not->toThrow(\Exception::class); + expect(fn () => (new ImportTariffCodes(['en', 'sl']))->handle())->not->toThrow(Exception::class); }); test('imports other language without units', function () { @@ -56,7 +56,7 @@ function fakeCnResponses(int $year, array $overrides = []): void ]); // Verify the job runs without throwing exceptions - expect(fn () => (new ImportTariffCodes(['hr']))->handle())->not->toThrow(\Exception::class); + expect(fn () => (new ImportTariffCodes(['hr']))->handle())->not->toThrow(Exception::class); }); test('missing year gracefully falls back to previous year', function () { @@ -70,5 +70,5 @@ function fakeCnResponses(int $year, array $overrides = []): void fakeCnResponses($year - 1); // Current year // Verify the job runs without throwing exceptions - expect(fn () => (new ImportTariffCodes(['en']))->handle())->not->toThrow(\Exception::class); + expect(fn () => (new ImportTariffCodes(['en']))->handle())->not->toThrow(Exception::class); }); diff --git a/workbench/app/Http/Middleware/WorkbenchBootstrap.php b/workbench/app/Http/Middleware/WorkbenchBootstrap.php index adddb77..ac6fadb 100644 --- a/workbench/app/Http/Middleware/WorkbenchBootstrap.php +++ b/workbench/app/Http/Middleware/WorkbenchBootstrap.php @@ -13,6 +13,7 @@ use Spatie\Permission\Models\Permission; use Spatie\Permission\Models\Role; use Spatie\Permission\PermissionRegistrar; +use Throwable; use Workbench\App\Models\User; class WorkbenchBootstrap @@ -32,7 +33,7 @@ public function handle(Request $request, Closure $next) 'email_verified_at' => now(), ], ); - } catch (\Throwable $e) { + } catch (Throwable $e) { Log::error('[Workbench] User creation failed', ['message' => $e->getMessage()]); // In case of a race/unique constraint, fetch the existing one $user = User::query()->where('email', 'test@example.com')->first(); @@ -105,7 +106,7 @@ private function bootstrapPermissionsAndAssign(User $user): void // Mark as bootstrapped (cache for 1 hour) Cache::put($cacheKey, true, 3600); }); - } catch (\Throwable $e) { + } catch (Throwable $e) { Log::error('[Workbench] Bootstrap permissions failed', ['message' => $e->getMessage()]); } } diff --git a/workbench/app/Policies/CountryPolicy.php b/workbench/app/Policies/CountryPolicy.php new file mode 100644 index 0000000..719e3e4 --- /dev/null +++ b/workbench/app/Policies/CountryPolicy.php @@ -0,0 +1,74 @@ +can('view_any_country'); + } + + public function view(AuthUser $authUser, Country $country): bool + { + return $authUser->can('view_country'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('create_country'); + } + + public function update(AuthUser $authUser, Country $country): bool + { + return $authUser->can('update_country'); + } + + public function restore(AuthUser $authUser, Country $country): bool + { + return $authUser->can('restore_country'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('restore_any_country'); + } + + public function replicate(AuthUser $authUser, Country $country): bool + { + return $authUser->can('replicate_country'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('reorder_country'); + } + + public function delete(AuthUser $authUser, Country $country): bool + { + return $authUser->can('delete_country'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('delete_any_country'); + } + + public function forceDelete(AuthUser $authUser, Country $country): bool + { + return $authUser->can('force_delete_country'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('force_delete_any_country'); + } +} diff --git a/workbench/app/Policies/CurrencyPolicy.php b/workbench/app/Policies/CurrencyPolicy.php new file mode 100644 index 0000000..bc8688c --- /dev/null +++ b/workbench/app/Policies/CurrencyPolicy.php @@ -0,0 +1,74 @@ +can('view_any_currency'); + } + + public function view(AuthUser $authUser, Currency $currency): bool + { + return $authUser->can('view_currency'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('create_currency'); + } + + public function update(AuthUser $authUser, Currency $currency): bool + { + return $authUser->can('update_currency'); + } + + public function restore(AuthUser $authUser, Currency $currency): bool + { + return $authUser->can('restore_currency'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('restore_any_currency'); + } + + public function replicate(AuthUser $authUser, Currency $currency): bool + { + return $authUser->can('replicate_currency'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('reorder_currency'); + } + + public function delete(AuthUser $authUser, Currency $currency): bool + { + return $authUser->can('delete_currency'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('delete_any_currency'); + } + + public function forceDelete(AuthUser $authUser, Currency $currency): bool + { + return $authUser->can('force_delete_currency'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('force_delete_any_currency'); + } +} diff --git a/workbench/app/Policies/PostPolicy.php b/workbench/app/Policies/PostPolicy.php new file mode 100644 index 0000000..5d2258b --- /dev/null +++ b/workbench/app/Policies/PostPolicy.php @@ -0,0 +1,74 @@ +can('view_any_post'); + } + + public function view(AuthUser $authUser, Post $post): bool + { + return $authUser->can('view_post'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('create_post'); + } + + public function update(AuthUser $authUser, Post $post): bool + { + return $authUser->can('update_post'); + } + + public function restore(AuthUser $authUser, Post $post): bool + { + return $authUser->can('restore_post'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('restore_any_post'); + } + + public function replicate(AuthUser $authUser, Post $post): bool + { + return $authUser->can('replicate_post'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('reorder_post'); + } + + public function delete(AuthUser $authUser, Post $post): bool + { + return $authUser->can('delete_post'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('delete_any_post'); + } + + public function forceDelete(AuthUser $authUser, Post $post): bool + { + return $authUser->can('force_delete_post'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('force_delete_any_post'); + } +} diff --git a/workbench/app/Policies/RegionPolicy.php b/workbench/app/Policies/RegionPolicy.php new file mode 100644 index 0000000..499d78d --- /dev/null +++ b/workbench/app/Policies/RegionPolicy.php @@ -0,0 +1,74 @@ +can('view_any_region'); + } + + public function view(AuthUser $authUser, Region $region): bool + { + return $authUser->can('view_region'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('create_region'); + } + + public function update(AuthUser $authUser, Region $region): bool + { + return $authUser->can('update_region'); + } + + public function restore(AuthUser $authUser, Region $region): bool + { + return $authUser->can('restore_region'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('restore_any_region'); + } + + public function replicate(AuthUser $authUser, Region $region): bool + { + return $authUser->can('replicate_region'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('reorder_region'); + } + + public function delete(AuthUser $authUser, Region $region): bool + { + return $authUser->can('delete_region'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('delete_any_region'); + } + + public function forceDelete(AuthUser $authUser, Region $region): bool + { + return $authUser->can('force_delete_region'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('force_delete_any_region'); + } +} diff --git a/workbench/app/Policies/RolePolicy.php b/workbench/app/Policies/RolePolicy.php index ad2a069..7c960da 100644 --- a/workbench/app/Policies/RolePolicy.php +++ b/workbench/app/Policies/RolePolicy.php @@ -1,108 +1,74 @@ can('view_any_role'); + return $authUser->can('view_any_role'); } - /** - * Determine whether the user can view the model. - */ - public function view(Authorizable $user, Role $role): bool + public function view(AuthUser $authUser, Role $role): bool { - return $user->can('view_role'); + return $authUser->can('view_role'); } - /** - * Determine whether the user can create models. - */ - public function create(Authorizable $user): bool + public function create(AuthUser $authUser): bool { - return $user->can('create_role'); + return $authUser->can('create_role'); } - /** - * Determine whether the user can update the model. - */ - public function update(Authorizable $user, Role $role): bool + public function update(AuthUser $authUser, Role $role): bool { - return $user->can('update_role'); + return $authUser->can('update_role'); } - /** - * Determine whether the user can delete the model. - */ - public function delete(Authorizable $user, Role $role): bool + public function restore(AuthUser $authUser, Role $role): bool { - return $user->can('delete_role'); + return $authUser->can('restore_role'); } - /** - * Determine whether the user can bulk delete. - */ - public function deleteAny(Authorizable $user): bool + public function restoreAny(AuthUser $authUser): bool { - return $user->can('delete_any_role'); + return $authUser->can('restore_any_role'); } - /** - * Determine whether the user can permanently delete. - */ - public function forceDelete(Authorizable $user, Role $role): bool + public function replicate(AuthUser $authUser, Role $role): bool { - return $user->can('force_delete_role'); + return $authUser->can('replicate_role'); } - /** - * Determine whether the user can permanently bulk delete. - */ - public function forceDeleteAny(Authorizable $user): bool + public function reorder(AuthUser $authUser): bool { - return $user->can('force_delete_any_role'); + return $authUser->can('reorder_role'); } - /** - * Determine whether the user can restore. - */ - public function restore(Authorizable $user, Role $role): bool + public function delete(AuthUser $authUser, Role $role): bool { - return $user->can('restore_role'); + return $authUser->can('delete_role'); } - /** - * Determine whether the user can bulk restore. - */ - public function restoreAny(Authorizable $user): bool + public function deleteAny(AuthUser $authUser): bool { - return $user->can('restore_any_role'); + return $authUser->can('delete_any_role'); } - /** - * Determine whether the user can replicate. - */ - public function replicate(Authorizable $user, Role $role): bool + public function forceDelete(AuthUser $authUser, Role $role): bool { - return $user->can('replicate_role'); + return $authUser->can('force_delete_role'); } - /** - * Determine whether the user can reorder. - */ - public function reorder(Authorizable $user): bool + public function forceDeleteAny(AuthUser $authUser): bool { - return $user->can('reorder_role'); + return $authUser->can('force_delete_any_role'); } } diff --git a/workbench/app/Policies/TariffCodePolicy.php b/workbench/app/Policies/TariffCodePolicy.php new file mode 100644 index 0000000..696c714 --- /dev/null +++ b/workbench/app/Policies/TariffCodePolicy.php @@ -0,0 +1,74 @@ +can('view_any_tariff_code'); + } + + public function view(AuthUser $authUser, TariffCode $tariffCode): bool + { + return $authUser->can('view_tariff_code'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('create_tariff_code'); + } + + public function update(AuthUser $authUser, TariffCode $tariffCode): bool + { + return $authUser->can('update_tariff_code'); + } + + public function restore(AuthUser $authUser, TariffCode $tariffCode): bool + { + return $authUser->can('restore_tariff_code'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('restore_any_tariff_code'); + } + + public function replicate(AuthUser $authUser, TariffCode $tariffCode): bool + { + return $authUser->can('replicate_tariff_code'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('reorder_tariff_code'); + } + + public function delete(AuthUser $authUser, TariffCode $tariffCode): bool + { + return $authUser->can('delete_tariff_code'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('delete_any_tariff_code'); + } + + public function forceDelete(AuthUser $authUser, TariffCode $tariffCode): bool + { + return $authUser->can('force_delete_tariff_code'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('force_delete_any_tariff_code'); + } +} diff --git a/workbench/app/Providers/AdminPanelProvider.php b/workbench/app/Providers/AdminPanelProvider.php index 28bf372..9ef49f2 100644 --- a/workbench/app/Providers/AdminPanelProvider.php +++ b/workbench/app/Providers/AdminPanelProvider.php @@ -10,7 +10,6 @@ use Filament\Pages\Dashboard; use Filament\Panel; use Filament\PanelProvider; -use Filament\SpatieLaravelTranslatablePlugin; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Cookie\Middleware\EncryptCookies; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; @@ -18,6 +17,7 @@ use Illuminate\Session\Middleware\AuthenticateSession; use Illuminate\Session\Middleware\StartSession; use Illuminate\View\Middleware\ShareErrorsFromSession; +use LaraZeus\SpatieTranslatable\SpatieTranslatablePlugin; use Workbench\App\Http\Middleware\WorkbenchBootstrap; class AdminPanelProvider extends PanelProvider @@ -47,7 +47,7 @@ public function panel(Panel $panel): Panel ->plugins([ FilamentShieldPlugin::make(), EclipseWorld::make(), - SpatieLaravelTranslatablePlugin::make() + SpatieTranslatablePlugin::make() ->defaultLocales(['en']), ]) ->viteTheme(false) diff --git a/workbench/app/Providers/WorkbenchServiceProvider.php b/workbench/app/Providers/WorkbenchServiceProvider.php index bd60efb..62715cf 100644 --- a/workbench/app/Providers/WorkbenchServiceProvider.php +++ b/workbench/app/Providers/WorkbenchServiceProvider.php @@ -2,7 +2,11 @@ namespace Workbench\App\Providers; +use BezhanSalleh\FilamentShield\FilamentShieldServiceProvider; +use Filament\FilamentServiceProvider; use Illuminate\Support\ServiceProvider; +use Livewire\LivewireServiceProvider; +use Spatie\Permission\PermissionServiceProvider; class WorkbenchServiceProvider extends ServiceProvider { @@ -11,10 +15,10 @@ class WorkbenchServiceProvider extends ServiceProvider */ public function register(): void { - $this->app->register(\Spatie\Permission\PermissionServiceProvider::class); - $this->app->register(\BezhanSalleh\FilamentShield\FilamentShieldServiceProvider::class); - $this->app->register(\Livewire\LivewireServiceProvider::class); - $this->app->register(\Filament\FilamentServiceProvider::class); + $this->app->register(PermissionServiceProvider::class); + $this->app->register(FilamentShieldServiceProvider::class); + $this->app->register(LivewireServiceProvider::class); + $this->app->register(FilamentServiceProvider::class); $this->app->register(AdminPanelProvider::class); $this->app->register(AuthServiceProvider::class); } diff --git a/workbench/config/auth.php b/workbench/config/auth.php index 8337867..df32bc3 100644 --- a/workbench/config/auth.php +++ b/workbench/config/auth.php @@ -1,5 +1,7 @@ [ 'users' => [ 'driver' => 'eloquent', - 'model' => env('AUTH_MODEL', \Workbench\App\Models\User::class), + 'model' => env('AUTH_MODEL', User::class), ], // 'users' => [ diff --git a/workbench/config/filament-shield.php b/workbench/config/filament-shield.php index 53532a6..d818cce 100644 --- a/workbench/config/filament-shield.php +++ b/workbench/config/filament-shield.php @@ -1,30 +1,32 @@ [ - 'should_register_navigation' => true, 'slug' => 'shield/roles', - 'navigation_sort' => -1, - 'navigation_badge' => true, - 'navigation_group' => true, - 'sub_navigation_position' => null, - 'is_globally_searchable' => false, 'show_model_path' => true, - 'is_scoped_to_tenant' => true, 'cluster' => null, + 'tabs' => [ + 'pages' => true, + 'widgets' => true, + 'resources' => true, + 'custom_permissions' => false, + ], ], 'tenant_model' => null, - 'auth_provider_model' => [ - 'fqcn' => 'Workbench\\App\\Models\\User', - ], + 'auth_provider_model' => Workbench\App\Models\User::class, 'super_admin' => [ 'enabled' => true, 'name' => 'super_admin', 'define_via_gate' => false, - 'intercept_gate' => 'before', // after + 'intercept_gate' => 'before', ], 'panel_user' => [ @@ -32,61 +34,64 @@ 'name' => 'panel_user', ], - 'permission_prefixes' => [ - 'resource' => [ - 'view', - 'view_any', - 'create', - 'update', - 'restore', - 'restore_any', - 'replicate', - 'reorder', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ], - - 'page' => 'page', - 'widget' => 'widget', + 'permissions' => [ + 'separator' => '_', + 'case' => 'lower_snake', + 'generate' => true, ], - 'entities' => [ - 'pages' => true, - 'widgets' => true, - 'resources' => true, - 'custom_permissions' => false, + 'policies' => [ + 'path' => app_path('Policies'), + 'merge' => true, + 'generate' => true, + 'methods' => [ + 'viewAny', 'view', 'create', 'update', 'restore', 'restoreAny', + 'replicate', 'reorder', 'delete', 'deleteAny', 'forceDelete', 'forceDeleteAny', + ], + 'single_parameter_methods' => [ + 'viewAny', 'create', 'deleteAny', 'forceDeleteAny', 'restoreAny', 'reorder', + ], ], - 'generator' => [ - 'option' => 'permissions', - 'policy_directory' => 'Policies', - 'policy_namespace' => 'Policies', + 'localization' => [ + 'enabled' => false, + 'key' => 'filament-shield::filament-shield', ], - 'exclude' => [ - 'enabled' => true, - - 'pages' => [ - 'Dashboard', + 'resources' => [ + 'subject' => 'model', + 'manage' => [ + RoleResource::class => [ + 'viewAny', 'view', 'create', 'update', 'delete', + ], ], + 'exclude' => [], + ], - 'widgets' => [ - 'AccountWidget', 'FilamentInfoWidget', + 'pages' => [ + 'subject' => 'class', + 'prefix' => 'view', + 'exclude' => [ + Dashboard::class, ], + ], - 'resources' => [], + 'widgets' => [ + 'subject' => 'class', + 'prefix' => 'view', + 'exclude' => [ + AccountWidget::class, + FilamentInfoWidget::class, + ], ], + 'custom_permissions' => [], + 'discovery' => [ 'discover_all_resources' => false, 'discover_all_widgets' => false, 'discover_all_pages' => false, ], - 'register_role_policy' => [ - 'enabled' => true, - ], - + 'register_role_policy' => true, ]; diff --git a/workbench/config/permission.php b/workbench/config/permission.php index f39f6b5..85b8832 100644 --- a/workbench/config/permission.php +++ b/workbench/config/permission.php @@ -1,5 +1,9 @@ [ @@ -13,7 +17,7 @@ * `Spatie\Permission\Contracts\Permission` contract. */ - 'permission' => Spatie\Permission\Models\Permission::class, + 'permission' => Permission::class, /* * When using the "HasRoles" trait from this package, we need to know which @@ -24,7 +28,7 @@ * `Spatie\Permission\Contracts\Role` contract. */ - 'role' => Spatie\Permission\Models\Role::class, + 'role' => Role::class, ], @@ -136,7 +140,7 @@ /* * The class to use to resolve the permissions team id */ - 'team_resolver' => \Spatie\Permission\DefaultTeamResolver::class, + 'team_resolver' => DefaultTeamResolver::class, /* * Passport Client Credentials Grant @@ -183,7 +187,7 @@ * When permissions or roles are updated the cache is flushed automatically. */ - 'expiration_time' => \DateInterval::createFromDateString('24 hours'), + 'expiration_time' => DateInterval::createFromDateString('24 hours'), /* * The cache key used to store all permissions. diff --git a/workbench/database/factories/UserFactory.php b/workbench/database/factories/UserFactory.php index dfcab01..8a58e9e 100644 --- a/workbench/database/factories/UserFactory.php +++ b/workbench/database/factories/UserFactory.php @@ -10,7 +10,7 @@ /** * @template TModel of \Workbench\App\Models\User * - * @extends \Illuminate\Database\Eloquent\Factories\Factory + * @extends Factory */ class UserFactory extends Factory { diff --git a/workbench/database/migrations/2025_08_28_142604_create_permission_tables.php b/workbench/database/migrations/2025_08_28_142604_create_permission_tables.php index ce4d9d2..5f8d69a 100644 --- a/workbench/database/migrations/2025_08_28_142604_create_permission_tables.php +++ b/workbench/database/migrations/2025_08_28_142604_create_permission_tables.php @@ -124,7 +124,7 @@ public function down(): void $tableNames = config('permission.table_names'); if (empty($tableNames)) { - throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); + throw new Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); } Schema::drop($tableNames['role_has_permissions']); diff --git a/workbench/public/.gitignore b/workbench/public/.gitignore new file mode 100644 index 0000000..0480ebe --- /dev/null +++ b/workbench/public/.gitignore @@ -0,0 +1 @@ +fonts/