From cf732fd7925923235a5aa43db947dbd84c18eb69 Mon Sep 17 00:00:00 2001 From: Kilian Trunk Date: Mon, 22 Sep 2025 15:10:21 +0200 Subject: [PATCH 1/7] feat: migrate to f4 --- composer.json | 24 ++- src/Casts/BackgroundCast.php | 5 +- src/CatalogueServiceProvider.php | 6 +- src/Factories/ProductTypeFactory.php | 5 +- .../CustomPropertyContainsOperator.php | 3 +- .../CustomPropertyEndsWithOperator.php | 3 +- .../CustomPropertyEqualsOperator.php | 3 +- .../CustomPropertyStartsWithOperator.php | 3 +- .../Forms/Components/ImageManager.php | 29 ++-- src/Filament/Resources/CategoryResource.php | 57 +++---- .../CategoryResource/Pages/CreateCategory.php | 7 +- .../CategoryResource/Pages/EditCategory.php | 16 +- .../CategoryResource/Pages/ListCategories.php | 16 +- .../Pages/SortingCategory.php | 4 +- .../Concerns/HandlesImageUploads.php | 4 +- src/Filament/Resources/GroupResource.php | 46 +++--- .../GroupResource/Pages/CreateGroup.php | 3 +- .../GroupResource/Pages/EditGroup.php | 4 +- .../GroupResource/Pages/ListGroups.php | 4 +- .../ProductsRelationManager.php | 55 ++++--- .../Resources/MeasureUnitResource.php | 32 ++-- src/Filament/Resources/PriceListResource.php | 26 ++-- .../Pages/CreatePriceList.php | 6 +- .../PriceListResource/Pages/EditPriceList.php | 9 +- src/Filament/Resources/ProductResource.php | 112 ++++++++------ .../ProductResource/Pages/CreateProduct.php | 26 ++-- .../ProductResource/Pages/EditProduct.php | 41 +++-- .../ProductResource/Pages/ListProducts.php | 13 +- .../ProductResource/Pages/ViewProduct.php | 10 +- .../PricesRelationManager.php | 38 +++-- .../Resources/ProductStatusResource.php | 53 ++++--- .../Pages/CreateProductStatus.php | 12 +- .../Pages/EditProductStatus.php | 12 +- .../Pages/ListProductStatuses.php | 9 +- .../Resources/ProductTypeResource.php | 32 ++-- .../Pages/CreateProductType.php | 10 +- .../Pages/EditProductType.php | 13 +- .../Pages/ListProductTypes.php | 4 +- .../PropertiesRelationManager.php | 59 ++++--- src/Filament/Resources/PropertyResource.php | 145 ++++++++++-------- .../PropertyResource/Pages/CreateProperty.php | 4 +- .../PropertyResource/Pages/EditProperty.php | 12 +- .../PropertyResource/Pages/ListProperties.php | 6 +- .../ValuesRelationManager.php | 57 ++++--- .../Resources/PropertyValueResource.php | 133 +++++++++------- .../Pages/ListPropertyValues.php | 39 +++-- src/Filament/Resources/TaxClassResource.php | 32 ++-- .../Actions/BulkUpdateProductsAction.php | 31 ++-- .../GenericTenantFieldsComponent.php | 20 +-- .../Components/InlineTranslatableField.php | 15 +- src/Jobs/ImportColorValues.php | 12 +- src/Livewire/TenantSwitcher.php | 5 +- src/Models/Group.php | 3 +- src/Models/PriceListData.php | 6 +- src/Models/Product.php | 6 +- src/Models/ProductData.php | 6 +- src/Models/ProductStatus.php | 8 +- src/Models/ProductType.php | 3 +- src/Models/ProductTypeData.php | 6 +- src/Models/Property.php | 5 +- src/Models/PropertyValue.php | 5 +- src/Models/TaxClass.php | 2 +- src/Services/ProductBulkUpdater.php | 21 ++- src/Traits/HandlesTenantData.php | 6 +- src/Traits/HasPriceListForm.php | 6 +- src/Traits/HasProductTypeForm.php | 4 +- src/Traits/HasTenantFields.php | 4 +- src/Traits/HasTenantScopedData.php | 25 +-- tests/Feature/CategoryResourceTest.php | 12 +- tests/Feature/GroupCodeUniquenessTest.php | 3 +- tests/Feature/ImportColorValuesTest.php | 3 +- tests/Feature/PriceListTest.php | 3 +- tests/Feature/ProductBulkUpdateTest.php | 18 ++- tests/Feature/ProductPriceTest.php | 6 +- tests/Feature/ProductResourceTest.php | 4 +- tests/Feature/ProductStatusCrudTest.php | 3 +- .../ProductStatusLabelRenderingTest.php | 3 +- tests/Feature/ProductStatusUniquenessTest.php | 5 +- tests/Feature/ProductStatusValidationTest.php | 7 +- tests/Feature/ProductTypeTest.php | 11 +- tests/Feature/PropertyValidationTest.php | 10 +- tests/Feature/PropertyValueColorFormTest.php | 31 ++-- tests/Pest.php | 4 +- tests/Unit/ColorBackgroundTest.php | 2 +- .../app/Providers/AdminPanelProvider.php | 4 +- workbench/database/factories/UserFactory.php | 2 +- 86 files changed, 894 insertions(+), 678 deletions(-) diff --git a/composer.json b/composer.json index 060dd25..34dec38 100644 --- a/composer.json +++ b/composer.json @@ -45,20 +45,30 @@ }, "require": { "php": "^8.2", - "bezhansalleh/filament-shield": "^3.3", + "bezhansalleh/filament-shield": "^4.0", "datalinx/php-utils": "^2.5", - "eclipsephp/common": "dev-main", - "eclipsephp/world-plugin": "dev-main", - "filament/filament": "^3.3", - "filament/spatie-laravel-media-library-plugin": "^3.2", - "filament/spatie-laravel-translatable-plugin": "^3.2", + "eclipsephp/common": "dev-f4@dev", + "eclipsephp/world-plugin": "dev-f4@dev", + "filament/filament": "^4.0", + "filament/spatie-laravel-media-library-plugin": "^4.0", + "lara-zeus/spatie-translatable": "^1.0", "laravel/framework": "^11.0|^12.0", "nben/filament-record-nav": "^1.0", "phpoffice/phpspreadsheet": "^1.30", - "solution-forest/filament-tree": "^2.1", + "solution-forest/filament-tree": "^3.0", "spatie/laravel-package-tools": "^1.19", "spatie/laravel-translatable": "^6.11" }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/KilianTrunk/eclipsephp-common.git" + }, + { + "type": "vcs", + "url": "https://github.com/KilianTrunk/eclipsephp-world-plugin.git" + } + ], "require-dev": { "laravel/pint": "^1.21", "orchestra/testbench": "^9.0|^10.1", diff --git a/src/Casts/BackgroundCast.php b/src/Casts/BackgroundCast.php index 2026212..c66e909 100644 --- a/src/Casts/BackgroundCast.php +++ b/src/Casts/BackgroundCast.php @@ -4,13 +4,14 @@ use Eclipse\Catalogue\Values\Background; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; +use Illuminate\Database\Eloquent\Model; class BackgroundCast implements CastsAttributes { /** * Cast the attribute from the database. * - * @param \Illuminate\Database\Eloquent\Model $model The model instance. + * @param Model $model The model instance. * @param string $key The attribute name. * @param mixed $value The attribute value. * @param array $attributes The attributes array. @@ -37,7 +38,7 @@ public function get($model, string $key, $value, array $attributes): Background /** * Cast the attribute to a database value. * - * @param \Illuminate\Database\Eloquent\Model $model The model instance. + * @param Model $model The model instance. * @param string $key The attribute name. * @param mixed $value The attribute value. * @param array $attributes The attributes array. diff --git a/src/CatalogueServiceProvider.php b/src/CatalogueServiceProvider.php index 6b76791..8f5a7c6 100644 --- a/src/CatalogueServiceProvider.php +++ b/src/CatalogueServiceProvider.php @@ -2,11 +2,13 @@ namespace Eclipse\Catalogue; +use Eclipse\Catalogue\Livewire\TenantSwitcher; use Eclipse\Catalogue\Models\Category; use Eclipse\Catalogue\Models\Product; use Filament\Support\Assets\Css; use Filament\Support\Facades\FilamentAsset; use Illuminate\Support\Facades\Config; +use Livewire\Livewire; use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; @@ -45,8 +47,8 @@ public function boot() parent::boot(); // Register Livewire components - if (class_exists(\Livewire\Livewire::class)) { - \Livewire\Livewire::component('eclipse-catalogue::tenant-switcher', \Eclipse\Catalogue\Livewire\TenantSwitcher::class); + if (class_exists(Livewire::class)) { + Livewire::component('eclipse-catalogue::tenant-switcher', TenantSwitcher::class); } FilamentAsset::register([ diff --git a/src/Factories/ProductTypeFactory.php b/src/Factories/ProductTypeFactory.php index 5b7aa27..febb806 100644 --- a/src/Factories/ProductTypeFactory.php +++ b/src/Factories/ProductTypeFactory.php @@ -3,6 +3,7 @@ namespace Eclipse\Catalogue\Factories; use Eclipse\Catalogue\Models\ProductType; +use Eclipse\Core\Models\Locale; use Illuminate\Database\Eloquent\Factories\Factory; class ProductTypeFactory extends Factory @@ -35,8 +36,8 @@ public function definition(): array */ protected function getAvailableLocales(): array { - if (class_exists(\Eclipse\Core\Models\Locale::class)) { - return \Eclipse\Core\Models\Locale::getAvailableLocales() + if (class_exists(Locale::class)) { + return Locale::getAvailableLocales() ->pluck('id') ->toArray(); } diff --git a/src/Filament/Filters/Operators/CustomPropertyContainsOperator.php b/src/Filament/Filters/Operators/CustomPropertyContainsOperator.php index 0c7867d..9d46e63 100644 --- a/src/Filament/Filters/Operators/CustomPropertyContainsOperator.php +++ b/src/Filament/Filters/Operators/CustomPropertyContainsOperator.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Filters\Operators; -use Filament\Forms\Components\Component; use Filament\Forms\Components\TextInput; use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator; use Illuminate\Database\Eloquent\Builder; @@ -48,7 +47,7 @@ public function getSummary(): string /** * Get the form schema of the operator. * - * @return array + * @return array<\Filament\Schemas\Components\Component> */ public function getFormSchema(): array { diff --git a/src/Filament/Filters/Operators/CustomPropertyEndsWithOperator.php b/src/Filament/Filters/Operators/CustomPropertyEndsWithOperator.php index 68e98a4..12677c9 100644 --- a/src/Filament/Filters/Operators/CustomPropertyEndsWithOperator.php +++ b/src/Filament/Filters/Operators/CustomPropertyEndsWithOperator.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Filters\Operators; -use Filament\Forms\Components\Component; use Filament\Forms\Components\TextInput; use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator; use Illuminate\Database\Eloquent\Builder; @@ -48,7 +47,7 @@ public function getSummary(): string /** * Get the form schema of the operator. * - * @return array + * @return array<\Filament\Schemas\Components\Component> */ public function getFormSchema(): array { diff --git a/src/Filament/Filters/Operators/CustomPropertyEqualsOperator.php b/src/Filament/Filters/Operators/CustomPropertyEqualsOperator.php index 5a63376..e53cd94 100644 --- a/src/Filament/Filters/Operators/CustomPropertyEqualsOperator.php +++ b/src/Filament/Filters/Operators/CustomPropertyEqualsOperator.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Filters\Operators; -use Filament\Forms\Components\Component; use Filament\Forms\Components\TextInput; use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator; use Illuminate\Database\Eloquent\Builder; @@ -48,7 +47,7 @@ public function getSummary(): string /** * Get the form schema of the operator. * - * @return array + * @return array<\Filament\Schemas\Components\Component> */ public function getFormSchema(): array { diff --git a/src/Filament/Filters/Operators/CustomPropertyStartsWithOperator.php b/src/Filament/Filters/Operators/CustomPropertyStartsWithOperator.php index dcf3bf7..11dd299 100644 --- a/src/Filament/Filters/Operators/CustomPropertyStartsWithOperator.php +++ b/src/Filament/Filters/Operators/CustomPropertyStartsWithOperator.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Filters\Operators; -use Filament\Forms\Components\Component; use Filament\Forms\Components\TextInput; use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator; use Illuminate\Database\Eloquent\Builder; @@ -48,7 +47,7 @@ public function getSummary(): string /** * Get the form schema of the operator. * - * @return array + * @return array<\Filament\Schemas\Components\Component> */ public function getFormSchema(): array { diff --git a/src/Filament/Forms/Components/ImageManager.php b/src/Filament/Forms/Components/ImageManager.php index 8e32e67..5e4b3ce 100644 --- a/src/Filament/Forms/Components/ImageManager.php +++ b/src/Filament/Forms/Components/ImageManager.php @@ -2,7 +2,8 @@ namespace Eclipse\Catalogue\Filament\Forms\Components; -use Filament\Forms\Components\Actions\Action; +use Exception; +use Filament\Actions\Action; use Filament\Forms\Components\Field; use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\Placeholder; @@ -12,6 +13,8 @@ use Filament\Notifications\Notification; use Illuminate\Database\Eloquent\Model; use Spatie\MediaLibrary\MediaCollections\Models\Media; +use Storage; +use Str; class ImageManager extends Field { @@ -106,7 +109,7 @@ protected function setUp(): void 'position' => $index, ]) ->toMediaCollection($this->collection); - } catch (\Exception $e) { + } catch (Exception $e) { } } } @@ -150,7 +153,7 @@ public function getAvailableLocales(): array $locales[$locale] = $plugin->getLocaleLabel($locale) ?? $locale; } } - } catch (\Exception $e) { + } catch (Exception $e) { } if (empty($locales)) { @@ -167,7 +170,7 @@ public function getSelectedLocale(): string if ($livewire && property_exists($livewire, 'activeLocale')) { return $livewire->activeLocale; } - } catch (\Exception $e) { + } catch (Exception $e) { } return app()->getLocale(); @@ -181,7 +184,7 @@ public function getUploadAction(): Action ->color('primary') ->modalHeading('Upload Images') ->modalSubmitActionLabel('Upload') - ->form([ + ->schema([ FileUpload::make('files') ->label('Choose files') ->multiple() @@ -219,10 +222,10 @@ public function getUploadAction(): Action 'id' => null, 'temp_id' => $tempId, 'temp_file' => $filePath, - 'uuid' => (string) \Str::uuid(), - 'url' => \Storage::url($filePath), - 'thumb_url' => \Storage::url($filePath), - 'preview_url' => \Storage::url($filePath), + 'uuid' => (string) Str::uuid(), + 'url' => Storage::url($filePath), + 'thumb_url' => Storage::url($filePath), + 'preview_url' => Storage::url($filePath), 'name' => [], 'description' => [], 'is_cover' => count($currentState) === 0, @@ -292,7 +295,7 @@ public function getUrlUploadAction(): Action ->color('gray') ->modalHeading('Add Images from URLs') ->modalSubmitActionLabel('Add Images') - ->form([ + ->schema([ Textarea::make('urls') ->label('Image URLs') ->placeholder("https://example.com/image1.jpg\nhttps://example.com/image2.jpg") @@ -323,7 +326,7 @@ public function getUrlUploadAction(): Action 'id' => null, 'temp_id' => $tempId, 'temp_url' => $url, - 'uuid' => (string) \Str::uuid(), + 'uuid' => (string) Str::uuid(), 'url' => $url, 'thumb_url' => $url, 'preview_url' => $url, @@ -380,7 +383,7 @@ public function getUrlUploadAction(): Action ->toMediaCollection($this->collection); $successCount++; - } catch (\Exception $e) { + } catch (Exception $e) { $failedUrls[] = $url; } } else { @@ -474,7 +477,7 @@ public function getEditAction(): Action ->label('Edit Image') ->modalHeading('Edit Image Details') ->modalSubmitActionLabel('Save Changes') - ->form(function (array $arguments) { + ->schema(function (array $arguments) { $args = $arguments['arguments'] ?? $arguments; $uuid = $args['uuid'] ?? null; $selectedLocale = $args['selectedLocale'] ?? $this->getSelectedLocale(); diff --git a/src/Filament/Resources/CategoryResource.php b/src/Filament/Resources/CategoryResource.php index 52cff17..9fe04d7 100644 --- a/src/Filament/Resources/CategoryResource.php +++ b/src/Filament/Resources/CategoryResource.php @@ -3,32 +3,34 @@ namespace Eclipse\Catalogue\Filament\Resources; use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; -use Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages; +use Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages\CreateCategory; +use Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages\EditCategory; +use Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages\ListCategories; +use Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages\SortingCategory; use Eclipse\Catalogue\Models\Category; +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\Facades\Filament; use Filament\Forms\Components\FileUpload; -use Filament\Forms\Components\Grid; use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\RichEditor; -use Filament\Forms\Components\Section; use Filament\Forms\Components\Select; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; -use Filament\Forms\Form; -use Filament\Forms\Get; -use Filament\Forms\Set; -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\Components\Grid; +use Filament\Schemas\Components\Section; +use Filament\Schemas\Components\Utilities\Get; +use Filament\Schemas\Components\Utilities\Set; +use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\ImageColumn; use Filament\Tables\Columns\TextColumn; @@ -41,6 +43,7 @@ use Illuminate\Database\Eloquent\SoftDeletingScope; use Illuminate\Support\HtmlString; use Illuminate\Support\Str; +use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; class CategoryResource extends Resource implements HasShieldPermissions { @@ -50,9 +53,9 @@ class CategoryResource extends Resource implements HasShieldPermissions protected static ?string $slug = 'catalogue/categories'; - protected static ?string $navigationGroup = 'Catalogue'; + protected static string|\UnitEnum|null $navigationGroup = 'Catalogue'; - protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-rectangle-stack'; protected static ?string $recordTitleAttribute = 'name'; @@ -68,10 +71,10 @@ public static function getPluralModelLabel(): string return __('eclipse-catalogue::categories.title'); } - public static function form(Form $form): Form + public static function form(Schema $schema): Schema { - return $form - ->schema([ + return $schema + ->components([ Section::make(__('eclipse-catalogue::categories.form.sections.basic_information')) ->columns(2) ->schema([ @@ -334,7 +337,7 @@ public static function table(Table $table): Table ->toggle(), ]) - ->actions([ + ->recordActions([ ActionGroup::make([ EditAction::make() ->label(__('eclipse-catalogue::categories.actions.edit')), @@ -351,7 +354,7 @@ public static function table(Table $table): Table ->color('gray') ->button(), ]) - ->bulkActions([ + ->toolbarActions([ BulkActionGroup::make([ DeleteBulkAction::make() ->label(__('eclipse-catalogue::categories.actions.delete')), @@ -366,10 +369,10 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => Pages\ListCategories::route('/'), - 'create' => Pages\CreateCategory::route('/create'), - 'sorting' => Pages\SortingCategory::route('/sorting'), - 'edit' => Pages\EditCategory::route('/{record}/edit'), + 'index' => ListCategories::route('/'), + 'create' => CreateCategory::route('/create'), + 'sorting' => SortingCategory::route('/sorting'), + 'edit' => EditCategory::route('/{record}/edit'), ]; } diff --git a/src/Filament/Resources/CategoryResource/Pages/CreateCategory.php b/src/Filament/Resources/CategoryResource/Pages/CreateCategory.php index 7a6924c..a4735bd 100644 --- a/src/Filament/Resources/CategoryResource/Pages/CreateCategory.php +++ b/src/Filament/Resources/CategoryResource/Pages/CreateCategory.php @@ -3,19 +3,20 @@ namespace Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages; use Eclipse\Catalogue\Filament\Resources\CategoryResource; -use Filament\Actions; use Filament\Resources\Pages\CreateRecord; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\CreateRecord\Concerns\Translatable; class CreateCategory extends CreateRecord { - use CreateRecord\Concerns\Translatable; + use Translatable; protected static string $resource = CategoryResource::class; protected function getHeaderActions(): array { return [ - Actions\LocaleSwitcher::make(), + LocaleSwitcher::make(), ]; } } diff --git a/src/Filament/Resources/CategoryResource/Pages/EditCategory.php b/src/Filament/Resources/CategoryResource/Pages/EditCategory.php index d88aaaa..1879639 100644 --- a/src/Filament/Resources/CategoryResource/Pages/EditCategory.php +++ b/src/Filament/Resources/CategoryResource/Pages/EditCategory.php @@ -3,22 +3,26 @@ namespace Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages; use Eclipse\Catalogue\Filament\Resources\CategoryResource; -use Filament\Actions; +use Filament\Actions\DeleteAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\RestoreAction; use Filament\Resources\Pages\EditRecord; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\EditRecord\Concerns\Translatable; class EditCategory extends EditRecord { - use EditRecord\Concerns\Translatable; + use Translatable; protected static string $resource = CategoryResource::class; protected function getHeaderActions(): array { return [ - Actions\LocaleSwitcher::make(), - Actions\DeleteAction::make(), - Actions\ForceDeleteAction::make(), - Actions\RestoreAction::make(), + LocaleSwitcher::make(), + DeleteAction::make(), + ForceDeleteAction::make(), + RestoreAction::make(), ]; } } diff --git a/src/Filament/Resources/CategoryResource/Pages/ListCategories.php b/src/Filament/Resources/CategoryResource/Pages/ListCategories.php index fc4270e..351e3bc 100644 --- a/src/Filament/Resources/CategoryResource/Pages/ListCategories.php +++ b/src/Filament/Resources/CategoryResource/Pages/ListCategories.php @@ -4,10 +4,12 @@ use Eclipse\Catalogue\Filament\Resources\CategoryResource; use Eclipse\Common\Foundation\Pages\HasScoutSearch; -use Filament\Actions; +use Filament\Actions\Action; +use Filament\Actions\CreateAction; use Filament\Resources\Pages\ListRecords; -use Filament\Resources\Pages\ListRecords\Concerns\Translatable; -use Filament\Support\Enums\MaxWidth; +use Filament\Support\Enums\Width; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\ListRecords\Concerns\Translatable; class ListCategories extends ListRecords { @@ -15,18 +17,18 @@ class ListCategories extends ListRecords protected static string $resource = CategoryResource::class; - protected ?string $maxContentWidth = MaxWidth::Full->value; + protected Width|string|null $maxContentWidth = Width::Full->value; protected function getHeaderActions(): array { return [ - Actions\LocaleSwitcher::make(), - Actions\Action::make('sorting') + LocaleSwitcher::make(), + Action::make('sorting') ->label(__('eclipse-catalogue::categories.actions.sorting')) ->icon('heroicon-o-arrows-up-down') ->color('gray') ->url(fn () => self::$resource::getUrl('sorting')), - Actions\CreateAction::make() + CreateAction::make() ->label(__('eclipse-catalogue::categories.actions.create')) ->icon('heroicon-o-plus-circle'), ]; diff --git a/src/Filament/Resources/CategoryResource/Pages/SortingCategory.php b/src/Filament/Resources/CategoryResource/Pages/SortingCategory.php index 20863b7..62e6044 100644 --- a/src/Filament/Resources/CategoryResource/Pages/SortingCategory.php +++ b/src/Filament/Resources/CategoryResource/Pages/SortingCategory.php @@ -3,8 +3,8 @@ namespace Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages; use Eclipse\Catalogue\Filament\Resources\CategoryResource; -use Filament\Actions; use Illuminate\Database\Eloquent\Model; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; use SolutionForest\FilamentTree\Concern\TreeRecords\Translatable; use SolutionForest\FilamentTree\Resources\Pages\TreePage as BasePage; @@ -24,7 +24,7 @@ public function getTitle(): string protected function getActions(): array { return [ - Actions\LocaleSwitcher::make(), + LocaleSwitcher::make(), $this->getCreateAction() ->translateLabel() ->label(__('eclipse-catalogue::categories.actions.create')) diff --git a/src/Filament/Resources/Concerns/HandlesImageUploads.php b/src/Filament/Resources/Concerns/HandlesImageUploads.php index 9be853e..cc98f4e 100644 --- a/src/Filament/Resources/Concerns/HandlesImageUploads.php +++ b/src/Filament/Resources/Concerns/HandlesImageUploads.php @@ -2,6 +2,8 @@ namespace Eclipse\Catalogue\Filament\Resources\Concerns; +use Exception; + trait HandlesImageUploads { public ?array $temporaryImages = null; @@ -50,7 +52,7 @@ protected function afterCreate(): void 'position' => $index, ]) ->toMediaCollection('images'); - } catch (\Exception $e) { + } catch (Exception $e) { } } } diff --git a/src/Filament/Resources/GroupResource.php b/src/Filament/Resources/GroupResource.php index 476ae52..31226e7 100644 --- a/src/Filament/Resources/GroupResource.php +++ b/src/Filament/Resources/GroupResource.php @@ -3,20 +3,24 @@ namespace Eclipse\Catalogue\Filament\Resources; use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; -use Eclipse\Catalogue\Filament\Resources\GroupResource\Pages; +use Eclipse\Catalogue\Filament\Resources\GroupResource\Pages\CreateGroup; +use Eclipse\Catalogue\Filament\Resources\GroupResource\Pages\EditGroup; +use Eclipse\Catalogue\Filament\Resources\GroupResource\Pages\ListGroups; +use Eclipse\Catalogue\Filament\Resources\GroupResource\RelationManagers\ProductsRelationManager; use Eclipse\Catalogue\Models\Group; use Eclipse\Common\Foundation\Models\Scopes\ActiveScope; -use Filament\Forms\Components\Section; +use Filament\Actions\ActionGroup; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; +use Filament\Facades\Filament; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; -use Filament\Forms\Form; use Filament\Resources\RelationManagers\RelationGroup; 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\Schemas\Components\Section; +use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\TernaryFilter; @@ -30,16 +34,16 @@ class GroupResource extends Resource implements HasShieldPermissions protected static ?string $slug = 'groups'; - protected static ?string $navigationIcon = 'heroicon-o-tag'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-tag'; - protected static ?string $navigationGroup = 'Catalogue'; + protected static string|\UnitEnum|null $navigationGroup = 'Catalogue'; protected static ?string $recordTitleAttribute = 'name'; - public static function form(Form $form): Form + public static function form(Schema $schema): Schema { - return $form - ->schema([ + return $schema + ->components([ Section::make('Group Information') ->schema([ TextInput::make('name') @@ -50,7 +54,7 @@ public static function form(Form $form): Form ->required() ->maxLength(50) ->unique(ignoreRecord: true, modifyRuleUsing: function ($rule) { - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); if ($currentTenant) { return $rule->where($tenantFK, $currentTenant->id); @@ -117,7 +121,7 @@ public static function table(Table $table): Table TernaryFilter::make('is_browsable') ->label('Browsable'), ]) - ->actions([ + ->recordActions([ ActionGroup::make([ EditAction::make(), DeleteAction::make(), @@ -128,7 +132,7 @@ public static function table(Table $table): Table ->color('gray') ->button(), ]) - ->bulkActions([ + ->toolbarActions([ BulkActionGroup::make([ DeleteBulkAction::make(), ]), @@ -138,9 +142,9 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => Pages\ListGroups::route('/'), - 'create' => Pages\CreateGroup::route('/create'), - 'edit' => Pages\EditGroup::route('/{record}/edit'), + 'index' => ListGroups::route('/'), + 'create' => CreateGroup::route('/create'), + 'edit' => EditGroup::route('/{record}/edit'), ]; } @@ -148,7 +152,7 @@ public static function getRelations(): array { return [ RelationGroup::make('Products', [ - \Eclipse\Catalogue\Filament\Resources\GroupResource\RelationManagers\ProductsRelationManager::class, + ProductsRelationManager::class, ]), ]; } @@ -158,7 +162,7 @@ public static function getEloquentQuery(): Builder $query = parent::getEloquentQuery() ->withoutGlobalScope(ActiveScope::class); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($currentTenant) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); $query->where($tenantFK, $currentTenant->id); diff --git a/src/Filament/Resources/GroupResource/Pages/CreateGroup.php b/src/Filament/Resources/GroupResource/Pages/CreateGroup.php index fb8e769..514a436 100644 --- a/src/Filament/Resources/GroupResource/Pages/CreateGroup.php +++ b/src/Filament/Resources/GroupResource/Pages/CreateGroup.php @@ -3,6 +3,7 @@ namespace Eclipse\Catalogue\Filament\Resources\GroupResource\Pages; use Eclipse\Catalogue\Filament\Resources\GroupResource; +use Filament\Facades\Filament; use Filament\Resources\Pages\CreateRecord; class CreateGroup extends CreateRecord @@ -11,7 +12,7 @@ class CreateGroup extends CreateRecord protected function mutateFormDataBeforeCreate(array $data): array { - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($currentTenant) { $data['site_id'] = $currentTenant->id; } diff --git a/src/Filament/Resources/GroupResource/Pages/EditGroup.php b/src/Filament/Resources/GroupResource/Pages/EditGroup.php index abe7938..7fb139d 100644 --- a/src/Filament/Resources/GroupResource/Pages/EditGroup.php +++ b/src/Filament/Resources/GroupResource/Pages/EditGroup.php @@ -3,7 +3,7 @@ namespace Eclipse\Catalogue\Filament\Resources\GroupResource\Pages; use Eclipse\Catalogue\Filament\Resources\GroupResource; -use Filament\Actions; +use Filament\Actions\DeleteAction; use Filament\Resources\Pages\EditRecord; class EditGroup extends EditRecord @@ -13,7 +13,7 @@ class EditGroup extends EditRecord protected function getHeaderActions(): array { return [ - Actions\DeleteAction::make(), + DeleteAction::make(), ]; } } diff --git a/src/Filament/Resources/GroupResource/Pages/ListGroups.php b/src/Filament/Resources/GroupResource/Pages/ListGroups.php index 1aaeb8d..9f1991d 100644 --- a/src/Filament/Resources/GroupResource/Pages/ListGroups.php +++ b/src/Filament/Resources/GroupResource/Pages/ListGroups.php @@ -3,7 +3,7 @@ namespace Eclipse\Catalogue\Filament\Resources\GroupResource\Pages; use Eclipse\Catalogue\Filament\Resources\GroupResource; -use Filament\Actions; +use Filament\Actions\CreateAction; use Filament\Resources\Pages\ListRecords; class ListGroups extends ListRecords @@ -13,7 +13,7 @@ class ListGroups extends ListRecords protected function getHeaderActions(): array { return [ - Actions\CreateAction::make(), + CreateAction::make(), ]; } } diff --git a/src/Filament/Resources/GroupResource/RelationManagers/ProductsRelationManager.php b/src/Filament/Resources/GroupResource/RelationManagers/ProductsRelationManager.php index 7ce11ad..2d24358 100644 --- a/src/Filament/Resources/GroupResource/RelationManagers/ProductsRelationManager.php +++ b/src/Filament/Resources/GroupResource/RelationManagers/ProductsRelationManager.php @@ -3,9 +3,16 @@ namespace Eclipse\Catalogue\Filament\Resources\GroupResource\RelationManagers; use Eclipse\Catalogue\Filament\Resources\ProductResource; -use Filament\Forms; +use Eclipse\Catalogue\Models\Product; +use Filament\Actions\Action; +use Filament\Actions\BulkAction; +use Filament\Actions\BulkActionGroup; +use Filament\Facades\Filament; +use Filament\Forms\Components\Placeholder; +use Filament\Forms\Components\Radio; +use Filament\Forms\Components\Select; +use Filament\Notifications\Notification; use Filament\Resources\RelationManagers\RelationManager; -use Filament\Tables; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; @@ -29,7 +36,7 @@ public function table(Table $table): Table ->defaultSort('pim_group_has_product.sort') ->reorderable('pim_group_has_product.sort') ->reorderRecordsTriggerAction( - fn (Tables\Actions\Action $action, bool $isReordering) => $action + fn (Action $action, bool $isReordering) => $action ->button() ->label($isReordering ? 'Disable reordering' : 'Enable reordering') ->icon($isReordering ? 'heroicon-o-x-mark' : 'heroicon-o-arrows-up-down') @@ -37,21 +44,21 @@ public function table(Table $table): Table ) ->paginated(false) ->headerActions([ - Tables\Actions\Action::make('add_product') + Action::make('add_product') ->label('Add product') ->icon('heroicon-o-plus') ->modalHeading('Add Product to Group') ->modalSubmitActionLabel('Add Product') ->modalCancelActionLabel('Cancel') - ->form([ - \Filament\Forms\Components\Select::make('product_id') + ->schema([ + Select::make('product_id') ->label('Select product') ->options(function () { $group = $this->getOwnerRecord(); $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); - $query = \Eclipse\Catalogue\Models\Product::query(); + $query = Product::query(); if ($currentTenant) { $query->whereHas('productData', function ($q) use ($tenantFK, $currentTenant) { @@ -70,38 +77,38 @@ public function table(Table $table): Table ]) ->action(function (array $data) { $group = $this->getOwnerRecord(); - $product = \Eclipse\Catalogue\Models\Product::find($data['product_id']); + $product = Product::find($data['product_id']); if ($product && ! $group->hasProduct($product)) { $group->addProduct($product); - \Filament\Notifications\Notification::make() + Notification::make() ->title('Product added to group') ->success() ->send(); } }), ]) - ->actions([ - Tables\Actions\Action::make('edit_product') + ->recordActions([ + Action::make('edit_product') ->label('Edit') ->icon('heroicon-o-pencil') ->url(fn ($record): string => ProductResource::getUrl('edit', ['record' => $record->id])) ->openUrlInNewTab(), - Tables\Actions\Action::make('move_product') + Action::make('move_product') ->label('Reorder') ->icon('heroicon-o-arrows-up-down') ->modalHeading(fn ($record) => 'Reorder: '.$record->name) ->modalSubmitActionLabel('Move Product') ->modalCancelActionLabel('Cancel') - ->form(function ($record, $livewire) { + ->schema(function ($record, $livewire) { return [ - Forms\Components\Placeholder::make('moving_info') + Placeholder::make('moving_info') ->label('You are moving') ->content($record->name), - Forms\Components\Select::make('reference_id') + Select::make('reference_id') ->label('Place relative to') ->options( $livewire->getOwnerRecord() @@ -113,7 +120,7 @@ public function table(Table $table): Table ->reactive() ->required(), - Forms\Components\Radio::make('position') + Radio::make('position') ->label('Position') ->options([ 'before' => 'Before selected product', @@ -123,7 +130,7 @@ public function table(Table $table): Table ->inline() ->reactive(), - Forms\Components\Placeholder::make('preview') + Placeholder::make('preview') ->label('Result') ->content(function (callable $get, $livewire) use ($record) { $refId = $get('reference_id'); @@ -181,7 +188,7 @@ public function table(Table $table): Table $group->updateProductSort($record, $newSort); }), - Tables\Actions\Action::make('remove_product') + Action::make('remove_product') ->label('Remove') ->icon('heroicon-o-x-mark') ->color('danger') @@ -193,15 +200,15 @@ public function table(Table $table): Table $group = $this->getOwnerRecord(); $group->removeProduct($record); - \Filament\Notifications\Notification::make() + Notification::make() ->title('Product removed from group') ->success() ->send(); }), ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ - Tables\Actions\BulkAction::make('remove_products') + ->toolbarActions([ + BulkActionGroup::make([ + BulkAction::make('remove_products') ->label('Remove from Group') ->icon('heroicon-o-x-mark') ->color('danger') @@ -220,7 +227,7 @@ public function table(Table $table): Table } } - \Filament\Notifications\Notification::make() + Notification::make() ->title("Removed {$removedCount} products from group") ->success() ->send(); diff --git a/src/Filament/Resources/MeasureUnitResource.php b/src/Filament/Resources/MeasureUnitResource.php index c55150e..2f9d3d8 100644 --- a/src/Filament/Resources/MeasureUnitResource.php +++ b/src/Filament/Resources/MeasureUnitResource.php @@ -3,17 +3,19 @@ namespace Eclipse\Catalogue\Filament\Resources; use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; -use Eclipse\Catalogue\Filament\Resources\MeasureUnitResource\Pages; +use Eclipse\Catalogue\Filament\Resources\MeasureUnitResource\Pages\CreateMeasureUnit; +use Eclipse\Catalogue\Filament\Resources\MeasureUnitResource\Pages\EditMeasureUnit; +use Eclipse\Catalogue\Filament\Resources\MeasureUnitResource\Pages\ListMeasureUnits; use Eclipse\Catalogue\Models\MeasureUnit; +use Filament\Actions\DeleteAction; +use Filament\Actions\EditAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\RestoreAction; use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; -use Filament\Forms\Form; use Filament\Resources\Resource; -use Filament\Tables\Actions\DeleteAction; -use Filament\Tables\Actions\EditAction; -use Filament\Tables\Actions\ForceDeleteAction; -use Filament\Tables\Actions\RestoreAction; +use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\TrashedFilter; @@ -27,9 +29,9 @@ class MeasureUnitResource extends Resource implements HasShieldPermissions protected static ?string $slug = 'measure-units'; - protected static ?string $navigationIcon = 'heroicon-o-scale'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-scale'; - protected static ?string $navigationGroup = 'Catalogue'; + protected static string|\UnitEnum|null $navigationGroup = 'Catalogue'; protected static ?string $recordTitleAttribute = 'name'; @@ -43,10 +45,10 @@ public static function getPluralModelLabel(): string return __('eclipse-catalogue::measure-unit.plural'); } - 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-catalogue::measure-unit.fields.name')) ->required() @@ -96,7 +98,7 @@ public static function table(Table $table): Table ->filters([ TrashedFilter::make(), ]) - ->actions([ + ->recordActions([ EditAction::make(), DeleteAction::make(), RestoreAction::make(), @@ -107,9 +109,9 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => Pages\ListMeasureUnits::route('/'), - 'create' => Pages\CreateMeasureUnit::route('/create'), - 'edit' => Pages\EditMeasureUnit::route('/{record}/edit'), + 'index' => ListMeasureUnits::route('/'), + 'create' => CreateMeasureUnit::route('/create'), + 'edit' => EditMeasureUnit::route('/{record}/edit'), ]; } diff --git a/src/Filament/Resources/PriceListResource.php b/src/Filament/Resources/PriceListResource.php index aa77e5c..b1a7335 100644 --- a/src/Filament/Resources/PriceListResource.php +++ b/src/Filament/Resources/PriceListResource.php @@ -3,14 +3,16 @@ namespace Eclipse\Catalogue\Filament\Resources; use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; -use Eclipse\Catalogue\Filament\Resources\PriceListResource\Pages; +use Eclipse\Catalogue\Filament\Resources\PriceListResource\Pages\CreatePriceList; +use Eclipse\Catalogue\Filament\Resources\PriceListResource\Pages\EditPriceList; +use Eclipse\Catalogue\Filament\Resources\PriceListResource\Pages\ListPriceLists; use Eclipse\Catalogue\Models\PriceList; +use Filament\Actions\ActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\EditAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\RestoreAction; use Filament\Resources\Resource; -use Filament\Tables\Actions\ActionGroup; -use Filament\Tables\Actions\DeleteAction; -use Filament\Tables\Actions\EditAction; -use Filament\Tables\Actions\ForceDeleteAction; -use Filament\Tables\Actions\RestoreAction; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\TrashedFilter; @@ -24,9 +26,9 @@ class PriceListResource extends Resource implements HasShieldPermissions protected static ?string $slug = 'price-lists'; - protected static ?string $navigationIcon = 'heroicon-o-currency-dollar'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-currency-dollar'; - protected static ?string $navigationGroup = 'Catalogue'; + protected static string|\UnitEnum|null $navigationGroup = 'Catalogue'; protected static ?string $recordTitleAttribute = 'name'; @@ -94,7 +96,7 @@ public static function table(Table $table): Table ->filters([ TrashedFilter::make(), ]) - ->actions([ + ->recordActions([ ActionGroup::make([ EditAction::make(), DeleteAction::make(), @@ -107,9 +109,9 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => Pages\ListPriceLists::route('/'), - 'create' => Pages\CreatePriceList::route('/create'), - 'edit' => Pages\EditPriceList::route('/{record}/edit'), + 'index' => ListPriceLists::route('/'), + 'create' => CreatePriceList::route('/create'), + 'edit' => EditPriceList::route('/{record}/edit'), ]; } diff --git a/src/Filament/Resources/PriceListResource/Pages/CreatePriceList.php b/src/Filament/Resources/PriceListResource/Pages/CreatePriceList.php index dcf837f..bdafc17 100644 --- a/src/Filament/Resources/PriceListResource/Pages/CreatePriceList.php +++ b/src/Filament/Resources/PriceListResource/Pages/CreatePriceList.php @@ -7,8 +7,8 @@ use Eclipse\Catalogue\Traits\HandlesTenantData; use Eclipse\Catalogue\Traits\HasPriceListForm; use Eclipse\Catalogue\Traits\HasTenantFields; -use Filament\Forms\Form; use Filament\Resources\Pages\CreateRecord; +use Filament\Schemas\Schema; use Illuminate\Database\Eloquent\Model; class CreatePriceList extends CreateRecord @@ -27,9 +27,9 @@ protected function getFormMutuallyExclusiveFlagSets(): array protected static string $resource = PriceListResource::class; - public function form(Form $form): Form + public function form(Schema $schema): Schema { - return $form->schema($this->buildPriceListFormSchema()); + return $schema->components($this->buildPriceListFormSchema()); } protected function handleRecordCreation(array $data): Model diff --git a/src/Filament/Resources/PriceListResource/Pages/EditPriceList.php b/src/Filament/Resources/PriceListResource/Pages/EditPriceList.php index 4cd72a4..d7641d7 100644 --- a/src/Filament/Resources/PriceListResource/Pages/EditPriceList.php +++ b/src/Filament/Resources/PriceListResource/Pages/EditPriceList.php @@ -9,8 +9,9 @@ use Filament\Actions\DeleteAction; use Filament\Actions\ForceDeleteAction; use Filament\Actions\RestoreAction; -use Filament\Forms\Form; +use Filament\Facades\Filament; use Filament\Resources\Pages\EditRecord; +use Filament\Schemas\Schema; use Illuminate\Database\Eloquent\Model; class EditPriceList extends EditRecord @@ -38,9 +39,9 @@ protected function getHeaderActions(): array ]; } - public function form(Form $form): Form + public function form(Schema $schema): Schema { - return $form->schema($this->buildPriceListFormSchema()); + return $schema->components($this->buildPriceListFormSchema()); } protected function mutateFormDataBeforeFill(array $data): array @@ -76,7 +77,7 @@ protected function mutateFormDataBeforeFill(array $data): array $data['tenant_data'] = $tenantData; // Set the selected tenant to current tenant so the form shows properly - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $data['selected_tenant'] = $currentTenant?->id; return $data; diff --git a/src/Filament/Resources/ProductResource.php b/src/Filament/Resources/ProductResource.php index e2be821..41c9b1b 100644 --- a/src/Filament/Resources/ProductResource.php +++ b/src/Filament/Resources/ProductResource.php @@ -6,7 +6,10 @@ use Eclipse\Catalogue\Enums\PropertyInputType; use Eclipse\Catalogue\Filament\Filters\CustomPropertyConstraint; use Eclipse\Catalogue\Filament\Forms\Components\ImageManager; -use Eclipse\Catalogue\Filament\Resources\ProductResource\Pages; +use Eclipse\Catalogue\Filament\Resources\ProductResource\Pages\CreateProduct; +use Eclipse\Catalogue\Filament\Resources\ProductResource\Pages\EditProduct; +use Eclipse\Catalogue\Filament\Resources\ProductResource\Pages\ListProducts; +use Eclipse\Catalogue\Filament\Resources\ProductResource\Pages\ViewProduct; use Eclipse\Catalogue\Filament\Tables\Actions\BulkUpdateProductsAction; use Eclipse\Catalogue\Forms\Components\GenericTenantFieldsComponent; use Eclipse\Catalogue\Forms\Components\InlineTranslatableField; @@ -14,34 +17,40 @@ use Eclipse\Catalogue\Models\Group; use Eclipse\Catalogue\Models\Product; use Eclipse\Catalogue\Models\ProductStatus; +use Eclipse\Catalogue\Models\ProductType; use Eclipse\Catalogue\Models\Property; +use Eclipse\Catalogue\Support\LabelType; use Eclipse\Catalogue\Traits\HandlesTenantData; use Eclipse\Catalogue\Traits\HasTenantFields; use Eclipse\World\Models\Country; 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\Facades\Filament; use Filament\Forms\Components\CheckboxList; +use Filament\Forms\Components\DatePicker; +use Filament\Forms\Components\DateTimePicker; +use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Radio; use Filament\Forms\Components\RichEditor; -use Filament\Forms\Components\Section; use Filament\Forms\Components\Select; -use Filament\Forms\Components\Tabs; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; -use Filament\Forms\Components\View as ViewComponent; -use Filament\Forms\Form; -use Filament\Forms\Get; -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\Components\Section; +use Filament\Schemas\Components\Tabs; +use Filament\Schemas\Components\Tabs\Tab; +use Filament\Schemas\Components\Utilities\Get; +use Filament\Schemas\Components\View; +use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\ImageColumn; use Filament\Tables\Columns\TextColumn; @@ -53,6 +62,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletingScope; +use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; class ProductResource extends Resource implements HasShieldPermissions { @@ -62,19 +72,19 @@ class ProductResource extends Resource implements HasShieldPermissions protected static ?string $slug = 'products'; - protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-rectangle-stack'; - protected static ?string $navigationGroup = 'Catalogue'; + protected static string|\UnitEnum|null $navigationGroup = 'Catalogue'; protected static ?string $recordTitleAttribute = 'name'; - public static function form(Form $form): Form + public static function form(Schema $form): Schema { return $form - ->schema([ + ->components([ Tabs::make('Product Information') ->tabs([ - Tabs\Tab::make('General') + Tab::make('General') ->schema([ Section::make('Basic Information') ->compact() @@ -234,7 +244,7 @@ public static function form(Form $form): Form ->label(__('eclipse-catalogue::product.fields.sorting_label')) ->maxLength(255), - \Filament\Forms\Components\DateTimePicker::make("tenant_data.{$tenantId}.available_from_date") + DateTimePicker::make("tenant_data.{$tenantId}.available_from_date") ->label(__('eclipse-catalogue::product.fields.available_from_date')), ]; }, @@ -243,14 +253,14 @@ public static function form(Form $form): Form ), ]), - Tabs\Tab::make(__('eclipse-catalogue::product.price.tab')) + Tab::make(__('eclipse-catalogue::product.price.tab')) ->badge(fn (?Product $record) => $record?->prices()->count() ?? 0) ->schema([ - ViewComponent::make('eclipse-catalogue::product.prices-table') + View::make('eclipse-catalogue::product.prices-table') ->columnSpanFull(), ]), - Tabs\Tab::make('Properties') + Tab::make('Properties') ->schema([ Section::make('Product Type Selection') ->description('Select the product type to see available properties') @@ -262,7 +272,7 @@ public static function form(Form $form): Form 'name', function ($query) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($tenantFK && $currentTenant) { return $query->whereHas('productTypeData', function ($q) use ($tenantFK, $currentTenant) { @@ -497,14 +507,14 @@ function ($query) { break; case 'date': - $schema[] = \Filament\Forms\Components\DatePicker::make($fieldName) + $schema[] = DatePicker::make($fieldName) ->label($displayName) ->helperText($property->description) ->rules(['date']); break; case 'datetime': - $schema[] = \Filament\Forms\Components\DateTimePicker::make($fieldName) + $schema[] = DateTimePicker::make($fieldName) ->label($displayName) ->helperText($property->description) ->rules(['date']); @@ -522,13 +532,13 @@ function ($query) { ->getComponent(); } else { if ($property->max_values > 1) { - $schema[] = \Filament\Forms\Components\FileUpload::make($fieldName) + $schema[] = FileUpload::make($fieldName) ->label($displayName) ->multiple() ->helperText($property->description) ->rules(['array', "max:{$property->max_values}"]); } else { - $schema[] = \Filament\Forms\Components\FileUpload::make($fieldName) + $schema[] = FileUpload::make($fieldName) ->label($displayName) ->helperText($property->description) ->rules(['file']); @@ -549,7 +559,7 @@ function ($query) { ->columns(2), ]), - Tabs\Tab::make('Images') + Tab::make('Images') ->schema([ ImageManager::make('images') ->label('') @@ -611,7 +621,7 @@ public static function table(Table $table): Table ->badge() ->getStateUsing(function (Product $record) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $status = null; @@ -632,7 +642,7 @@ public static function table(Table $table): Table }) ->color(function (Product $record) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $status = null; if ($record->relationLoaded('productData')) { @@ -648,7 +658,7 @@ public static function table(Table $table): Table }) ->extraAttributes(function (Product $record) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $status = null; if ($record->relationLoaded('productData')) { @@ -660,7 +670,7 @@ public static function table(Table $table): Table } } - return $status ? ['class' => \Eclipse\Catalogue\Support\LabelType::badgeClass($status->label_type)] : []; + return $status ? ['class' => LabelType::badgeClass($status->label_type)] : []; }) ->searchable(false) ->sortable(false), @@ -686,7 +696,7 @@ public static function table(Table $table): Table ->limit(3) ->toggleable() ->getStateUsing(function (Product $record) { - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); if ($currentTenant) { @@ -758,7 +768,7 @@ public static function table(Table $table): Table ->options(function () { $query = ProductStatus::query(); $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($tenantFK && $currentTenant) { $query->where($tenantFK, $currentTenant->id); } @@ -775,7 +785,7 @@ public static function table(Table $table): Table return; } $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $query->whereHas('productData', function ($q) use ($selected, $tenantFK, $currentTenant) { if ($tenantFK && $currentTenant) { $q->where($tenantFK, $currentTenant->id); @@ -793,7 +803,7 @@ public static function table(Table $table): Table return; } $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $query->whereHas('productData', function ($q) use ($selected, $tenantFK, $currentTenant) { if ($tenantFK && $currentTenant) { $q->where($tenantFK, $currentTenant->id); @@ -806,9 +816,9 @@ public static function table(Table $table): Table ->multiple() ->options(function () { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); - $query = \Eclipse\Catalogue\Models\ProductType::query(); + $query = ProductType::query(); if ($tenantFK && $currentTenant) { $query->whereHas('productTypeData', function ($q) use ($tenantFK, $currentTenant) { @@ -853,7 +863,7 @@ public static function table(Table $table): Table ->label('Groups') ->multiple() ->relationship('groups', 'name', function ($query) { - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); if ($currentTenant) { return $query->where($tenantFK, $currentTenant->id); @@ -866,7 +876,7 @@ public static function table(Table $table): Table ->queries( true: function (Builder $query) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); return $query->whereHas('productData', function ($q) use ($tenantFK, $currentTenant) { $q->where('is_active', true); @@ -877,7 +887,7 @@ public static function table(Table $table): Table }, false: function (Builder $query) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); return $query->whereHas('productData', function ($q) use ($tenantFK, $currentTenant) { $q->where('is_active', false); @@ -894,7 +904,7 @@ public static function table(Table $table): Table ...static::getCustomPropertyConstraints(), ]), ]) - ->actions([ + ->recordActions([ ActionGroup::make([ EditAction::make(), DeleteAction::make(), @@ -907,7 +917,7 @@ public static function table(Table $table): Table ->color('gray') ->button(), ]) - ->bulkActions([ + ->toolbarActions([ BulkActionGroup::make([ BulkUpdateProductsAction::make(), DeleteBulkAction::make(), @@ -920,10 +930,10 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => Pages\ListProducts::route('/'), - 'create' => Pages\CreateProduct::route('/create'), - 'view' => Pages\ViewProduct::route('/{record}'), - 'edit' => Pages\EditProduct::route('/{record}/edit'), + 'index' => ListProducts::route('/'), + 'create' => CreateProduct::route('/create'), + 'view' => ViewProduct::route('/{record}'), + 'edit' => EditProduct::route('/{record}/edit'), ]; } @@ -935,7 +945,7 @@ public static function getEloquentQuery(): Builder ]); $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($tenantFK && $currentTenant) { $query->with(['productData' => function ($q) use ($tenantFK, $currentTenant) { diff --git a/src/Filament/Resources/ProductResource/Pages/CreateProduct.php b/src/Filament/Resources/ProductResource/Pages/CreateProduct.php index 0d00f8e..ade8f0b 100644 --- a/src/Filament/Resources/ProductResource/Pages/CreateProduct.php +++ b/src/Filament/Resources/ProductResource/Pages/CreateProduct.php @@ -4,26 +4,30 @@ use Eclipse\Catalogue\Filament\Resources\Concerns\HandlesImageUploads; use Eclipse\Catalogue\Filament\Resources\ProductResource; +use Eclipse\Catalogue\Models\Group; use Eclipse\Catalogue\Models\Product; +use Eclipse\Catalogue\Models\ProductStatus; +use Eclipse\Catalogue\Models\Property; use Eclipse\Catalogue\Traits\HandlesTenantData; use Eclipse\Catalogue\Traits\HasTenantFields; -use Filament\Actions; -use Filament\Forms\Form; use Filament\Resources\Pages\CreateRecord; +use Filament\Schemas\Schema; use Illuminate\Database\Eloquent\Model; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\CreateRecord\Concerns\Translatable; class CreateProduct extends CreateRecord { - use CreateRecord\Concerns\Translatable; use HandlesImageUploads; use HandlesTenantData, HasTenantFields; + use Translatable; protected static string $resource = ProductResource::class; protected function getHeaderActions(): array { return [ - Actions\LocaleSwitcher::make(), + LocaleSwitcher::make(), ]; } @@ -48,9 +52,9 @@ protected function getFormMutuallyExclusiveFlagSets(): array return []; } - public function form(Form $form): Form + public function form(Schema $schema): Schema { - return $form; + return $schema; } protected function handleRecordCreation(array $data): Model @@ -60,7 +64,7 @@ protected function handleRecordCreation(array $data): Model $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); if (! $tenantFK) { if (empty($tenantData['product_status_id'] ?? null)) { - $default = \Eclipse\Catalogue\Models\ProductStatus::query()->where('is_default', true)->orderBy('priority')->first(); + $default = ProductStatus::query()->where('is_default', true)->orderBy('priority')->first(); if ($default) { $tenantData['product_status_id'] = $default->id; } @@ -68,7 +72,7 @@ protected function handleRecordCreation(array $data): Model } else { foreach ($tenantData as $siteId => &$td) { if (empty($td['product_status_id'] ?? null)) { - $default = \Eclipse\Catalogue\Models\ProductStatus::query()->where($tenantFK, $siteId)->where('is_default', true)->orderBy('priority')->first(); + $default = ProductStatus::query()->where($tenantFK, $siteId)->where('is_default', true)->orderBy('priority')->first(); if ($default) { $td['product_status_id'] = $default->id; } @@ -124,7 +128,7 @@ protected function afterCreate(): void } foreach ($customPropertyData as $propertyId => $value) { - $property = \Eclipse\Catalogue\Models\Property::find($propertyId); + $property = Property::find($propertyId); if ($property && $property->isCustomType()) { if ($property->supportsMultilang() && is_array($value)) { $filteredValue = array_filter($value, fn ($v) => $v !== null && $v !== ''); @@ -143,7 +147,7 @@ protected function afterCreate(): void foreach ($tenantData as $tenantId => $data) { $groupIds = array_filter(array_map('intval', (array) ($data['groups'] ?? []))); foreach ($groupIds as $groupId) { - $group = \Eclipse\Catalogue\Models\Group::find($groupId); + $group = Group::find($groupId); $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); if ($group && (int) $group->getAttribute($tenantFK) === (int) $tenantId) { $group->addProduct($product); @@ -164,7 +168,7 @@ protected function afterCreate(): void } foreach ($flatGroupIds as $groupId) { - if ($group = \Eclipse\Catalogue\Models\Group::find($groupId)) { + if ($group = Group::find($groupId)) { $group->addProduct($product); } } diff --git a/src/Filament/Resources/ProductResource/Pages/EditProduct.php b/src/Filament/Resources/ProductResource/Pages/EditProduct.php index b634c79..c883989 100644 --- a/src/Filament/Resources/ProductResource/Pages/EditProduct.php +++ b/src/Filament/Resources/ProductResource/Pages/EditProduct.php @@ -3,13 +3,22 @@ namespace Eclipse\Catalogue\Filament\Resources\ProductResource\Pages; use Eclipse\Catalogue\Filament\Resources\ProductResource; +use Eclipse\Catalogue\Models\Group; use Eclipse\Catalogue\Models\Property; +use Eclipse\Catalogue\Models\PropertyValue; use Eclipse\Catalogue\Traits\HandlesTenantData; use Eclipse\Catalogue\Traits\HasTenantFields; -use Filament\Actions; -use Filament\Forms\Form; +use Eclipse\Core\Models\Locale; +use Filament\Actions\DeleteAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\RestoreAction; +use Filament\Actions\ViewAction; +use Filament\Facades\Filament; use Filament\Resources\Pages\EditRecord; +use Filament\Schemas\Schema; use Illuminate\Database\Eloquent\Model; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\EditRecord\Concerns\Translatable; use Nben\FilamentRecordNav\Actions\NextRecordAction; use Nben\FilamentRecordNav\Actions\PreviousRecordAction; use Nben\FilamentRecordNav\Concerns\WithRecordNavigation; @@ -17,8 +26,8 @@ class EditProduct extends EditRecord { - use EditRecord\Concerns\Translatable; use HandlesTenantData, HasTenantFields; + use Translatable; use WithRecordNavigation; protected static string $resource = ProductResource::class; @@ -28,11 +37,11 @@ protected function getHeaderActions(): array return [ PreviousRecordAction::make(), NextRecordAction::make(), - Actions\LocaleSwitcher::make(), - Actions\ViewAction::make(), - Actions\DeleteAction::make(), - Actions\ForceDeleteAction::make(), - Actions\RestoreAction::make(), + LocaleSwitcher::make(), + ViewAction::make(), + DeleteAction::make(), + ForceDeleteAction::make(), + RestoreAction::make(), ]; } @@ -116,7 +125,7 @@ protected function mutateFormDataBeforeFill(array $data): array } $data['tenant_data'] = $tenantData; - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $data['selected_tenant'] = $currentTenant?->id; return $data; @@ -146,7 +155,7 @@ protected function afterSave(): void } foreach ($propertyData as $propertyId => $values) { - $idsToDetach = \Eclipse\Catalogue\Models\PropertyValue::query() + $idsToDetach = PropertyValue::query() ->where('property_id', $propertyId) ->pluck('id') ->all(); @@ -208,9 +217,9 @@ protected function getFormMutuallyExclusiveFlagSets(): array return []; } - public function form(Form $form): Form + public function form(Schema $schema): Schema { - return $form; + return $schema; } protected function getFormActions(): array @@ -252,14 +261,14 @@ protected function handleRecordUpdate(Model $record, array $data): Model $toDetach = array_values(array_diff($currentGroupIds, $desiredGroupIds)); foreach ($toAttach as $groupId) { - $group = \Eclipse\Catalogue\Models\Group::find($groupId); + $group = Group::find($groupId); if ($group) { $group->addProduct($record); } } foreach ($toDetach as $groupId) { - $group = \Eclipse\Catalogue\Models\Group::find($groupId); + $group = Group::find($groupId); if ($group) { $group->removeProduct($record); } @@ -281,8 +290,8 @@ protected function getRecordUrl(Model $record): string */ protected function getAvailableLocales(): array { - if (class_exists(\Eclipse\Core\Models\Locale::class)) { - return \Eclipse\Core\Models\Locale::getAvailableLocales()->pluck('id')->toArray(); + if (class_exists(Locale::class)) { + return Locale::getAvailableLocales()->pluck('id')->toArray(); } return ['en']; diff --git a/src/Filament/Resources/ProductResource/Pages/ListProducts.php b/src/Filament/Resources/ProductResource/Pages/ListProducts.php index 2b41b61..a0ffca5 100644 --- a/src/Filament/Resources/ProductResource/Pages/ListProducts.php +++ b/src/Filament/Resources/ProductResource/Pages/ListProducts.php @@ -4,11 +4,12 @@ use Eclipse\Catalogue\Filament\Resources\ProductResource; use Eclipse\Common\Foundation\Pages\HasScoutSearch; -use Filament\Actions; +use Filament\Actions\CreateAction; use Filament\Resources\Pages\ListRecords; -use Filament\Resources\Pages\ListRecords\Concerns\Translatable; -use Filament\Support\Enums\MaxWidth; +use Filament\Support\Enums\Width; use Illuminate\Contracts\View\View; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\ListRecords\Concerns\Translatable; class ListProducts extends ListRecords { @@ -16,13 +17,13 @@ class ListProducts extends ListRecords protected static string $resource = ProductResource::class; - protected ?string $maxContentWidth = MaxWidth::Full->value; + protected Width|string|null $maxContentWidth = Width::Full->value; protected function getHeaderActions(): array { return [ - Actions\LocaleSwitcher::make(), - Actions\CreateAction::make(), + LocaleSwitcher::make(), + CreateAction::make(), ]; } diff --git a/src/Filament/Resources/ProductResource/Pages/ViewProduct.php b/src/Filament/Resources/ProductResource/Pages/ViewProduct.php index 516fa47..f161c17 100644 --- a/src/Filament/Resources/ProductResource/Pages/ViewProduct.php +++ b/src/Filament/Resources/ProductResource/Pages/ViewProduct.php @@ -3,15 +3,17 @@ namespace Eclipse\Catalogue\Filament\Resources\ProductResource\Pages; use Eclipse\Catalogue\Filament\Resources\ProductResource; -use Filament\Actions; +use Filament\Actions\EditAction; use Filament\Resources\Pages\ViewRecord; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\ViewRecord\Concerns\Translatable; use Nben\FilamentRecordNav\Actions\NextRecordAction; use Nben\FilamentRecordNav\Actions\PreviousRecordAction; use Nben\FilamentRecordNav\Concerns\WithRecordNavigation; class ViewProduct extends ViewRecord { - use ViewRecord\Concerns\Translatable; + use Translatable; use WithRecordNavigation; protected static string $resource = ProductResource::class; @@ -21,8 +23,8 @@ protected function getHeaderActions(): array return [ PreviousRecordAction::make(), NextRecordAction::make(), - Actions\LocaleSwitcher::make(), - Actions\EditAction::make(), + LocaleSwitcher::make(), + EditAction::make(), ]; } } diff --git a/src/Filament/Resources/ProductResource/RelationManagers/PricesRelationManager.php b/src/Filament/Resources/ProductResource/RelationManagers/PricesRelationManager.php index c02a0ac..6c7aeb3 100644 --- a/src/Filament/Resources/ProductResource/RelationManagers/PricesRelationManager.php +++ b/src/Filament/Resources/ProductResource/RelationManagers/PricesRelationManager.php @@ -2,14 +2,22 @@ namespace Eclipse\Catalogue\Filament\Resources\ProductResource\RelationManagers; +use Carbon\Carbon; use Eclipse\Catalogue\Models\PriceList; -use Filament\Forms; +use Eclipse\Catalogue\Models\Product\Price; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\CreateAction; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; use Filament\Resources\RelationManagers\RelationManager; -use Filament\Tables; +use Filament\Schemas\Components\Utilities\Get; +use Filament\Schemas\Components\Utilities\Set; +use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; @@ -20,9 +28,9 @@ class PricesRelationManager extends RelationManager protected static ?string $recordTitleAttribute = 'price'; - public function form(Forms\Form $form): Forms\Form + public function form(Schema $schema): Schema { - return $form->schema([ + return $schema->components([ Select::make('price_list_id') ->label(__('eclipse-catalogue::product.price.fields.price_list')) ->relationship('priceList', 'name') @@ -30,7 +38,7 @@ public function form(Forms\Form $form): Forms\Form ->preload() ->searchable() ->live() - ->afterStateUpdated(function ($state, Forms\Set $set) { + ->afterStateUpdated(function ($state, Set $set) { if (! $state) { return; } @@ -51,7 +59,7 @@ public function form(Forms\Form $form): Forms\Form ->native(false) ->default(fn () => now()) ->required() - ->rule(function (Forms\Get $get) { + ->rule(function (Get $get) { return function (string $attribute, $value, $fail) use ($get) { if (empty($value)) { return; @@ -63,10 +71,10 @@ public function form(Forms\Form $form): Forms\Form return; } - $query = \Eclipse\Catalogue\Models\Product\Price::query() + $query = Price::query() ->where('product_id', $productId) ->where('price_list_id', $priceListId) - ->whereDate('valid_from', \Carbon\Carbon::parse($value)->toDateString()); + ->whereDate('valid_from', Carbon::parse($value)->toDateString()); $current = method_exists($this, 'getMountedTableActionRecord') ? $this->getMountedTableActionRecord() : null; if ($current) { @@ -125,18 +133,18 @@ public function table(Table $table): Table ->paginated(false) ->filters([]) ->headerActions([ - Tables\Actions\CreateAction::make() + CreateAction::make() ->label(__('eclipse-catalogue::product.price.actions.add')), ]) - ->actions([ - Tables\Actions\EditAction::make() + ->recordActions([ + EditAction::make() ->label(__('filament-actions::edit.single.label')), - Tables\Actions\DeleteAction::make() + DeleteAction::make() ->label(__('filament-actions::delete.single.label')), ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ - Tables\Actions\DeleteBulkAction::make(), + ->toolbarActions([ + BulkActionGroup::make([ + DeleteBulkAction::make(), ]), ]); } diff --git a/src/Filament/Resources/ProductStatusResource.php b/src/Filament/Resources/ProductStatusResource.php index d96ac97..8122cfe 100644 --- a/src/Filament/Resources/ProductStatusResource.php +++ b/src/Filament/Resources/ProductStatusResource.php @@ -3,17 +3,23 @@ namespace Eclipse\Catalogue\Filament\Resources; use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; -use Eclipse\Catalogue\Filament\Resources\ProductStatusResource\Pages; +use Eclipse\Catalogue\Enums\StructuredData\ItemAvailability; +use Eclipse\Catalogue\Filament\Resources\ProductStatusResource\Pages\CreateProductStatus; +use Eclipse\Catalogue\Filament\Resources\ProductStatusResource\Pages\EditProductStatus; +use Eclipse\Catalogue\Filament\Resources\ProductStatusResource\Pages\ListProductStatuses; use Eclipse\Catalogue\Models\ProductStatus; use Eclipse\Catalogue\Support\LabelType; -use Filament\Forms\Components\Grid; -use Filament\Forms\Components\Section; +use Filament\Actions\DeleteAction; +use Filament\Actions\EditAction; +use Filament\Facades\Filament; use Filament\Forms\Components\Select; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; -use Filament\Forms\Form; -use Filament\Resources\Concerns\Translatable; +use Filament\Forms\Components\Toggle; use Filament\Resources\Resource; +use Filament\Schemas\Components\Grid; +use Filament\Schemas\Components\Section; +use Filament\Schemas\Schema; use Filament\Tables\Columns\BadgeColumn; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; @@ -21,6 +27,7 @@ use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\HtmlString; +use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; class ProductStatusResource extends Resource implements HasShieldPermissions { @@ -28,9 +35,9 @@ class ProductStatusResource extends Resource implements HasShieldPermissions protected static ?string $model = ProductStatus::class; - protected static ?string $navigationIcon = 'heroicon-o-check-circle'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-check-circle'; - protected static ?string $navigationGroup = 'Catalogue'; + protected static string|\UnitEnum|null $navigationGroup = 'Catalogue'; protected static ?string $slug = 'product-statuses'; @@ -51,9 +58,9 @@ public static function getPluralModelLabel(): string return __('eclipse-catalogue::product-status.plural'); } - public static function form(Form $form): Form + public static function form(Schema $schema): Schema { - return $form->schema([ + return $schema->components([ Section::make(__('eclipse-catalogue::product-status.singular')) ->schema([ TextInput::make('title')->label(__('eclipse-catalogue::product-status.fields.title')) @@ -71,7 +78,7 @@ public static function form(Form $form): Form modifyRuleUsing: function ($rule, $livewire) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); if ($tenantFK) { - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($currentTenant) { $rule->where($tenantFK, $currentTenant->id); } @@ -99,26 +106,26 @@ public static function form(Form $form): Form ])->columns(1), Section::make(__('eclipse-catalogue::product-status.sections.visibility_rules'))->schema([ Grid::make(3)->schema([ - \Filament\Forms\Components\Toggle::make('shown_in_browse')->label(__('eclipse-catalogue::product-status.fields.shown_in_browse')) + Toggle::make('shown_in_browse')->label(__('eclipse-catalogue::product-status.fields.shown_in_browse')) ->helperText(__('eclipse-catalogue::product-status.help_text.shown_in_browse')) ->default(true), - \Filament\Forms\Components\Toggle::make('allow_price_display')->label(__('eclipse-catalogue::product-status.fields.allow_price_display')) + Toggle::make('allow_price_display')->label(__('eclipse-catalogue::product-status.fields.allow_price_display')) ->helperText(__('eclipse-catalogue::product-status.help_text.allow_price_display')) ->default(true) ->live(), - \Filament\Forms\Components\Toggle::make('allow_sale')->label(__('eclipse-catalogue::product-status.fields.allow_sale')) + Toggle::make('allow_sale')->label(__('eclipse-catalogue::product-status.fields.allow_sale')) ->helperText(__('eclipse-catalogue::product-status.help_text.allow_sale')) ->default(true) ->disabled(fn ($get) => $get('allow_price_display') === false), - \Filament\Forms\Components\Toggle::make('is_default')->label(__('eclipse-catalogue::product-status.fields.is_default')) + Toggle::make('is_default')->label(__('eclipse-catalogue::product-status.fields.is_default')) ->helperText(__('eclipse-catalogue::product-status.help_text.is_default')) ->default(false), - \Filament\Forms\Components\Toggle::make('skip_stock_qty_check')->label(__('eclipse-catalogue::product-status.fields.skip_stock_qty_check')) + Toggle::make('skip_stock_qty_check')->label(__('eclipse-catalogue::product-status.fields.skip_stock_qty_check')) ->helperText(__('eclipse-catalogue::product-status.help_text.skip_stock_qty_check')) ->default(false), Select::make('sd_item_availability')->label(__('eclipse-catalogue::product-status.fields.sd_item_availability')) ->helperText(new HtmlString(__('eclipse-catalogue::product-status.help_text.sd_item_availability'))) - ->options(\Eclipse\Catalogue\Enums\StructuredData\ItemAvailability::class) + ->options(ItemAvailability::class) ->searchable() ->required(), ]), @@ -141,18 +148,18 @@ public static function table(Table $table): Table TextColumn::make('priority')->label(__('eclipse-catalogue::product-status.fields.priority'))->numeric(), ])->filters([ TernaryFilter::make('shown_in_browse')->label(__('eclipse-catalogue::product-status.fields.shown_in_browse')), - ])->actions([ - \Filament\Tables\Actions\EditAction::make(), - \Filament\Tables\Actions\DeleteAction::make(), + ])->recordActions([ + EditAction::make(), + DeleteAction::make(), ]); } public static function getPages(): array { return [ - 'index' => Pages\ListProductStatuses::route('/'), - 'create' => Pages\CreateProductStatus::route('/create'), - 'edit' => Pages\EditProductStatus::route('/{record}/edit'), + 'index' => ListProductStatuses::route('/'), + 'create' => CreateProductStatus::route('/create'), + 'edit' => EditProductStatus::route('/{record}/edit'), ]; } @@ -163,7 +170,7 @@ public static function getEloquentQuery(): Builder // Filter by current tenant if tenancy is enabled $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); if ($tenantFK) { - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($currentTenant) { $query->where($tenantFK, $currentTenant->id); } diff --git a/src/Filament/Resources/ProductStatusResource/Pages/CreateProductStatus.php b/src/Filament/Resources/ProductStatusResource/Pages/CreateProductStatus.php index c949e38..6b82aa6 100644 --- a/src/Filament/Resources/ProductStatusResource/Pages/CreateProductStatus.php +++ b/src/Filament/Resources/ProductStatusResource/Pages/CreateProductStatus.php @@ -3,9 +3,11 @@ namespace Eclipse\Catalogue\Filament\Resources\ProductStatusResource\Pages; use Eclipse\Catalogue\Filament\Resources\ProductStatusResource; -use Filament\Actions; +use Eclipse\Catalogue\Models\ProductStatus; +use Filament\Facades\Filament; use Filament\Resources\Pages\CreateRecord; -use Filament\Resources\Pages\CreateRecord\Concerns\Translatable; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\CreateRecord\Concerns\Translatable; class CreateProductStatus extends CreateRecord { @@ -16,13 +18,13 @@ class CreateProductStatus extends CreateRecord protected function getHeaderActions(): array { return [ - Actions\LocaleSwitcher::make(), + LocaleSwitcher::make(), ]; } protected function mutateFormDataBeforeCreate(array $data): array { - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($currentTenant) { $data['site_id'] = $currentTenant->id; } @@ -33,7 +35,7 @@ protected function mutateFormDataBeforeCreate(array $data): array if (! empty($data['is_default'])) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $query = \Eclipse\Catalogue\Models\ProductStatus::query()->where('is_default', true); + $query = ProductStatus::query()->where('is_default', true); if ($tenantFK && isset($data[$tenantFK])) { $query->where($tenantFK, $data[$tenantFK]); } diff --git a/src/Filament/Resources/ProductStatusResource/Pages/EditProductStatus.php b/src/Filament/Resources/ProductStatusResource/Pages/EditProductStatus.php index 18aa142..4fa0267 100644 --- a/src/Filament/Resources/ProductStatusResource/Pages/EditProductStatus.php +++ b/src/Filament/Resources/ProductStatusResource/Pages/EditProductStatus.php @@ -3,9 +3,11 @@ namespace Eclipse\Catalogue\Filament\Resources\ProductStatusResource\Pages; use Eclipse\Catalogue\Filament\Resources\ProductStatusResource; -use Filament\Actions; +use Eclipse\Catalogue\Models\ProductStatus; +use Filament\Actions\DeleteAction; use Filament\Resources\Pages\EditRecord; -use Filament\Resources\Pages\EditRecord\Concerns\Translatable; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\EditRecord\Concerns\Translatable; class EditProductStatus extends EditRecord { @@ -23,7 +25,7 @@ protected function mutateFormDataBeforeSave(array $data): array // Ensure only one default per tenant/site if (! empty($data['is_default'])) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $query = \Eclipse\Catalogue\Models\ProductStatus::query()->where('is_default', true)->where('id', '!=', $this->record->id); + $query = ProductStatus::query()->where('is_default', true)->where('id', '!=', $this->record->id); if ($tenantFK) { $query->where($tenantFK, $this->record->getAttribute($tenantFK)); } @@ -36,8 +38,8 @@ protected function mutateFormDataBeforeSave(array $data): array protected function getHeaderActions(): array { return [ - Actions\LocaleSwitcher::make(), - Actions\DeleteAction::make(), + LocaleSwitcher::make(), + DeleteAction::make(), ]; } } diff --git a/src/Filament/Resources/ProductStatusResource/Pages/ListProductStatuses.php b/src/Filament/Resources/ProductStatusResource/Pages/ListProductStatuses.php index 1e92f94..c3cdeea 100644 --- a/src/Filament/Resources/ProductStatusResource/Pages/ListProductStatuses.php +++ b/src/Filament/Resources/ProductStatusResource/Pages/ListProductStatuses.php @@ -3,9 +3,10 @@ namespace Eclipse\Catalogue\Filament\Resources\ProductStatusResource\Pages; use Eclipse\Catalogue\Filament\Resources\ProductStatusResource; -use Filament\Actions; +use Filament\Actions\CreateAction; 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 ListProductStatuses extends ListRecords { @@ -16,8 +17,8 @@ class ListProductStatuses extends ListRecords protected function getHeaderActions(): array { return [ - Actions\LocaleSwitcher::make(), - Actions\CreateAction::make() + LocaleSwitcher::make(), + CreateAction::make() ->label(__('eclipse-catalogue::product-status.actions.create')), ]; } diff --git a/src/Filament/Resources/ProductTypeResource.php b/src/Filament/Resources/ProductTypeResource.php index b072689..6a7830e 100644 --- a/src/Filament/Resources/ProductTypeResource.php +++ b/src/Filament/Resources/ProductTypeResource.php @@ -3,22 +3,24 @@ namespace Eclipse\Catalogue\Filament\Resources; use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; -use Eclipse\Catalogue\Filament\Resources\ProductTypeResource\Pages; -use Eclipse\Catalogue\Filament\Resources\ProductTypeResource\RelationManagers; +use Eclipse\Catalogue\Filament\Resources\ProductTypeResource\Pages\CreateProductType; +use Eclipse\Catalogue\Filament\Resources\ProductTypeResource\Pages\EditProductType; +use Eclipse\Catalogue\Filament\Resources\ProductTypeResource\Pages\ListProductTypes; +use Eclipse\Catalogue\Filament\Resources\ProductTypeResource\RelationManagers\PropertiesRelationManager; use Eclipse\Catalogue\Models\ProductType; -use Filament\Resources\Concerns\Translatable; +use Filament\Actions\ActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\EditAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\RestoreAction; use Filament\Resources\Resource; -use Filament\Tables\Actions\ActionGroup; -use Filament\Tables\Actions\DeleteAction; -use Filament\Tables\Actions\EditAction; -use Filament\Tables\Actions\ForceDeleteAction; -use Filament\Tables\Actions\RestoreAction; use Filament\Tables\Columns\IconColumn; 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 ProductTypeResource extends Resource implements HasShieldPermissions { @@ -28,9 +30,9 @@ class ProductTypeResource extends Resource implements HasShieldPermissions protected static ?string $slug = 'product-types'; - protected static ?string $navigationIcon = 'heroicon-o-tag'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-tag'; - protected static ?string $navigationGroup = 'Catalogue'; + protected static string|\UnitEnum|null $navigationGroup = 'Catalogue'; protected static ?string $recordTitleAttribute = 'name'; @@ -84,7 +86,7 @@ public static function table(Table $table): Table ->filters([ TrashedFilter::make(), ]) - ->actions([ + ->recordActions([ ActionGroup::make([ EditAction::make(), DeleteAction::make(), @@ -97,16 +99,16 @@ public static function table(Table $table): Table public static function getRelations(): array { return [ - RelationManagers\PropertiesRelationManager::class, + PropertiesRelationManager::class, ]; } public static function getPages(): array { return [ - 'index' => Pages\ListProductTypes::route('/'), - 'create' => Pages\CreateProductType::route('/create'), - 'edit' => Pages\EditProductType::route('/{record}/edit'), + 'index' => ListProductTypes::route('/'), + 'create' => CreateProductType::route('/create'), + 'edit' => EditProductType::route('/{record}/edit'), ]; } diff --git a/src/Filament/Resources/ProductTypeResource/Pages/CreateProductType.php b/src/Filament/Resources/ProductTypeResource/Pages/CreateProductType.php index 18ac739..aee124d 100644 --- a/src/Filament/Resources/ProductTypeResource/Pages/CreateProductType.php +++ b/src/Filament/Resources/ProductTypeResource/Pages/CreateProductType.php @@ -7,11 +7,11 @@ use Eclipse\Catalogue\Traits\HandlesTenantData; use Eclipse\Catalogue\Traits\HasProductTypeForm; use Eclipse\Catalogue\Traits\HasTenantFields; -use Filament\Actions\LocaleSwitcher; -use Filament\Forms\Form; use Filament\Resources\Pages\CreateRecord; -use Filament\Resources\Pages\CreateRecord\Concerns\Translatable; +use Filament\Schemas\Schema; use Illuminate\Database\Eloquent\Model; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\CreateRecord\Concerns\Translatable; class CreateProductType extends CreateRecord { @@ -36,9 +36,9 @@ protected function getFormMutuallyExclusiveFlagSets(): array return []; } - public function form(Form $form): Form + public function form(Schema $schema): Schema { - return $form->schema($this->buildProductTypeFormSchema()); + return $schema->components($this->buildProductTypeFormSchema()); } protected function handleRecordCreation(array $data): Model diff --git a/src/Filament/Resources/ProductTypeResource/Pages/EditProductType.php b/src/Filament/Resources/ProductTypeResource/Pages/EditProductType.php index 27d8cc2..8603ce6 100644 --- a/src/Filament/Resources/ProductTypeResource/Pages/EditProductType.php +++ b/src/Filament/Resources/ProductTypeResource/Pages/EditProductType.php @@ -8,12 +8,13 @@ use Eclipse\Catalogue\Traits\HasTenantFields; use Filament\Actions\DeleteAction; use Filament\Actions\ForceDeleteAction; -use Filament\Actions\LocaleSwitcher; use Filament\Actions\RestoreAction; -use Filament\Forms\Form; +use Filament\Facades\Filament; use Filament\Resources\Pages\EditRecord; -use Filament\Resources\Pages\EditRecord\Concerns\Translatable; +use Filament\Schemas\Schema; use Illuminate\Database\Eloquent\Model; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\EditRecord\Concerns\Translatable; class EditProductType extends EditRecord { @@ -41,9 +42,9 @@ protected function getHeaderActions(): array ]; } - public function form(Form $form): Form + public function form(Schema $schema): Schema { - return $form->schema($this->buildProductTypeFormSchema()); + return $schema->components($this->buildProductTypeFormSchema()); } protected function mutateFormDataBeforeFill(array $data): array @@ -77,7 +78,7 @@ protected function mutateFormDataBeforeFill(array $data): array $data['tenant_data'] = $tenantData; // Set the selected tenant to current tenant so the form shows properly - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $data['selected_tenant'] = $currentTenant?->id; return $data; diff --git a/src/Filament/Resources/ProductTypeResource/Pages/ListProductTypes.php b/src/Filament/Resources/ProductTypeResource/Pages/ListProductTypes.php index 5151b7d..1c593ad 100644 --- a/src/Filament/Resources/ProductTypeResource/Pages/ListProductTypes.php +++ b/src/Filament/Resources/ProductTypeResource/Pages/ListProductTypes.php @@ -4,9 +4,9 @@ use Eclipse\Catalogue\Filament\Resources\ProductTypeResource; use Filament\Actions\CreateAction; -use Filament\Actions\LocaleSwitcher; -use Filament\Resources\Concerns\Translatable; use Filament\Resources\Pages\ListRecords; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; class ListProductTypes extends ListRecords { diff --git a/src/Filament/Resources/ProductTypeResource/RelationManagers/PropertiesRelationManager.php b/src/Filament/Resources/ProductTypeResource/RelationManagers/PropertiesRelationManager.php index 60c9cc5..e4ebbc7 100644 --- a/src/Filament/Resources/ProductTypeResource/RelationManagers/PropertiesRelationManager.php +++ b/src/Filament/Resources/ProductTypeResource/RelationManagers/PropertiesRelationManager.php @@ -2,11 +2,20 @@ namespace Eclipse\Catalogue\Filament\Resources\ProductTypeResource\RelationManagers; +use Eclipse\Catalogue\Filament\Resources\PropertyResource; use Eclipse\Catalogue\Models\Property; -use Filament\Forms; -use Filament\Forms\Form; +use Filament\Actions\Action; +use Filament\Actions\AttachAction; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\DetachAction; +use Filament\Actions\DetachBulkAction; +use Filament\Forms\Components\Select; +use Filament\Forms\Components\TextInput; use Filament\Resources\RelationManagers\RelationManager; -use Filament\Tables; +use Filament\Schemas\Schema; +use Filament\Tables\Columns\IconColumn; +use Filament\Tables\Columns\TextColumn; +use Filament\Tables\Filters\TernaryFilter; use Filament\Tables\Table; class PropertiesRelationManager extends RelationManager @@ -15,17 +24,17 @@ class PropertiesRelationManager extends RelationManager protected static ?string $recordTitleAttribute = 'name'; - public function form(Form $form): Form + public function form(Schema $schema): Schema { - return $form - ->schema([ - Forms\Components\Select::make('property_id') + return $schema + ->components([ + Select::make('property_id') ->label('Property') ->options(Property::where('is_active', true)->pluck('name', 'id')) ->required() ->searchable(), - Forms\Components\TextInput::make('sort') + TextInput::make('sort') ->label('Sort Order') ->numeric() ->default(0) @@ -37,43 +46,43 @@ public function table(Table $table): Table { return $table ->columns([ - Tables\Columns\TextColumn::make('name') + TextColumn::make('name') ->label('Property Name') ->searchable() ->sortable(), - Tables\Columns\TextColumn::make('code') + TextColumn::make('code') ->label('Code') ->searchable(), - Tables\Columns\IconColumn::make('is_global') + IconColumn::make('is_global') ->label('Global') ->boolean(), - Tables\Columns\TextColumn::make('max_values') + TextColumn::make('max_values') ->label('Max Values') ->formatStateUsing(fn ($state) => $state === 1 ? 'Single' : 'Multiple'), - Tables\Columns\IconColumn::make('is_filter') + IconColumn::make('is_filter') ->label('Filter') ->boolean(), - Tables\Columns\TextColumn::make('values_count') + TextColumn::make('values_count') ->label('Values') ->counts('values'), ]) ->filters([ - Tables\Filters\TernaryFilter::make('is_global') + TernaryFilter::make('is_global') ->label('Global Properties'), ]) ->headerActions([ - Tables\Actions\AttachAction::make() + AttachAction::make() ->label('Add property') ->modalHeading('Add Property') ->modalSubmitActionLabel('Add Property') ->modalCancelActionLabel('Cancel') ->extraModalFooterActions( - fn (Tables\Actions\AttachAction $action): array => [ + fn (AttachAction $action): array => [ $action->makeModalSubmitAction('submitAnother', ['another' => true]) ->label('Add Property & Add Another'), ] @@ -90,22 +99,22 @@ public function table(Table $table): Table ->preloadRecordSelect() ->recordSelectSearchColumns(['name', 'code']), ]) - ->actions([ - Tables\Actions\Action::make('edit_property') + ->recordActions([ + Action::make('edit_property') ->label('Edit Property') ->icon('heroicon-o-pencil') - ->url(fn ($record): string => \Eclipse\Catalogue\Filament\Resources\PropertyResource::getUrl('edit', ['record' => $record->id])) + ->url(fn ($record): string => PropertyResource::getUrl('edit', ['record' => $record->id])) ->openUrlInNewTab(), - Tables\Actions\DetachAction::make() + DetachAction::make() ->label('Remove') ->modalHeading(fn ($record) => 'Remove '.($record->name ?? 'property')) ->modalSubmitActionLabel('Remove') ->modalCancelActionLabel('Cancel'), ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ - Tables\Actions\DetachBulkAction::make() + ->toolbarActions([ + BulkActionGroup::make([ + DetachBulkAction::make() ->label('Remove') ->modalHeading('Remove selected') ->modalSubmitActionLabel('Remove') @@ -115,7 +124,7 @@ public function table(Table $table): Table ->defaultSort('pim_product_type_has_property.sort') ->reorderable('pim_product_type_has_property.sort') ->reorderRecordsTriggerAction( - fn (Tables\Actions\Action $action, bool $isReordering) => $action + fn (Action $action, bool $isReordering) => $action ->button() ->label($isReordering ? 'Disable reordering' : 'Enable reordering') ->icon($isReordering ? 'heroicon-o-x-mark' : 'heroicon-o-arrows-up-down') diff --git a/src/Filament/Resources/PropertyResource.php b/src/Filament/Resources/PropertyResource.php index 84b837b..95c0970 100644 --- a/src/Filament/Resources/PropertyResource.php +++ b/src/Filament/Resources/PropertyResource.php @@ -5,16 +5,33 @@ use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\Catalogue\Enums\PropertyInputType; use Eclipse\Catalogue\Enums\PropertyType; -use Eclipse\Catalogue\Filament\Resources\PropertyResource\Pages; -use Eclipse\Catalogue\Filament\Resources\PropertyResource\RelationManagers; +use Eclipse\Catalogue\Filament\Resources\PropertyResource\Pages\CreateProperty; +use Eclipse\Catalogue\Filament\Resources\PropertyResource\Pages\EditProperty; +use Eclipse\Catalogue\Filament\Resources\PropertyResource\Pages\ListProperties; +use Eclipse\Catalogue\Filament\Resources\PropertyResource\RelationManagers\ValuesRelationManager; use Eclipse\Catalogue\Models\ProductType; use Eclipse\Catalogue\Models\Property; -use Filament\Forms; -use Filament\Forms\Form; -use Filament\Resources\Concerns\Translatable; +use Filament\Actions\Action; +use Filament\Actions\ActionGroup; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; +use Filament\Forms\Components\CheckboxList; +use Filament\Forms\Components\Select; +use Filament\Forms\Components\Textarea; +use Filament\Forms\Components\TextInput; +use Filament\Forms\Components\Toggle; use Filament\Resources\Resource; -use Filament\Tables; +use Filament\Schemas\Components\Section; +use Filament\Schemas\Components\Utilities\Get; +use Filament\Schemas\Schema; +use Filament\Tables\Columns\IconColumn; +use Filament\Tables\Columns\TextColumn; +use Filament\Tables\Filters\SelectFilter; +use Filament\Tables\Filters\TernaryFilter; use Filament\Tables\Table; +use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; class PropertyResource extends Resource implements HasShieldPermissions { @@ -22,49 +39,49 @@ class PropertyResource extends Resource implements HasShieldPermissions protected static ?string $model = Property::class; - protected static ?string $navigationIcon = 'heroicon-o-tag'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-tag'; - protected static ?string $navigationGroup = 'Catalogue'; + protected static string|\UnitEnum|null $navigationGroup = 'Catalogue'; - public static function form(Form $form): Form + public static function form(Schema $schema): Schema { - return $form - ->schema([ - Forms\Components\Section::make(__('eclipse-catalogue::property.sections.basic_information')) + return $schema + ->components([ + Section::make(__('eclipse-catalogue::property.sections.basic_information')) ->schema([ - Forms\Components\TextInput::make('name') + TextInput::make('name') ->label(__('eclipse-catalogue::property.fields.name')) ->required() ->maxLength(255), - Forms\Components\TextInput::make('code') + TextInput::make('code') ->label(__('eclipse-catalogue::property.fields.code')) ->helperText(__('eclipse-catalogue::property.help_text.code')) ->regex('/^[a-zA-Z0-9_]*$/') ->unique(ignoreRecord: true), - Forms\Components\Textarea::make('description') + Textarea::make('description') ->label(__('eclipse-catalogue::property.fields.description')) ->rows(3), - Forms\Components\TextInput::make('internal_name') + TextInput::make('internal_name') ->label(__('eclipse-catalogue::property.fields.internal_name')) ->helperText(__('eclipse-catalogue::property.help_text.internal_name')) ->maxLength(255), ])->columns(2), - Forms\Components\Section::make(__('eclipse-catalogue::property.sections.configuration')) + Section::make(__('eclipse-catalogue::property.sections.configuration')) ->schema([ - Forms\Components\Toggle::make('is_active') + Toggle::make('is_active') ->label(__('eclipse-catalogue::property.fields.is_active')) ->default(true), - Forms\Components\Toggle::make('is_global') + Toggle::make('is_global') ->label(__('eclipse-catalogue::property.fields.is_global')) ->helperText(__('eclipse-catalogue::property.help_text.is_global')) ->reactive(), - Forms\Components\Select::make('type') + Select::make('type') ->label('Property Type') ->options(fn () => collect(PropertyType::cases()) ->mapWithKeys(fn (PropertyType $e) => [$e->value => $e->getLabel()]) @@ -73,53 +90,53 @@ public static function form(Form $form): Form ->reactive() ->required(), - Forms\Components\Select::make('input_type') + Select::make('input_type') ->label('Input Type') ->options(fn () => collect(PropertyInputType::cases()) ->mapWithKeys(fn (PropertyInputType $e) => [$e->value => $e->getLabel()]) ->toArray()) - ->visible(fn (Forms\Get $get) => $get('type') === PropertyType::CUSTOM->value) - ->required(fn (Forms\Get $get) => $get('type') === PropertyType::CUSTOM->value) + ->visible(fn (Get $get) => $get('type') === PropertyType::CUSTOM->value) + ->required(fn (Get $get) => $get('type') === PropertyType::CUSTOM->value) ->reactive(), - Forms\Components\Toggle::make('is_multilang') + Toggle::make('is_multilang') ->label('Multilingual') ->helperText('Enable translation support for string, text, and file inputs') - ->visible(fn (Forms\Get $get) => $get('type') === PropertyType::CUSTOM->value && in_array($get('input_type'), [ + ->visible(fn (Get $get) => $get('type') === PropertyType::CUSTOM->value && in_array($get('input_type'), [ PropertyInputType::STRING->value, PropertyInputType::TEXT->value, PropertyInputType::FILE->value, ])) ->default(false), - Forms\Components\TextInput::make('max_values') + TextInput::make('max_values') ->label(__('eclipse-catalogue::property.fields.max_values')) ->numeric() ->minValue(1) ->maxValue(10) ->helperText(__('eclipse-catalogue::property.help_text.max_values')) - ->visible(fn (Forms\Get $get) => $get('type') === PropertyType::LIST->value || $get('input_type') === PropertyInputType::FILE->value), + ->visible(fn (Get $get) => $get('type') === PropertyType::LIST->value || $get('input_type') === PropertyInputType::FILE->value), - Forms\Components\Toggle::make('enable_sorting') + Toggle::make('enable_sorting') ->label(__('eclipse-catalogue::property.fields.enable_sorting')) ->helperText(__('eclipse-catalogue::property.help_text.enable_sorting')) - ->visible(fn (Forms\Get $get) => $get('type') === PropertyType::LIST->value), + ->visible(fn (Get $get) => $get('type') === PropertyType::LIST->value), - Forms\Components\Toggle::make('is_filter') + Toggle::make('is_filter') ->label(__('eclipse-catalogue::property.fields.is_filter')) ->helperText(__('eclipse-catalogue::property.help_text.is_filter')), ])->columns(2), - Forms\Components\Section::make(__('eclipse-catalogue::property.sections.product_types')) + Section::make(__('eclipse-catalogue::property.sections.product_types')) ->schema([ - Forms\Components\CheckboxList::make('product_types') + CheckboxList::make('product_types') ->label(__('eclipse-catalogue::property.fields.product_types')) ->relationship('productTypes', 'name') ->options(ProductType::pluck('name', 'id')) ->helperText(__('eclipse-catalogue::property.help_text.product_types')) - ->hidden(fn (Forms\Get $get) => $get('is_global')), + ->hidden(fn (Get $get) => $get('is_global')), ]) - ->hidden(fn (Forms\Get $get) => $get('is_global')), + ->hidden(fn (Get $get) => $get('is_global')), ]); } @@ -127,22 +144,22 @@ public static function table(Table $table): Table { return $table ->columns([ - Tables\Columns\TextColumn::make('code') + TextColumn::make('code') ->label(__('eclipse-catalogue::property.table.columns.code')) ->searchable() ->sortable(), - Tables\Columns\TextColumn::make('name') + TextColumn::make('name') ->label(__('eclipse-catalogue::property.table.columns.name')) ->searchable() ->sortable(), - Tables\Columns\TextColumn::make('internal_name') + TextColumn::make('internal_name') ->label(__('eclipse-catalogue::property.table.columns.internal_name')) ->searchable() ->toggleable(isToggledHiddenByDefault: true), - Tables\Columns\TextColumn::make('type') + TextColumn::make('type') ->label('Type') ->badge() ->color(fn (string $state): string => match ($state) { @@ -152,55 +169,55 @@ public static function table(Table $table): Table default => 'gray', }), - Tables\Columns\TextColumn::make('input_type') + TextColumn::make('input_type') ->label('Input Type') ->visible(fn (?Property $record) => $record && $record->isCustomType()) ->badge() ->color('info'), - Tables\Columns\IconColumn::make('is_multilang') + IconColumn::make('is_multilang') ->label('Multilingual') ->boolean() ->state(fn (?Property $record) => $record?->supportsMultilang()) ->visible(fn (?Property $record) => $record && $record->supportsMultilang()), - Tables\Columns\IconColumn::make('is_global') + IconColumn::make('is_global') ->label(__('eclipse-catalogue::property.table.columns.is_global')) ->boolean(), - Tables\Columns\TextColumn::make('max_values') + TextColumn::make('max_values') ->label(__('eclipse-catalogue::property.table.columns.max_values')) ->numeric(), - Tables\Columns\IconColumn::make('enable_sorting') + IconColumn::make('enable_sorting') ->label(__('eclipse-catalogue::property.table.columns.enable_sorting')) ->boolean(), - Tables\Columns\IconColumn::make('is_filter') + IconColumn::make('is_filter') ->label(__('eclipse-catalogue::property.table.columns.is_filter')) ->boolean(), - Tables\Columns\IconColumn::make('is_active') + IconColumn::make('is_active') ->label(__('eclipse-catalogue::property.table.columns.is_active')) ->boolean(), - Tables\Columns\TextColumn::make('values_count') + TextColumn::make('values_count') ->label(__('eclipse-catalogue::property.table.columns.values_count')) ->counts('values'), - Tables\Columns\TextColumn::make('created_at') + TextColumn::make('created_at') ->label(__('eclipse-catalogue::property.table.columns.created_at')) ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ - Tables\Filters\SelectFilter::make('product_type') + SelectFilter::make('product_type') ->label(__('eclipse-catalogue::property.table.filters.product_type')) ->relationship('productTypes', 'name') ->multiple(), - Tables\Filters\SelectFilter::make('type') + SelectFilter::make('type') ->label('Property Type') ->options([ PropertyType::LIST->value => PropertyType::LIST->getLabel(), @@ -208,29 +225,29 @@ public static function table(Table $table): Table PropertyType::CUSTOM->value => PropertyType::CUSTOM->getLabel(), ]), - Tables\Filters\TernaryFilter::make('is_global') + TernaryFilter::make('is_global') ->label(__('eclipse-catalogue::property.table.filters.is_global')), - Tables\Filters\TernaryFilter::make('is_active') + TernaryFilter::make('is_active') ->label(__('eclipse-catalogue::property.table.filters.is_active')), - Tables\Filters\TernaryFilter::make('is_filter') + TernaryFilter::make('is_filter') ->label(__('eclipse-catalogue::property.table.filters.is_filter')), ]) - ->actions([ - Tables\Actions\ActionGroup::make([ - Tables\Actions\Action::make('values') + ->recordActions([ + ActionGroup::make([ + Action::make('values') ->label(__('eclipse-catalogue::property.table.actions.values')) ->icon('heroicon-o-list-bullet') ->url(fn (Property $record): string => PropertyValueResource::getUrl('index', ['property' => $record->id])) ->visible(fn (Property $record): bool => in_array($record->type, [PropertyType::LIST->value, PropertyType::COLOR->value], true)), - Tables\Actions\EditAction::make(), - Tables\Actions\DeleteAction::make(), + EditAction::make(), + DeleteAction::make(), ])->label('Actions'), ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ - Tables\Actions\DeleteBulkAction::make(), + ->toolbarActions([ + BulkActionGroup::make([ + DeleteBulkAction::make(), ]), ]) ->recordUrl(fn (Property $record): ?string => in_array($record->type, [PropertyType::LIST->value, PropertyType::COLOR->value], true) ? PropertyValueResource::getUrl('index', ['property' => $record->id]) : null) @@ -240,16 +257,16 @@ public static function table(Table $table): Table public static function getRelations(): array { return [ - RelationManagers\ValuesRelationManager::class, + ValuesRelationManager::class, ]; } public static function getPages(): array { return [ - 'index' => Pages\ListProperties::route('/'), - 'create' => Pages\CreateProperty::route('/create'), - 'edit' => Pages\EditProperty::route('/{record}/edit'), + 'index' => ListProperties::route('/'), + 'create' => CreateProperty::route('/create'), + 'edit' => EditProperty::route('/{record}/edit'), ]; } diff --git a/src/Filament/Resources/PropertyResource/Pages/CreateProperty.php b/src/Filament/Resources/PropertyResource/Pages/CreateProperty.php index 3bae26e..6330ae8 100644 --- a/src/Filament/Resources/PropertyResource/Pages/CreateProperty.php +++ b/src/Filament/Resources/PropertyResource/Pages/CreateProperty.php @@ -3,9 +3,9 @@ namespace Eclipse\Catalogue\Filament\Resources\PropertyResource\Pages; use Eclipse\Catalogue\Filament\Resources\PropertyResource; -use Filament\Actions\LocaleSwitcher; use Filament\Resources\Pages\CreateRecord; -use Filament\Resources\Pages\CreateRecord\Concerns\Translatable; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\CreateRecord\Concerns\Translatable; class CreateProperty extends CreateRecord { diff --git a/src/Filament/Resources/PropertyResource/Pages/EditProperty.php b/src/Filament/Resources/PropertyResource/Pages/EditProperty.php index 83896b7..cf6ff33 100644 --- a/src/Filament/Resources/PropertyResource/Pages/EditProperty.php +++ b/src/Filament/Resources/PropertyResource/Pages/EditProperty.php @@ -4,11 +4,11 @@ use Eclipse\Catalogue\Enums\PropertyType; use Eclipse\Catalogue\Filament\Resources\PropertyResource; -use Eclipse\Catalogue\Filament\Resources\PropertyResource\RelationManagers; -use Filament\Actions; -use Filament\Actions\LocaleSwitcher; +use Eclipse\Catalogue\Filament\Resources\PropertyResource\RelationManagers\ValuesRelationManager; +use Filament\Actions\DeleteAction; use Filament\Resources\Pages\EditRecord; -use Filament\Resources\Pages\EditRecord\Concerns\Translatable; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\EditRecord\Concerns\Translatable; class EditProperty extends EditRecord { @@ -25,7 +25,7 @@ protected function getHeaderActions(): array { return [ LocaleSwitcher::make(), - Actions\DeleteAction::make(), + DeleteAction::make(), ]; } @@ -34,7 +34,7 @@ public function getRelationManagers(): array $managers = []; if ($this->getRecord() && $this->getRecord()->type === PropertyType::LIST->value) { - $managers[] = RelationManagers\ValuesRelationManager::class; + $managers[] = ValuesRelationManager::class; } return $managers; diff --git a/src/Filament/Resources/PropertyResource/Pages/ListProperties.php b/src/Filament/Resources/PropertyResource/Pages/ListProperties.php index 16d8919..3d183ba 100644 --- a/src/Filament/Resources/PropertyResource/Pages/ListProperties.php +++ b/src/Filament/Resources/PropertyResource/Pages/ListProperties.php @@ -3,9 +3,9 @@ namespace Eclipse\Catalogue\Filament\Resources\PropertyResource\Pages; use Eclipse\Catalogue\Filament\Resources\PropertyResource; -use Filament\Actions; +use Filament\Actions\CreateAction; use Filament\Resources\Pages\ListRecords; -use Filament\Resources\Pages\ListRecords\Concerns\Translatable; +use LaraZeus\SpatieTranslatable\Resources\Pages\ListRecords\Concerns\Translatable; class ListProperties extends ListRecords { @@ -16,7 +16,7 @@ class ListProperties extends ListRecords protected function getHeaderActions(): array { return [ - Actions\CreateAction::make(), + CreateAction::make(), ]; } } diff --git a/src/Filament/Resources/PropertyResource/RelationManagers/ValuesRelationManager.php b/src/Filament/Resources/PropertyResource/RelationManagers/ValuesRelationManager.php index 3abeae2..71068bc 100644 --- a/src/Filament/Resources/PropertyResource/RelationManagers/ValuesRelationManager.php +++ b/src/Filament/Resources/PropertyResource/RelationManagers/ValuesRelationManager.php @@ -3,12 +3,21 @@ namespace Eclipse\Catalogue\Filament\Resources\PropertyResource\RelationManagers; use Eclipse\Catalogue\Models\Property; -use Filament\Forms; -use Filament\Forms\Form; -use Filament\Resources\RelationManagers\Concerns\Translatable; +use Filament\Actions\Action; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\CreateAction; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; +use Filament\Forms\Components\FileUpload; +use Filament\Forms\Components\TextInput; use Filament\Resources\RelationManagers\RelationManager; -use Filament\Tables; +use Filament\Schemas\Schema; +use Filament\Tables\Columns\ImageColumn; +use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\RelationManagers\Concerns\Translatable; class ValuesRelationManager extends RelationManager { @@ -18,22 +27,23 @@ class ValuesRelationManager extends RelationManager protected static ?string $recordTitleAttribute = 'value'; - public function form(Form $form): Form + public function form(Schema $schema): Schema { - return $form - ->schema([ - Forms\Components\TextInput::make('value') + return $schema + ->components([ + TextInput::make('value') + ->translatable() ->label(__('eclipse-catalogue::property-value.fields.value')) ->required() ->maxLength(255), - Forms\Components\TextInput::make('info_url') + TextInput::make('info_url') ->label(__('eclipse-catalogue::property-value.fields.info_url')) ->helperText(__('eclipse-catalogue::property-value.help_text.info_url')) ->url() ->maxLength(255), - Forms\Components\FileUpload::make('image') + FileUpload::make('image') ->label(__('eclipse-catalogue::property-value.fields.image')) ->helperText(__('eclipse-catalogue::property-value.help_text.image')) ->image() @@ -74,26 +84,26 @@ public function table(Table $table): Table $table = $table ->columns([ - Tables\Columns\TextColumn::make('value') + TextColumn::make('value') ->label(__('eclipse-catalogue::property-value.table.columns.value')) ->searchable() ->sortable(), - Tables\Columns\ImageColumn::make('image') + ImageColumn::make('image') ->label(__('eclipse-catalogue::property-value.table.columns.image')) ->disk('public') ->size(40), - Tables\Columns\TextColumn::make('info_url') + TextColumn::make('info_url') ->label(__('eclipse-catalogue::property-value.table.columns.info_url')) ->limit(50) ->toggleable(isToggledHiddenByDefault: true), - Tables\Columns\TextColumn::make('products_count') + TextColumn::make('products_count') ->label(__('eclipse-catalogue::property-value.table.columns.products_count')) ->counts('products'), - Tables\Columns\TextColumn::make('created_at') + TextColumn::make('created_at') ->label(__('eclipse-catalogue::property-value.table.columns.created_at')) ->dateTime() ->sortable() @@ -104,19 +114,20 @@ public function table(Table $table): Table ]) ->deferLoading() ->headerActions([ - Tables\Actions\CreateAction::make() + LocaleSwitcher::make(), + CreateAction::make() ->modalWidth('lg') ->modalHeading(__('eclipse-catalogue::property-value.modal.create_heading')), ]) - ->actions([ - Tables\Actions\EditAction::make() + ->recordActions([ + EditAction::make() ->modalWidth('lg') ->modalHeading(__('eclipse-catalogue::property-value.modal.edit_heading')), - Tables\Actions\DeleteAction::make(), + DeleteAction::make(), ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ - Tables\Actions\DeleteBulkAction::make(), + ->toolbarActions([ + BulkActionGroup::make([ + DeleteBulkAction::make(), ]), ]); @@ -125,7 +136,7 @@ public function table(Table $table): Table ->reorderable('sort') ->defaultSort('sort') ->reorderRecordsTriggerAction( - fn (Tables\Actions\Action $action, bool $isReordering) => $action + fn (Action $action, bool $isReordering) => $action ->button() ->label($isReordering ? 'Disable reordering' : 'Enable reordering') ->icon($isReordering ? 'heroicon-o-x-mark' : 'heroicon-o-arrows-up-down') diff --git a/src/Filament/Resources/PropertyValueResource.php b/src/Filament/Resources/PropertyValueResource.php index 0458c65..e6792ac 100644 --- a/src/Filament/Resources/PropertyValueResource.php +++ b/src/Filament/Resources/PropertyValueResource.php @@ -5,17 +5,38 @@ use Eclipse\Catalogue\Enums\BackgroundType; use Eclipse\Catalogue\Enums\GradientDirection; use Eclipse\Catalogue\Enums\GradientStyle; -use Eclipse\Catalogue\Filament\Resources\PropertyValueResource\Pages; +use Eclipse\Catalogue\Filament\Resources\PropertyValueResource\Pages\ListPropertyValues; +use Eclipse\Catalogue\Models\Property; use Eclipse\Catalogue\Models\PropertyValue; use Eclipse\Catalogue\Values\Background; -use Filament\Forms; -use Filament\Forms\Form; +use Filament\Actions\Action; +use Filament\Actions\ActionGroup; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; +use Filament\Forms\Components\ColorPicker; +use Filament\Forms\Components\FileUpload; +use Filament\Forms\Components\Hidden; +use Filament\Forms\Components\Placeholder; +use Filament\Forms\Components\Radio; +use Filament\Forms\Components\Select; +use Filament\Forms\Components\TextInput; +use Filament\Forms\Components\ViewField; use Filament\Notifications\Notification; -use Filament\Resources\Concerns\Translatable; use Filament\Resources\Resource; -use Filament\Tables; +use Filament\Schemas\Components\Grid; +use Filament\Schemas\Components\Group; +use Filament\Schemas\Components\Utilities\Get; +use Filament\Schemas\Schema; +use Filament\Tables\Columns\ImageColumn; +use Filament\Tables\Columns\TextColumn; +use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; +use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; +use Log; +use Throwable; class PropertyValueResource extends Resource { @@ -23,30 +44,30 @@ class PropertyValueResource extends Resource protected static ?string $model = PropertyValue::class; - protected static ?string $navigationIcon = 'heroicon-o-squares-2x2'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-squares-2x2'; protected static bool $shouldRegisterNavigation = false; - protected static ?string $navigationGroup = 'Catalogue'; + protected static string|\UnitEnum|null $navigationGroup = 'Catalogue'; - public static function form(Form $form): Form + public static function form(Schema $form): Schema { $schema = [ - Forms\Components\Hidden::make('property_id') + Hidden::make('property_id') ->default(fn () => request()->has('property') ? (int) request('property') : null), - Forms\Components\TextInput::make('value') + TextInput::make('value') ->label(__('eclipse-catalogue::property-value.fields.value')) ->required() ->maxLength(255), - Forms\Components\TextInput::make('info_url') + TextInput::make('info_url') ->label(__('eclipse-catalogue::property-value.fields.info_url')) ->helperText(__('eclipse-catalogue::property-value.help_text.info_url')) ->url() ->maxLength(255), - Forms\Components\FileUpload::make('image') + FileUpload::make('image') ->label(__('eclipse-catalogue::property-value.fields.image')) ->helperText(__('eclipse-catalogue::property-value.help_text.image')) ->image() @@ -79,26 +100,26 @@ public static function form(Form $form): Form ]; if (request()->has('property')) { - $prop = \Eclipse\Catalogue\Models\Property::find((int) request('property')); + $prop = Property::find((int) request('property')); if ($prop && $prop->isColorType()) { $colorGroup = static::buildColorGroupSchema(); array_splice($schema, 1, 0, $colorGroup); } } - return $form->schema($schema)->columns(1); + return $form->components($schema)->columns(1); } public static function table(Table $table): Table { $table = $table ->columns([ - Tables\Columns\TextColumn::make('value') + TextColumn::make('value') ->label(__('eclipse-catalogue::property-value.table.columns.value')) ->searchable() ->sortable(), - Tables\Columns\TextColumn::make('color_swatch') + TextColumn::make('color_swatch') ->label('Color') ->state(fn ($record) => $record->getColor()) ->formatStateUsing(function ($state) { @@ -109,51 +130,51 @@ public static function table(Table $table): Table }) ->html(), - Tables\Columns\ImageColumn::make('image') + ImageColumn::make('image') ->label(__('eclipse-catalogue::property-value.table.columns.image')) ->disk('public') ->size(40), - Tables\Columns\TextColumn::make('info_url') + TextColumn::make('info_url') ->label(__('eclipse-catalogue::property-value.table.columns.info_url')) ->limit(50) ->toggleable(isToggledHiddenByDefault: true), - Tables\Columns\TextColumn::make('products_count') + TextColumn::make('products_count') ->label(__('eclipse-catalogue::property-value.table.columns.products_count')) ->counts('products'), - Tables\Columns\TextColumn::make('created_at') + TextColumn::make('created_at') ->label(__('eclipse-catalogue::property-value.table.columns.created_at')) ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ - Tables\Filters\SelectFilter::make('property') + SelectFilter::make('property') ->label(__('eclipse-catalogue::property-value.table.filters.property')) ->relationship('property', 'name') ->default(fn () => request('property')), ]) - ->actions([ - Tables\Actions\ActionGroup::make([ - Tables\Actions\EditAction::make() + ->recordActions([ + ActionGroup::make([ + EditAction::make() ->modalWidth('lg') ->modalHeading(__('eclipse-catalogue::property-value.modal.edit_heading')) - ->form(function (Form $form) { + ->schema(function (Schema $form) { $schema = [ - Forms\Components\TextInput::make('value') + TextInput::make('value') ->label(__('eclipse-catalogue::property-value.fields.value')) ->required() ->maxLength(255), - Forms\Components\TextInput::make('info_url') + TextInput::make('info_url') ->label(__('eclipse-catalogue::property-value.fields.info_url')) ->helperText(__('eclipse-catalogue::property-value.help_text.info_url')) ->url() ->maxLength(255), - Forms\Components\FileUpload::make('image') + FileUpload::make('image') ->label(__('eclipse-catalogue::property-value.fields.image')) ->helperText(__('eclipse-catalogue::property-value.help_text.image')) ->image() @@ -164,7 +185,7 @@ public static function table(Table $table): Table $prop = null; if (request()->has('property')) { - $prop = \Eclipse\Catalogue\Models\Property::find((int) request('property')); + $prop = Property::find((int) request('property')); } elseif ($record = $form->getModelInstance()) { if (method_exists($record, 'property')) { $prop = $record->property; @@ -176,18 +197,18 @@ public static function table(Table $table): Table array_splice($schema, 1, 0, $colorGroup); } - return $form->schema($schema)->columns(1); + return $form->components($schema)->columns(1); }), - Tables\Actions\Action::make('merge') + Action::make('merge') ->label(__('eclipse-catalogue::property-value.table.actions.merge')) ->icon('heroicon-o-arrow-uturn-right') ->modalHeading(__('eclipse-catalogue::property-value.modal.merge_heading')) - ->form(function (PropertyValue $record) { + ->schema(function (PropertyValue $record) { return [ - \Filament\Forms\Components\Placeholder::make('current_value') + Placeholder::make('current_value') ->label(__('eclipse-catalogue::property-value.modal.merge_from_label')) ->content($record->value), - \Filament\Forms\Components\Select::make('target_id') + Select::make('target_id') ->label(__('eclipse-catalogue::property-value.modal.merge_to_label')) ->required() ->options( @@ -197,7 +218,7 @@ public static function table(Table $table): Table ->orderBy('value') ->pluck('value', 'id') ), - \Filament\Forms\Components\Placeholder::make('merge_helper') + Placeholder::make('merge_helper') ->label('') ->content(__('eclipse-catalogue::property-value.modal.merge_helper')) ->columnSpanFull(), @@ -218,8 +239,8 @@ public static function table(Table $table): Table ->body(__('eclipse-catalogue::property-value.messages.merged_body', ['affected' => $result['affected_products']])) ->success() ->send(); - } catch (\Throwable $e) { - \Log::error('Merge property values failed', ['exception' => $e]); + } catch (Throwable $e) { + Log::error('Merge property values failed', ['exception' => $e]); Notification::make() ->title(__('eclipse-catalogue::property-value.messages.merged_error_title')) ->body(__('eclipse-catalogue::property-value.messages.merged_error_body')) @@ -228,12 +249,12 @@ public static function table(Table $table): Table throw $e; } }), - Tables\Actions\DeleteAction::make(), + DeleteAction::make(), ]), ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ - Tables\Actions\DeleteBulkAction::make(), + ->toolbarActions([ + BulkActionGroup::make([ + DeleteBulkAction::make(), ]), ]); @@ -243,10 +264,10 @@ public static function table(Table $table): Table public static function buildColorGroupSchema(): array { return [ - Forms\Components\Group::make() + Group::make() ->statePath('color') ->dehydrated(true) - ->afterStateHydrated(function (\Filament\Forms\Components\Group $component, $state) { + ->afterStateHydrated(function (Group $component, $state) { if (is_string($state)) { $decoded = json_decode($state, true); if (json_last_error() === JSON_ERROR_NONE) { @@ -256,27 +277,27 @@ public static function buildColorGroupSchema(): array }) ->dehydrateStateUsing(fn ($state) => $state) ->schema([ - Forms\Components\Radio::make('type') + Radio::make('type') ->options(fn () => collect(BackgroundType::cases()) ->mapWithKeys(fn (BackgroundType $e) => [$e->value => $e->getLabel()]) ->toArray()) ->default(BackgroundType::NONE->value) ->live(), - Forms\Components\ColorPicker::make('color') - ->visible(fn (Forms\Get $get) => $get('type') === 's') + ColorPicker::make('color') + ->visible(fn (Get $get) => $get('type') === 's') ->live(), - Forms\Components\Grid::make() + Grid::make() ->columns(4) - ->visible(fn (Forms\Get $get) => $get('type') === 'g') + ->visible(fn (Get $get) => $get('type') === 'g') ->schema([ - Forms\Components\ColorPicker::make('color_start')->columnSpan(2)->live(), - Forms\Components\ColorPicker::make('color_end')->columnSpan(2)->live(), - Forms\Components\Select::make('gradient_direction') + ColorPicker::make('color_start')->columnSpan(2)->live(), + ColorPicker::make('color_end')->columnSpan(2)->live(), + Select::make('gradient_direction') ->options(fn () => collect(GradientDirection::cases()) ->mapWithKeys(fn (GradientDirection $e) => [$e->value => $e->getLabel()]) ->toArray()) ->default(GradientDirection::BOTTOM->value)->columnSpan(2)->live(), - Forms\Components\Radio::make('gradient_style') + Radio::make('gradient_style') ->options(fn () => collect(GradientStyle::cases()) ->mapWithKeys(fn (GradientStyle $e) => [$e->value => $e->getLabel()]) ->toArray()) @@ -286,9 +307,9 @@ public static function buildColorGroupSchema(): array ->columnSpan(2) ->live(), ]), - Forms\Components\ViewField::make('preview') + ViewField::make('preview') ->view('eclipse-catalogue::components.color-preview') - ->visible(function (Forms\Get $get) { + ->visible(function (Get $get) { $bg = Background::fromForm([ 'type' => $get('type'), 'color' => $get('color'), @@ -300,7 +321,7 @@ public static function buildColorGroupSchema(): array return $bg->hasRenderableCss(); }) - ->viewData(function (Forms\Get $get) { + ->viewData(function (Get $get) { $bg = Background::fromForm([ 'type' => $get('type'), 'color' => $get('color'), @@ -320,7 +341,7 @@ public static function buildColorGroupSchema(): array public static function getPages(): array { return [ - 'index' => Pages\ListPropertyValues::route('/'), + 'index' => ListPropertyValues::route('/'), ]; } diff --git a/src/Filament/Resources/PropertyValueResource/Pages/ListPropertyValues.php b/src/Filament/Resources/PropertyValueResource/Pages/ListPropertyValues.php index 5332a37..5c16dce 100644 --- a/src/Filament/Resources/PropertyValueResource/Pages/ListPropertyValues.php +++ b/src/Filament/Resources/PropertyValueResource/Pages/ListPropertyValues.php @@ -5,13 +5,18 @@ use Eclipse\Catalogue\Enums\PropertyType; use Eclipse\Catalogue\Filament\Resources\PropertyResource; use Eclipse\Catalogue\Filament\Resources\PropertyValueResource; +use Eclipse\Catalogue\Jobs\ImportColorValues; use Eclipse\Catalogue\Models\Property; -use Filament\Actions; -use Filament\Actions\LocaleSwitcher; +use Filament\Actions\Action; +use Filament\Actions\CreateAction; +use Filament\Forms\Components\FileUpload; +use Filament\Forms\Components\TextInput; use Filament\Resources\Pages\ListRecords; -use Filament\Resources\Pages\ListRecords\Concerns\Translatable; -use Filament\Tables; +use Filament\Schemas\Schema; use Filament\Tables\Table; +use Illuminate\Support\HtmlString; +use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher; +use LaraZeus\SpatieTranslatable\Resources\Pages\ListRecords\Concerns\Translatable; class ListPropertyValues extends ListRecords { @@ -38,23 +43,23 @@ protected function getHeaderActions(): array { $actions = [ LocaleSwitcher::make(), - Actions\CreateAction::make() + CreateAction::make() ->modalWidth('lg') ->modalHeading(__('eclipse-catalogue::property-value.modal.create_heading')) - ->form(function (\Filament\Forms\Form $form) { + ->schema(function (Schema $form) { $schema = [ - \Filament\Forms\Components\TextInput::make('value') + TextInput::make('value') ->label(__('eclipse-catalogue::property-value.fields.value')) ->required() ->maxLength(255), - \Filament\Forms\Components\TextInput::make('info_url') + TextInput::make('info_url') ->label(__('eclipse-catalogue::property-value.fields.info_url')) ->helperText(__('eclipse-catalogue::property-value.help_text.info_url')) ->url() ->maxLength(255), - \Filament\Forms\Components\FileUpload::make('image') + FileUpload::make('image') ->label(__('eclipse-catalogue::property-value.fields.image')) ->helperText(__('eclipse-catalogue::property-value.help_text.image')) ->image() @@ -68,9 +73,9 @@ protected function getHeaderActions(): array array_splice($schema, 1, 0, $colorGroup); } - return $form->schema($schema)->columns(1); + return $form->components($schema)->columns(1); }) - ->mutateFormDataUsing(function (array $data): array { + ->mutateDataUsing(function (array $data): array { // Ensure property_id is set from the page state if (empty($data['property_id']) && $this->property) { $data['property_id'] = $this->property->id; @@ -81,22 +86,22 @@ protected function getHeaderActions(): array ]; if ($this->property && $this->property->type === PropertyType::COLOR->value) { - $actions[] = Actions\Action::make('import') + $actions[] = Action::make('import') ->label(__('eclipse-catalogue::property-value.actions.import')) ->icon('heroicon-o-arrow-up-tray') ->modalWidth('lg') ->modalHeading(__('eclipse-catalogue::property-value.modal.import_heading')) - ->form([ - \Filament\Forms\Components\FileUpload::make('file') + ->schema([ + FileUpload::make('file') ->label(__('eclipse-catalogue::property-value.fields.import_file')) - ->helperText(new \Illuminate\Support\HtmlString(__('eclipse-catalogue::property-value.help_text.import_file'))) + ->helperText(new HtmlString(__('eclipse-catalogue::property-value.help_text.import_file'))) ->acceptedFileTypes(['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'text/csv']) ->required() ->disk('local') ->directory('temp/color-imports'), ]) ->action(function (array $data): void { - \Eclipse\Catalogue\Jobs\ImportColorValues::dispatch($data['file'], $this->property->id); + ImportColorValues::dispatch($data['file'], $this->property->id); }); } @@ -132,7 +137,7 @@ public function getTable(): Table ->reorderable('sort', $this->property?->enable_sorting) ->defaultSort($this->property?->enable_sorting ? 'sort' : 'value') ->reorderRecordsTriggerAction( - fn (Tables\Actions\Action $action, bool $isReordering) => $action + fn (Action $action, bool $isReordering) => $action ->button() ->label($isReordering ? 'Disable reordering' : 'Enable reordering') ->icon($isReordering ? 'heroicon-o-x-mark' : 'heroicon-o-arrows-up-down') diff --git a/src/Filament/Resources/TaxClassResource.php b/src/Filament/Resources/TaxClassResource.php index 7fed21a..e8a3680 100644 --- a/src/Filament/Resources/TaxClassResource.php +++ b/src/Filament/Resources/TaxClassResource.php @@ -3,19 +3,21 @@ namespace Eclipse\Catalogue\Filament\Resources; use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; -use Eclipse\Catalogue\Filament\Resources\TaxClassResource\Pages; +use Eclipse\Catalogue\Filament\Resources\TaxClassResource\Pages\CreateTaxClass; +use Eclipse\Catalogue\Filament\Resources\TaxClassResource\Pages\EditTaxClass; +use Eclipse\Catalogue\Filament\Resources\TaxClassResource\Pages\ListTaxClasses; use Eclipse\Catalogue\Models\TaxClass; +use Filament\Actions\DeleteAction; +use Filament\Actions\EditAction; +use Filament\Actions\ForceDeleteAction; +use Filament\Actions\RestoreAction; use Filament\Facades\Filament; use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; -use Filament\Forms\Form; use Filament\Resources\Resource; -use Filament\Tables\Actions\DeleteAction; -use Filament\Tables\Actions\EditAction; -use Filament\Tables\Actions\ForceDeleteAction; -use Filament\Tables\Actions\RestoreAction; +use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\TrashedFilter; @@ -29,9 +31,9 @@ class TaxClassResource extends Resource implements HasShieldPermissions protected static ?string $slug = 'tax-classes'; - protected static ?string $navigationIcon = 'heroicon-o-calculator'; + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-calculator'; - protected static ?string $navigationGroup = 'Catalogue'; + protected static string|\UnitEnum|null $navigationGroup = 'Catalogue'; protected static ?string $recordTitleAttribute = 'name'; @@ -49,10 +51,10 @@ public static function getPluralModelLabel(): string return __('eclipse-catalogue::tax-class.plural'); } - 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-catalogue::tax-class.fields.name')) ->required() @@ -139,7 +141,7 @@ public static function table(Table $table): Table ->filters([ TrashedFilter::make(), ]) - ->actions([ + ->recordActions([ EditAction::make(), DeleteAction::make(), RestoreAction::make(), @@ -150,9 +152,9 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => Pages\ListTaxClasses::route('/'), - 'create' => Pages\CreateTaxClass::route('/create'), - 'edit' => Pages\EditTaxClass::route('/{record}/edit'), + 'index' => ListTaxClasses::route('/'), + 'create' => CreateTaxClass::route('/create'), + 'edit' => EditTaxClass::route('/{record}/edit'), ]; } diff --git a/src/Filament/Tables/Actions/BulkUpdateProductsAction.php b/src/Filament/Tables/Actions/BulkUpdateProductsAction.php index 3823fdd..b8f7a99 100644 --- a/src/Filament/Tables/Actions/BulkUpdateProductsAction.php +++ b/src/Filament/Tables/Actions/BulkUpdateProductsAction.php @@ -8,14 +8,17 @@ use Eclipse\Catalogue\Models\ProductStatus; use Eclipse\Catalogue\Models\ProductType; use Eclipse\Catalogue\Services\ProductBulkUpdater; +use Filament\Actions\BulkAction; +use Filament\Facades\Filament; use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\FileUpload; -use Filament\Forms\Components\Section; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; use Filament\Notifications\Notification; -use Filament\Tables\Actions\BulkAction; +use Filament\Schemas\Components\Grid; +use Filament\Schemas\Components\Section; +use Filament\Schemas\Components\Utilities\Set; use Illuminate\Support\Facades\App; class BulkUpdateProductsAction extends BulkAction @@ -39,7 +42,7 @@ public static function make(?string $name = null): static ->options(function () { $query = ProductStatus::query(); $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($tenantFK && $currentTenant) { $query->where($tenantFK, $currentTenant->id); @@ -62,7 +65,7 @@ public static function make(?string $name = null): static ->label('Product Type') ->options(function () { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $query = ProductType::query(); @@ -103,7 +106,7 @@ public static function make(?string $name = null): static ->label('Category') ->options(function () { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $query = Category::query()->withoutGlobalScopes(); if ($tenantFK && $currentTenant) { $query->where($tenantFK, $currentTenant->id); @@ -120,7 +123,7 @@ public static function make(?string $name = null): static ->collapsible() ->collapsed() ->schema([ - \Filament\Forms\Components\Grid::make(2) + Grid::make(2) ->schema([ Select::make('groups_add_ids') ->label('Add to groups') @@ -142,7 +145,7 @@ public static function make(?string $name = null): static ->label(__('eclipse-catalogue::product.price.fields.price_list')) ->options(function () { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); $query = PriceList::query(); if ($tenantFK && $currentTenant) { @@ -161,7 +164,7 @@ public static function make(?string $name = null): static ->searchable() ->preload() ->live() - ->afterStateUpdated(function ($state, \Filament\Forms\Set $set) { + ->afterStateUpdated(function ($state, Set $set) { if (! $state) { return; } @@ -172,9 +175,9 @@ public static function make(?string $name = null): static }) ->columnSpanFull(), - \Filament\Forms\Components\Grid::make(2) + Grid::make(2) ->schema([ - \Filament\Forms\Components\Group::make() + \Filament\Schemas\Components\Group::make() ->schema([ TextInput::make('price') ->label(__('eclipse-catalogue::product.price.fields.price')) @@ -185,7 +188,7 @@ public static function make(?string $name = null): static ->inline(false) ->default(false), ]), - \Filament\Forms\Components\Group::make() + \Filament\Schemas\Components\Group::make() ->schema([ DatePicker::make('valid_from') ->label(__('eclipse-catalogue::product.price.fields.valid_from')) @@ -202,9 +205,9 @@ public static function make(?string $name = null): static ->collapsible() ->collapsed() ->schema([ - \Filament\Forms\Components\Grid::make(2) + Grid::make(2) ->schema([ - \Filament\Forms\Components\Group::make() + \Filament\Schemas\Components\Group::make() ->schema([ FileUpload::make('cover_image') ->label('Cover image') @@ -225,7 +228,7 @@ public static function make(?string $name = null): static ->preserveFilenames() ->nullable(), ]), - \Filament\Forms\Components\Group::make() + \Filament\Schemas\Components\Group::make() ->schema([ FileUpload::make('image_1') ->label('Image #1') diff --git a/src/Forms/Components/GenericTenantFieldsComponent.php b/src/Forms/Components/GenericTenantFieldsComponent.php index 8a66b1c..23e62db 100644 --- a/src/Forms/Components/GenericTenantFieldsComponent.php +++ b/src/Forms/Components/GenericTenantFieldsComponent.php @@ -3,13 +3,15 @@ namespace Eclipse\Catalogue\Forms\Components; use Eclipse\Catalogue\Livewire\TenantSwitcher; -use Filament\Forms\Components\Component; -use Filament\Forms\Components\Fieldset; -use Filament\Forms\Components\Grid; -use Filament\Forms\Components\Section; +use Filament\Facades\Filament; +use Filament\Forms\Components\Hidden; use Filament\Forms\Components\Toggle; -use Filament\Forms\Get; -use Filament\Forms\Set; +use Filament\Schemas\Components\Component; +use Filament\Schemas\Components\Fieldset; +use Filament\Schemas\Components\Grid; +use Filament\Schemas\Components\Section; +use Filament\Schemas\Components\Utilities\Get; +use Filament\Schemas\Components\Utilities\Set; /** * Generic per-tenant fields builder for Filament forms. @@ -52,13 +54,13 @@ public static function make( TenantSwitcher::make('selected_tenant'), // Hidden field to store all tenant data - \Filament\Forms\Components\Hidden::make('all_tenant_data') + Hidden::make('all_tenant_data') ->default([]) ->dehydrated(true), // Hidden field to track previous tenant for switching logic - \Filament\Forms\Components\Hidden::make('_previous_tenant') - ->default(\Filament\Facades\Filament::getTenant()?->id) + Hidden::make('_previous_tenant') + ->default(Filament::getTenant()?->id) ->dehydrated(false), ...static::getTenantSpecificFields($tenants, $tenantFlags, $mutuallyExclusiveFlagSets, $translationPrefix, $extraFieldsBuilder), diff --git a/src/Forms/Components/InlineTranslatableField.php b/src/Forms/Components/InlineTranslatableField.php index ffa532f..81aba2e 100644 --- a/src/Forms/Components/InlineTranslatableField.php +++ b/src/Forms/Components/InlineTranslatableField.php @@ -3,15 +3,16 @@ namespace Eclipse\Catalogue\Forms\Components; use Closure; -use Filament\Forms\Components\Component; +use Eclipse\Core\Models\Locale; use Filament\Forms\Components\FileUpload; -use Filament\Forms\Components\Group; use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\RichEditor; -use Filament\Forms\Components\Tabs; -use Filament\Forms\Components\Tabs\Tab; use Filament\Forms\Components\TextInput; -use Filament\Forms\Get; +use Filament\Schemas\Components\Component; +use Filament\Schemas\Components\Group; +use Filament\Schemas\Components\Tabs; +use Filament\Schemas\Components\Tabs\Tab; +use Filament\Schemas\Components\Utilities\Get; use Filament\Support\Enums\IconPosition; use Illuminate\Support\Facades\Blade; use Illuminate\Support\HtmlString; @@ -280,8 +281,8 @@ protected function valueHasMeaningfulContent(mixed $value): bool */ protected function getAvailableLocales(): array { - if (class_exists(\Eclipse\Core\Models\Locale::class)) { - return \Eclipse\Core\Models\Locale::getAvailableLocales()->pluck('id')->toArray(); + if (class_exists(Locale::class)) { + return Locale::getAvailableLocales()->pluck('id')->toArray(); } return ['en']; diff --git a/src/Jobs/ImportColorValues.php b/src/Jobs/ImportColorValues.php index 4533feb..f857794 100644 --- a/src/Jobs/ImportColorValues.php +++ b/src/Jobs/ImportColorValues.php @@ -2,9 +2,11 @@ namespace Eclipse\Catalogue\Jobs; +use Eclipse\Catalogue\Enums\PropertyType; use Eclipse\Catalogue\Models\Property; use Eclipse\Catalogue\Models\PropertyValue; use Eclipse\Catalogue\Values\Background; +use Eclipse\Common\Enums\JobStatus; use Eclipse\Common\Foundation\Jobs\QueueableJob; use Exception; use Illuminate\Support\Facades\Storage; @@ -65,7 +67,7 @@ public function __construct(string $filePath, int $propertyId) protected function execute(): void { $property = Property::find($this->propertyId); - if (! $property || $property->type !== \Eclipse\Catalogue\Enums\PropertyType::COLOR->value) { + if (! $property || $property->type !== PropertyType::COLOR->value) { throw new Exception('Invalid property or property is not a color type.'); } @@ -197,11 +199,11 @@ private function isValidHexColor(string $hex): bool */ protected function getNotificationTitle(): string { - if ($this->status === \Eclipse\Common\Enums\JobStatus::COMPLETED) { + if ($this->status === JobStatus::COMPLETED) { return __('eclipse-catalogue::property-value.notifications.import_completed.title'); } - if ($this->status === \Eclipse\Common\Enums\JobStatus::FAILED) { + if ($this->status === JobStatus::FAILED) { return __('eclipse-catalogue::property-value.notifications.import_failed.title'); } @@ -213,7 +215,7 @@ protected function getNotificationTitle(): string */ protected function getNotificationBody(): string { - if ($this->status === \Eclipse\Common\Enums\JobStatus::COMPLETED) { + if ($this->status === JobStatus::COMPLETED) { $body = __('eclipse-catalogue::property-value.notifications.import_completed.body', [ 'inserted' => $this->stats['inserted'], 'skipped' => $this->stats['skipped'], @@ -231,7 +233,7 @@ protected function getNotificationBody(): string return $body; } - if ($this->status === \Eclipse\Common\Enums\JobStatus::FAILED) { + if ($this->status === JobStatus::FAILED) { $message = $this->exception?->getMessage(); return $message ?: __('eclipse-catalogue::property-value.notifications.import_queued.body'); diff --git a/src/Livewire/TenantSwitcher.php b/src/Livewire/TenantSwitcher.php index c8ae44a..67dfd48 100644 --- a/src/Livewire/TenantSwitcher.php +++ b/src/Livewire/TenantSwitcher.php @@ -3,7 +3,6 @@ namespace Eclipse\Catalogue\Livewire; use Filament\Facades\Filament; -use Filament\Forms\Components\Component; use Filament\Forms\Components\Select; use Livewire\Component as LivewireComponent; @@ -48,7 +47,7 @@ public function render() /** * Create a Filament Select component used within the form schema. */ - public static function make(string $fieldName = 'selected_tenant'): Component + public static function make(string $fieldName = 'selected_tenant'): \Filament\Schemas\Components\Component { $tenantModel = config('eclipse-catalogue.tenancy.model'); @@ -110,7 +109,7 @@ public static function makeWithOptions( array $options = [], ?string $label = null, ?string $placeholder = null - ): Component { + ): \Filament\Schemas\Components\Component { $tenantModel = config('eclipse-catalogue.tenancy.model'); if (! $tenantModel) { diff --git a/src/Models/Group.php b/src/Models/Group.php index 20d1644..3c00d1a 100644 --- a/src/Models/Group.php +++ b/src/Models/Group.php @@ -4,6 +4,7 @@ use Eclipse\Catalogue\Factories\GroupFactory; use Eclipse\Common\Foundation\Models\Scopes\ActiveScope; +use Filament\Facades\Filament; use Illuminate\Database\Eloquent\Attributes\ScopedBy; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -37,7 +38,7 @@ class Group extends Model public function scopeForCurrentTenant(Builder $query): Builder { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $tenant = \Filament\Facades\Filament::getTenant(); + $tenant = Filament::getTenant(); if ($tenantFK && $tenant) { $query->where($tenantFK, $tenant->id); diff --git a/src/Models/PriceListData.php b/src/Models/PriceListData.php index 571e6c2..1e47eaf 100644 --- a/src/Models/PriceListData.php +++ b/src/Models/PriceListData.php @@ -2,6 +2,8 @@ namespace Eclipse\Catalogue\Models; +use Eclipse\Catalogue\Factories\PriceListDataFactory; +use Eclipse\Core\Models\Site; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -46,7 +48,7 @@ public function priceList(): BelongsTo /** @return BelongsTo<\Eclipse\Core\Models\Site, self> */ public function site(): BelongsTo { - return $this->belongsTo(\Eclipse\Core\Models\Site::class); + return $this->belongsTo(Site::class); } /** @@ -63,6 +65,6 @@ protected function casts(): array protected static function newFactory() { - return \Eclipse\Catalogue\Factories\PriceListDataFactory::new(); + return PriceListDataFactory::new(); } } diff --git a/src/Models/Product.php b/src/Models/Product.php index 2076851..f45727f 100644 --- a/src/Models/Product.php +++ b/src/Models/Product.php @@ -4,9 +4,11 @@ use Eclipse\Catalogue\Enums\PropertyInputType; use Eclipse\Catalogue\Factories\ProductFactory; +use Eclipse\Catalogue\Models\Product\Price; use Eclipse\Catalogue\Traits\HasTenantScopedData; use Eclipse\Common\Foundation\Models\IsSearchable; use Eclipse\World\Models\Country; +use Eclipse\World\Models\TariffCode; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -127,7 +129,7 @@ public function originCountry(): BelongsTo public function tariffCode(): BelongsTo { - return $this->belongsTo(\Eclipse\World\Models\TariffCode::class, 'tariff_code_id'); + return $this->belongsTo(TariffCode::class, 'tariff_code_id'); } /** @@ -159,7 +161,7 @@ public function getHasFreeDeliveryAttribute(): bool */ public function prices(): HasMany { - return $this->hasMany(\Eclipse\Catalogue\Models\Product\Price::class); + return $this->hasMany(Price::class); } public function getAvailableFromDateAttribute() diff --git a/src/Models/ProductData.php b/src/Models/ProductData.php index d4a4148..5901ba4 100644 --- a/src/Models/ProductData.php +++ b/src/Models/ProductData.php @@ -2,6 +2,8 @@ namespace Eclipse\Catalogue\Models; +use Eclipse\Catalogue\Factories\ProductDataFactory; +use Eclipse\Core\Models\Site; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -57,7 +59,7 @@ public function status(): BelongsTo /** @return BelongsTo<\Eclipse\Core\Models\Site, self> */ public function site(): BelongsTo { - return $this->belongsTo(\Eclipse\Core\Models\Site::class); + return $this->belongsTo(Site::class); } protected function casts(): array @@ -71,6 +73,6 @@ protected function casts(): array protected static function newFactory() { - return \Eclipse\Catalogue\Factories\ProductDataFactory::new(); + return ProductDataFactory::new(); } } diff --git a/src/Models/ProductStatus.php b/src/Models/ProductStatus.php index 51ad315..5956d1d 100644 --- a/src/Models/ProductStatus.php +++ b/src/Models/ProductStatus.php @@ -2,9 +2,11 @@ namespace Eclipse\Catalogue\Models; +use Eclipse\Catalogue\Enums\StructuredData\ItemAvailability; use Eclipse\Catalogue\Factories\ProductStatusFactory; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use InvalidArgumentException; use Spatie\Translatable\HasTranslations; class ProductStatus extends Model @@ -59,7 +61,7 @@ protected function casts(): array 'is_default' => 'boolean', 'priority' => 'integer', 'skip_stock_qty_check' => 'boolean', - 'sd_item_availability' => \Eclipse\Catalogue\Enums\StructuredData\ItemAvailability::class, + 'sd_item_availability' => ItemAvailability::class, ]; } @@ -76,12 +78,12 @@ protected static function boot() static::saving(function ($model) { // Validate code length if (strlen($model->code) > 20) { - throw new \InvalidArgumentException('Code must not exceed 20 characters.'); + throw new InvalidArgumentException('Code must not exceed 20 characters.'); } // Validate required fields if (empty($model->title) || empty($model->label_type) || empty($model->priority) || empty($model->sd_item_availability)) { - throw new \InvalidArgumentException('Required fields cannot be empty.'); + throw new InvalidArgumentException('Required fields cannot be empty.'); } }); diff --git a/src/Models/ProductType.php b/src/Models/ProductType.php index 4092b89..8065f30 100644 --- a/src/Models/ProductType.php +++ b/src/Models/ProductType.php @@ -4,6 +4,7 @@ use Eclipse\Catalogue\Factories\ProductTypeFactory; use Eclipse\Catalogue\Traits\HasTenantScopedData; +use Filament\Facades\Filament; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -67,7 +68,7 @@ public function properties(): BelongsToMany public static function getDefault(?int $tenantId = null): ?self { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenantId = $tenantId ?: \Filament\Facades\Filament::getTenant()?->id; + $currentTenantId = $tenantId ?: Filament::getTenant()?->id; $query = static::whereHas('productTypeData', function ($q) use ($tenantFK, $currentTenantId) { $q->where('is_default', true); diff --git a/src/Models/ProductTypeData.php b/src/Models/ProductTypeData.php index b34aaab..f4759e4 100644 --- a/src/Models/ProductTypeData.php +++ b/src/Models/ProductTypeData.php @@ -2,6 +2,8 @@ namespace Eclipse\Catalogue\Models; +use Eclipse\Catalogue\Factories\ProductTypeDataFactory; +use Eclipse\Core\Models\Site; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -45,7 +47,7 @@ public function productType(): BelongsTo /** @return BelongsTo<\Eclipse\Core\Models\Site, self> */ public function site(): BelongsTo { - return $this->belongsTo(\Eclipse\Core\Models\Site::class); + return $this->belongsTo(Site::class); } /** @@ -61,6 +63,6 @@ protected function casts(): array protected static function newFactory() { - return \Eclipse\Catalogue\Factories\ProductTypeDataFactory::new(); + return ProductTypeDataFactory::new(); } } diff --git a/src/Models/Property.php b/src/Models/Property.php index aa0e2b1..db3726f 100644 --- a/src/Models/Property.php +++ b/src/Models/Property.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\SoftDeletes; +use InvalidArgumentException; use Spatie\Translatable\HasTranslations; class Property extends Model @@ -100,7 +101,7 @@ protected function validateTypeAndInputType(): void if ($this->type && ! empty(trim($this->type))) { $validTypes = [PropertyType::LIST->value, PropertyType::COLOR->value, PropertyType::CUSTOM->value]; if (! in_array($this->type, $validTypes)) { - throw new \InvalidArgumentException("Invalid type '{$this->type}'. Must be one of: ".implode(', ', $validTypes)); + throw new InvalidArgumentException("Invalid type '{$this->type}'. Must be one of: ".implode(', ', $validTypes)); } } @@ -116,7 +117,7 @@ protected function validateTypeAndInputType(): void ]; if (! in_array($this->input_type, $validInputTypes)) { - throw new \InvalidArgumentException("Invalid input_type '{$this->input_type}'. Must be one of: ".implode(', ', $validInputTypes)); + throw new InvalidArgumentException("Invalid input_type '{$this->input_type}'. Must be one of: ".implode(', ', $validInputTypes)); } } } diff --git a/src/Models/PropertyValue.php b/src/Models/PropertyValue.php index 2081e1e..d218481 100644 --- a/src/Models/PropertyValue.php +++ b/src/Models/PropertyValue.php @@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Support\Facades\DB; +use RuntimeException; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\Translatable\HasTranslations; @@ -134,11 +135,11 @@ public function mergeInto(int $targetId): array $target = self::query()->lockForUpdate()->findOrFail($targetId); if ($target->id === $this->id) { - throw new \RuntimeException('Cannot merge a value into itself.'); + throw new RuntimeException('Cannot merge a value into itself.'); } if ($target->property_id !== $this->property_id) { - throw new \RuntimeException('Values must belong to the same property.'); + throw new RuntimeException('Values must belong to the same property.'); } $pivotTable = 'catalogue_product_has_property_value'; diff --git a/src/Models/TaxClass.php b/src/Models/TaxClass.php index 4caee38..f47772f 100644 --- a/src/Models/TaxClass.php +++ b/src/Models/TaxClass.php @@ -95,7 +95,7 @@ public static function getDefault(?int $tenantId = null): ?self // Add tenant scope if tenancy is configured $tenantFK = config('eclipse-catalogue.tenancy.foreign_key'); - $currentTenantId = $tenantId ?: \Filament\Facades\Filament::getTenant()?->id; + $currentTenantId = $tenantId ?: Filament::getTenant()?->id; if ($tenantFK && $currentTenantId) { $query->where($tenantFK, $currentTenantId); } diff --git a/src/Services/ProductBulkUpdater.php b/src/Services/ProductBulkUpdater.php index 10fa5cb..fe8f6ca 100644 --- a/src/Services/ProductBulkUpdater.php +++ b/src/Services/ProductBulkUpdater.php @@ -2,11 +2,16 @@ namespace Eclipse\Catalogue\Services; +use Carbon\Carbon; use Eclipse\Catalogue\Models\Group; use Eclipse\Catalogue\Models\Product\Price as ProductPrice; +use Filament\Facades\Filament; +use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; +use RuntimeException; +use Throwable; class ProductBulkUpdater { @@ -90,12 +95,12 @@ public function apply(array $data, iterable $products): array } if (is_string($fileValue)) { if (! Storage::disk('public')->exists($fileValue)) { - throw new \RuntimeException('Temp image not found on public disk: '.$fileValue); + throw new RuntimeException('Temp image not found on public disk: '.$fileValue); } return $product->addMediaFromDisk($fileValue, 'public'); } - if ($fileValue instanceof \Illuminate\Http\UploadedFile) { + if ($fileValue instanceof UploadedFile) { return $product->addMedia($fileValue->getRealPath()); } @@ -137,7 +142,7 @@ public function apply(array $data, iterable $products): array if ($shouldUpdateCategories) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($tenantFK && $currentTenant) { $existing = $product->productData()->where($tenantFK, $currentTenant->id)->first(); $currentCategoryId = $existing?->category_id; @@ -163,7 +168,7 @@ public function apply(array $data, iterable $products): array if ($shouldUpdateFreeDelivery) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($tenantFK && $currentTenant) { $existing = $product->productData()->where($tenantFK, $currentTenant->id)->first(); $currentFlag = (bool) ($existing?->has_free_delivery ?? false); @@ -179,7 +184,7 @@ public function apply(array $data, iterable $products): array if ($shouldUpdateStatus) { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); - $currentTenant = \Filament\Facades\Filament::getTenant(); + $currentTenant = Filament::getTenant(); if ($tenantFK && $currentTenant) { $existing = $product->productData()->where($tenantFK, $currentTenant->id)->first(); $currentStatusId = $existing?->product_status_id; @@ -199,13 +204,13 @@ public function apply(array $data, iterable $products): array $price = ProductPrice::query()->firstOrNew([ 'product_id' => $product->id, 'price_list_id' => (int) $bulkPriceListId, - 'valid_from' => \Carbon\Carbon::parse($bulkValidFrom)->toDateString(), + 'valid_from' => Carbon::parse($bulkValidFrom)->toDateString(), ]); $original = $price->exists ? clone $price : null; $price->price = $bulkPrice; - $price->valid_to = $bulkValidTo ? \Carbon\Carbon::parse($bulkValidTo)->toDateString() : null; + $price->valid_to = $bulkValidTo ? Carbon::parse($bulkValidTo)->toDateString() : null; $price->tax_included = (bool) $bulkTaxIncluded; $price->save(); @@ -220,7 +225,7 @@ public function apply(array $data, iterable $products): array if ($changed) { $successCount++; } - } catch (\Throwable $e) { + } catch (Throwable $e) { $errors[] = $e->getMessage(); Log::error('Bulk product update failed', [ 'product_id' => $product->id ?? null, diff --git a/src/Traits/HandlesTenantData.php b/src/Traits/HandlesTenantData.php index df5be49..24952dc 100644 --- a/src/Traits/HandlesTenantData.php +++ b/src/Traits/HandlesTenantData.php @@ -2,6 +2,8 @@ namespace Eclipse\Catalogue\Traits; +use Illuminate\Validation\ValidationException; + /** * Page-level helpers for Filament resources to handle per-tenant form state. * @@ -172,7 +174,7 @@ protected function validateTenantDataConstraints(array $tenantData): void foreach ($activeFlags as $flag) { $errors[$flag] = 'These options cannot be enabled simultaneously.'; } - throw \Illuminate\Validation\ValidationException::withMessages($errors); + throw ValidationException::withMessages($errors); } } @@ -204,7 +206,7 @@ protected function validateTenantDataConstraints(array $tenantData): void } if (! empty($errors)) { - throw \Illuminate\Validation\ValidationException::withMessages($errors); + throw ValidationException::withMessages($errors); } } diff --git a/src/Traits/HasPriceListForm.php b/src/Traits/HasPriceListForm.php index d6defa6..ff1bf9f 100644 --- a/src/Traits/HasPriceListForm.php +++ b/src/Traits/HasPriceListForm.php @@ -3,15 +3,15 @@ namespace Eclipse\Catalogue\Traits; use Eclipse\Catalogue\Forms\Components\GenericTenantFieldsComponent; -use Filament\Forms\Components\Fieldset; -use Filament\Forms\Components\Grid; -use Filament\Forms\Components\Section; use Filament\Forms\Components\Select; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; use Filament\Forms\Form; use Filament\Notifications\Notification; +use Filament\Schemas\Components\Fieldset; +use Filament\Schemas\Components\Grid; +use Filament\Schemas\Components\Section; trait HasPriceListForm { diff --git a/src/Traits/HasProductTypeForm.php b/src/Traits/HasProductTypeForm.php index 5e29ed6..65d4564 100644 --- a/src/Traits/HasProductTypeForm.php +++ b/src/Traits/HasProductTypeForm.php @@ -3,10 +3,10 @@ namespace Eclipse\Catalogue\Traits; use Eclipse\Catalogue\Forms\Components\GenericTenantFieldsComponent; -use Filament\Forms\Components\Grid; -use Filament\Forms\Components\Section; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; +use Filament\Schemas\Components\Grid; +use Filament\Schemas\Components\Section; trait HasProductTypeForm { diff --git a/src/Traits/HasTenantFields.php b/src/Traits/HasTenantFields.php index 8bad9d4..2adfb76 100644 --- a/src/Traits/HasTenantFields.php +++ b/src/Traits/HasTenantFields.php @@ -2,6 +2,8 @@ namespace Eclipse\Catalogue\Traits; +use Filament\Facades\Filament; + trait HasTenantFields { /** @@ -17,6 +19,6 @@ protected function isTenancyEnabled(): bool */ protected function getCurrentTenantId(): ?int { - return \Filament\Facades\Filament::getTenant()?->id; + return Filament::getTenant()?->id; } } diff --git a/src/Traits/HasTenantScopedData.php b/src/Traits/HasTenantScopedData.php index 71662a3..f6adf17 100644 --- a/src/Traits/HasTenantScopedData.php +++ b/src/Traits/HasTenantScopedData.php @@ -3,7 +3,10 @@ namespace Eclipse\Catalogue\Traits; use Filament\Facades\Filament; +use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Validation\ValidationException; +use ReflectionClass; /** * Adds per-tenant data behavior to an Eloquent model. @@ -52,7 +55,7 @@ public function getTenantDataRelation(): HasMany */ protected function getTenantDataRelationName(): string { - $reflection = new \ReflectionClass(static::class); + $reflection = new ReflectionClass(static::class); $property = $reflection->getProperty('tenantDataRelation'); $property->setAccessible(true); @@ -64,7 +67,7 @@ protected function getTenantDataRelationName(): string */ protected function getTenantDataModelClass(): string { - $reflection = new \ReflectionClass(static::class); + $reflection = new ReflectionClass(static::class); $property = $reflection->getProperty('tenantDataModel'); $property->setAccessible(true); @@ -76,7 +79,7 @@ protected function getTenantDataModelClass(): string */ protected function getTenantFlags(): array { - $reflection = new \ReflectionClass(static::class); + $reflection = new ReflectionClass(static::class); $property = $reflection->getProperty('tenantFlags'); $property->setAccessible(true); @@ -88,7 +91,7 @@ protected function getTenantFlags(): array */ protected function getMutuallyExclusiveFlagSets(): array { - $reflection = new \ReflectionClass(static::class); + $reflection = new ReflectionClass(static::class); $property = $reflection->getProperty('mutuallyExclusiveFlagSets'); $property->setAccessible(true); @@ -100,7 +103,7 @@ protected function getMutuallyExclusiveFlagSets(): array */ protected static function getStaticMutuallyExclusiveFlagSets(): array { - $reflection = new \ReflectionClass(static::class); + $reflection = new ReflectionClass(static::class); $property = $reflection->getProperty('mutuallyExclusiveFlagSets'); $property->setAccessible(true); @@ -112,7 +115,7 @@ protected static function getStaticMutuallyExclusiveFlagSets(): array */ protected function getUniqueFlagsPerTenant(): array { - $reflection = new \ReflectionClass(static::class); + $reflection = new ReflectionClass(static::class); $property = $reflection->getProperty('uniqueFlagsPerTenant'); $property->setAccessible(true); @@ -124,7 +127,7 @@ protected function getUniqueFlagsPerTenant(): array */ protected function getTenantAttributes(): array { - $reflection = new \ReflectionClass(static::class); + $reflection = new ReflectionClass(static::class); if ($reflection->hasProperty('tenantAttributes')) { $property = $reflection->getProperty('tenantAttributes'); $property->setAccessible(true); @@ -149,7 +152,7 @@ protected function filterTenantDataForPersistence(array $tenantData): array // Second pass: ensure only fillable keys for data model persist $dataModelClass = $this->getTenantDataModelClass(); - /** @var \Illuminate\Database\Eloquent\Model $dataModel */ + /** @var Model $dataModel */ $dataModel = new $dataModelClass; $fillable = array_flip($dataModel->getFillable()); @@ -379,7 +382,7 @@ public function handleDefaultConstraints(array &$tenantData, ?int $tenantId): vo foreach ($activeFlags as $flag) { $errors[$errorKey ? "{$errorKey}.{$flag}" : $flag] = 'These options cannot be enabled simultaneously.'; } - throw \Illuminate\Validation\ValidationException::withMessages($errors); + throw ValidationException::withMessages($errors); } } @@ -422,7 +425,7 @@ public static function validateTenantDataConstraints(array $tenantData): void foreach ($activeFlags as $flag) { $errors[$flag] = 'These options cannot be enabled simultaneously.'; } - throw \Illuminate\Validation\ValidationException::withMessages($errors); + throw ValidationException::withMessages($errors); } } @@ -454,7 +457,7 @@ public static function validateTenantDataConstraints(array $tenantData): void } if (! empty($errors)) { - throw \Illuminate\Validation\ValidationException::withMessages($errors); + throw ValidationException::withMessages($errors); } } } diff --git a/tests/Feature/CategoryResourceTest.php b/tests/Feature/CategoryResourceTest.php index 97d2f50..8305f86 100644 --- a/tests/Feature/CategoryResourceTest.php +++ b/tests/Feature/CategoryResourceTest.php @@ -1,6 +1,8 @@ definition(); - Livewire::test(CategoryResource\Pages\CreateCategory::class) + Livewire::test(CreateCategory::class) ->fillForm([ 'name' => $factoryData['name']['en'], 'sef_key' => $factoryData['sef_key']['en'], @@ -39,7 +41,7 @@ it('can edit category', function (): void { $category = Category::factory()->create(); - Livewire::test(CategoryResource\Pages\EditCategory::class, [ + Livewire::test(EditCategory::class, [ 'record' => $category->getRouteKey(), ]) ->fillForm([ @@ -57,7 +59,7 @@ it('can delete category', function (): void { $category = Category::factory()->create(); - Livewire::test(CategoryResource\Pages\EditCategory::class, [ + Livewire::test(EditCategory::class, [ 'record' => $category->getRouteKey(), ]) ->callAction('delete'); @@ -70,7 +72,7 @@ 'sef_key' => 'electronics', ]); - Livewire::test(CategoryResource\Pages\CreateCategory::class) + Livewire::test(CreateCategory::class) ->fillForm([ 'name' => 'New Category', 'sef_key' => 'electronics', @@ -86,7 +88,7 @@ 'parent_id' => $parent->id, ]); - Livewire::test(CategoryResource\Pages\EditCategory::class, [ + Livewire::test(EditCategory::class, [ 'record' => $parent->getRouteKey(), ]) ->fillForm([ diff --git a/tests/Feature/GroupCodeUniquenessTest.php b/tests/Feature/GroupCodeUniquenessTest.php index a6af3b4..885b31c 100644 --- a/tests/Feature/GroupCodeUniquenessTest.php +++ b/tests/Feature/GroupCodeUniquenessTest.php @@ -1,6 +1,7 @@ migrate(); @@ -55,7 +56,7 @@ 'code' => 'unique-code', 'name' => 'Second Group', 'is_active' => true, - ]))->toThrow(\Illuminate\Database\QueryException::class); + ]))->toThrow(QueryException::class); }); it('allows updating group with same code on same site', function () { diff --git a/tests/Feature/ImportColorValuesTest.php b/tests/Feature/ImportColorValuesTest.php index 380f9df..e622f32 100644 --- a/tests/Feature/ImportColorValuesTest.php +++ b/tests/Feature/ImportColorValuesTest.php @@ -5,6 +5,7 @@ use Eclipse\Catalogue\Models\Property; use Eclipse\Catalogue\Models\PropertyValue; use Eclipse\Catalogue\Values\Background; +use Eclipse\Common\Enums\JobStatus; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Queue; use Illuminate\Support\Facades\Storage; @@ -131,7 +132,7 @@ function runImportJob(ImportColorValues $job): void // Set job status to completed to get notification body $statusProperty = $reflection->getProperty('status'); $statusProperty->setAccessible(true); - $statusProperty->setValue($job, \Eclipse\Common\Enums\JobStatus::COMPLETED); + $statusProperty->setValue($job, JobStatus::COMPLETED); // Access protected method via reflection $method = $reflection->getMethod('getNotificationBody'); diff --git a/tests/Feature/PriceListTest.php b/tests/Feature/PriceListTest.php index 385d859..f01287e 100644 --- a/tests/Feature/PriceListTest.php +++ b/tests/Feature/PriceListTest.php @@ -1,5 +1,6 @@ logout(); - $this->get(\Eclipse\Catalogue\Filament\Resources\PriceListResource::getUrl()) + $this->get(PriceListResource::getUrl()) ->assertRedirect(); // Should redirect to login }); diff --git a/tests/Feature/ProductBulkUpdateTest.php b/tests/Feature/ProductBulkUpdateTest.php index 081daf1..5b4345a 100644 --- a/tests/Feature/ProductBulkUpdateTest.php +++ b/tests/Feature/ProductBulkUpdateTest.php @@ -5,9 +5,13 @@ use Eclipse\Catalogue\Models\Group; use Eclipse\Catalogue\Models\PriceList; use Eclipse\Catalogue\Models\Product; +use Eclipse\Catalogue\Models\Product\Price; use Eclipse\Catalogue\Models\ProductData; +use Eclipse\Catalogue\Models\ProductType; use Eclipse\Catalogue\Services\ProductBulkUpdater; +use Filament\Facades\Filament; use Illuminate\Foundation\Testing\RefreshDatabase; +use Workbench\App\Models\Site; uses(RefreshDatabase::class); @@ -23,7 +27,7 @@ it('respects no-change vs blank update for category and toggle fields', function (): void { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); - $siteId = \Workbench\App\Models\Site::first()->id; + $siteId = Site::first()->id; $catA = Category::factory()->create(); $product = Product::factory()->create(); @@ -62,9 +66,9 @@ it('groups add/remove are tenant-aware', function (): void { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); - $site = \Filament\Facades\Filament::getTenant(); + $site = Filament::getTenant(); - $otherSite = \Workbench\App\Models\Site::factory()->create(); + $otherSite = Site::factory()->create(); // Group for current tenant $gCurrent = Group::factory()->create([$tenantFK => $site->id, 'is_active' => true]); @@ -99,7 +103,7 @@ it('inserts price correctly', function (): void { $tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id'); - $site = \Filament\Facades\Filament::getTenant(); + $site = Filament::getTenant(); $priceList = PriceList::factory()->create(); // Enable list for current tenant @@ -120,7 +124,7 @@ ], [$product]); expect($result['successCount'])->toBe(1); - $price = \Eclipse\Catalogue\Models\Product\Price::query() + $price = Price::query() ->where('product_id', $product->id) ->where('price_list_id', $priceList->id) ->whereDate('valid_from', $today) @@ -132,12 +136,12 @@ }); it('rolls back only the failing product inside per-product transaction', function (): void { - $type = \Eclipse\Catalogue\Models\ProductType::factory()->create(); + $type = ProductType::factory()->create(); $p1 = Product::factory()->create(['product_type_id' => $type->id]); $p2 = Product::factory()->create(['product_type_id' => $type->id]); // Make saving p1 fail when changing product type - \Eclipse\Catalogue\Models\Product::saving(function ($model) use ($p1) { + Product::saving(function ($model) use ($p1) { if ($model->id === $p1->id && $model->isDirty('product_type_id')) { throw new Exception('Induced failure'); } diff --git a/tests/Feature/ProductPriceTest.php b/tests/Feature/ProductPriceTest.php index 8796cf0..1c7faf2 100644 --- a/tests/Feature/ProductPriceTest.php +++ b/tests/Feature/ProductPriceTest.php @@ -5,8 +5,10 @@ use Eclipse\Catalogue\Models\Product\Price as ProductPrice; use Eclipse\World\Models\Currency; use Illuminate\Database\QueryException; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Carbon; -uses(\Illuminate\Foundation\Testing\RefreshDatabase::class); +uses(RefreshDatabase::class); beforeEach(function () { Currency::create(['id' => 'USD', 'name' => 'US Dollar', 'is_active' => true]); @@ -42,7 +44,7 @@ function makePriceList(array $attrs = []): PriceList expect($price)->toBeInstanceOf(ProductPrice::class); expect($price->price)->toBeFloat(); expect($price->tax_included)->toBeTrue(); - expect($price->valid_from)->toBeInstanceOf(\Illuminate\Support\Carbon::class); + expect($price->valid_from)->toBeInstanceOf(Carbon::class); expect($price->valid_to)->toBeNull(); }); diff --git a/tests/Feature/ProductResourceTest.php b/tests/Feature/ProductResourceTest.php index 1c7cb4b..a243d0b 100644 --- a/tests/Feature/ProductResourceTest.php +++ b/tests/Feature/ProductResourceTest.php @@ -1,6 +1,6 @@ true, ]); - Livewire::test(ProductResource\Pages\ListProducts::class) + Livewire::test(ListProducts::class) ->filterTable('category_id', [$electronics->id]) ->assertCanSeeTableRecords([$laptop]) ->assertCanNotSeeTableRecords([$novel, $orphanProduct]); diff --git a/tests/Feature/ProductStatusCrudTest.php b/tests/Feature/ProductStatusCrudTest.php index 48a9c93..5082c87 100644 --- a/tests/Feature/ProductStatusCrudTest.php +++ b/tests/Feature/ProductStatusCrudTest.php @@ -1,11 +1,12 @@ migrate(); $this->setUpSuperAdminAndTenant(); - $this->site = \Workbench\App\Models\Site::first(); + $this->site = Site::first(); }); it('can create a product status', function () { diff --git a/tests/Feature/ProductStatusLabelRenderingTest.php b/tests/Feature/ProductStatusLabelRenderingTest.php index 3ce350e..fe05bc7 100644 --- a/tests/Feature/ProductStatusLabelRenderingTest.php +++ b/tests/Feature/ProductStatusLabelRenderingTest.php @@ -2,11 +2,12 @@ use Eclipse\Catalogue\Models\ProductStatus; use Eclipse\Catalogue\Support\LabelType; +use Workbench\App\Models\Site; beforeEach(function () { $this->migrate(); $this->setUpSuperAdminAndTenant(); - $this->site = \Workbench\App\Models\Site::first(); + $this->site = Site::first(); }); it('renders correct badge class for each label type', function () { diff --git a/tests/Feature/ProductStatusUniquenessTest.php b/tests/Feature/ProductStatusUniquenessTest.php index 056340f..5e08885 100644 --- a/tests/Feature/ProductStatusUniquenessTest.php +++ b/tests/Feature/ProductStatusUniquenessTest.php @@ -1,12 +1,13 @@ migrate(); $this->setUpSuperAdminAndTenant(); - $this->site = \Workbench\App\Models\Site::first(); + $this->site = Site::first(); }); it('enforces unique code per site', function () { @@ -30,7 +31,7 @@ 'priority' => 2, 'sd_item_availability' => 'InStock', ]); - })->toThrow(\Illuminate\Database\QueryException::class); + })->toThrow(QueryException::class); }); it('allows same code for different sites', function () { diff --git a/tests/Feature/ProductStatusValidationTest.php b/tests/Feature/ProductStatusValidationTest.php index ae2f804..c8c5b77 100644 --- a/tests/Feature/ProductStatusValidationTest.php +++ b/tests/Feature/ProductStatusValidationTest.php @@ -1,11 +1,12 @@ migrate(); $this->setUpSuperAdminAndTenant(); - $this->site = \Workbench\App\Models\Site::first(); + $this->site = Site::first(); }); it('enforces allow_sale false when allow_price_display is false', function () { @@ -54,7 +55,7 @@ 'site_id' => $this->site->id, // Missing required fields: code, title, label_type, priority, sd_item_availability ]); - })->toThrow(\Exception::class); + })->toThrow(Exception::class); }); it('validates code length limit', function () { @@ -67,5 +68,5 @@ 'priority' => 1, 'sd_item_availability' => 'InStock', ]); - })->toThrow(\Exception::class); + })->toThrow(Exception::class); }); diff --git a/tests/Feature/ProductTypeTest.php b/tests/Feature/ProductTypeTest.php index de85b54..79a0b38 100644 --- a/tests/Feature/ProductTypeTest.php +++ b/tests/Feature/ProductTypeTest.php @@ -1,7 +1,10 @@ logout(); - $this->get(\Eclipse\Catalogue\Filament\Resources\ProductTypeResource::getUrl()) + $this->get(ProductTypeResource::getUrl()) ->assertRedirect(); // Should redirect to login }); @@ -116,7 +119,7 @@ function createTypeData(array $attributes): ProductTypeData expect($type->getTranslation('name', 'en'))->toBeString(); expect($type->code)->toBeString(); - expect($type->created_at)->toBeInstanceOf(\Illuminate\Support\Carbon::class); + expect($type->created_at)->toBeInstanceOf(Carbon::class); }); // Default Type Tests @@ -254,8 +257,8 @@ function createTypeData(array $attributes): ProductTypeData expect($translations)->toHaveKey('en'); // Should have translations for all available locales - if (class_exists(\Eclipse\Core\Models\Locale::class)) { - $availableLocales = \Eclipse\Core\Models\Locale::getAvailableLocales() + if (class_exists(Locale::class)) { + $availableLocales = Locale::getAvailableLocales() ->pluck('id') ->toArray(); diff --git a/tests/Feature/PropertyValidationTest.php b/tests/Feature/PropertyValidationTest.php index eb176b5..6f68800 100644 --- a/tests/Feature/PropertyValidationTest.php +++ b/tests/Feature/PropertyValidationTest.php @@ -1,7 +1,9 @@ migrate(); @@ -20,7 +22,7 @@ 'enable_sorting' => false, 'is_filter' => false, ]); - })->toThrow(\Illuminate\Database\QueryException::class); + })->toThrow(QueryException::class); }); it('allows null property codes', function () { @@ -68,7 +70,7 @@ 'enable_sorting' => false, 'is_filter' => false, ]); - })->toThrow(\Illuminate\Database\QueryException::class); + })->toThrow(QueryException::class); }); it('validates property value belongs to property', function () { @@ -83,7 +85,7 @@ }); it('validates unique product property value assignment', function () { - $product = \Eclipse\Catalogue\Models\Product::factory()->create(); + $product = Product::factory()->create(); $property = Property::factory()->create(); $value = PropertyValue::factory()->create(['property_id' => $property->id]); @@ -94,7 +96,7 @@ // Duplicate assignment should be prevented by unique constraint expect(function () use ($product, $value) { $product->propertyValues()->attach($value->id); - })->toThrow(\Illuminate\Database\QueryException::class); + })->toThrow(QueryException::class); }); it('validates property value sort order is numeric', function () { diff --git a/tests/Feature/PropertyValueColorFormTest.php b/tests/Feature/PropertyValueColorFormTest.php index 91be984..2fc35ed 100644 --- a/tests/Feature/PropertyValueColorFormTest.php +++ b/tests/Feature/PropertyValueColorFormTest.php @@ -1,12 +1,19 @@ migrate(); }); it('builds color group schema correctly', function () { // Test that color form fields are properly structured - $resource = new \Eclipse\Catalogue\Filament\Resources\PropertyValueResource; + $resource = new PropertyValueResource; $reflection = new ReflectionClass($resource); $method = $reflection->getMethod('buildColorGroupSchema'); $method->setAccessible(true); @@ -15,22 +22,22 @@ // Should return one main group component expect($colorGroupSchema)->toHaveCount(1); - expect($colorGroupSchema[0])->toBeInstanceOf(\Filament\Forms\Components\Group::class); + expect($colorGroupSchema[0])->toBeInstanceOf(Group::class); // Group should contain 4 form components $groupSchema = $colorGroupSchema[0]->getChildComponents(); expect($groupSchema)->toHaveCount(4); // Verify component types: Radio (background type), ColorPicker, Grid (gradient), ViewField (preview) - expect($groupSchema[0])->toBeInstanceOf(\Filament\Forms\Components\Radio::class); - expect($groupSchema[1])->toBeInstanceOf(\Filament\Forms\Components\ColorPicker::class); - expect($groupSchema[2])->toBeInstanceOf(\Filament\Forms\Components\Grid::class); - expect($groupSchema[3])->toBeInstanceOf(\Filament\Forms\Components\ViewField::class); + expect($groupSchema[0])->toBeInstanceOf(Radio::class); + expect($groupSchema[1])->toBeInstanceOf(ColorPicker::class); + expect($groupSchema[2])->toBeInstanceOf(Grid::class); + expect($groupSchema[3])->toBeInstanceOf(ViewField::class); }); it('configures color picker component', function () { // Test that the color picker is properly configured for solid colors - $resource = new \Eclipse\Catalogue\Filament\Resources\PropertyValueResource; + $resource = new PropertyValueResource; $reflection = new ReflectionClass($resource); $method = $reflection->getMethod('buildColorGroupSchema'); $method->setAccessible(true); @@ -39,13 +46,13 @@ $groupSchema = $colorGroupSchema[0]->getChildComponents(); $colorPicker = $groupSchema[1]; - expect($colorPicker)->toBeInstanceOf(\Filament\Forms\Components\ColorPicker::class); + expect($colorPicker)->toBeInstanceOf(ColorPicker::class); expect($colorPicker->getName())->toBe('color'); }); it('configures gradient grid component', function () { // Test that gradient controls are properly structured - $resource = new \Eclipse\Catalogue\Filament\Resources\PropertyValueResource; + $resource = new PropertyValueResource; $reflection = new ReflectionClass($resource); $method = $reflection->getMethod('buildColorGroupSchema'); $method->setAccessible(true); @@ -54,7 +61,7 @@ $groupSchema = $colorGroupSchema[0]->getChildComponents(); $gradientGrid = $groupSchema[2]; - expect($gradientGrid)->toBeInstanceOf(\Filament\Forms\Components\Grid::class); + expect($gradientGrid)->toBeInstanceOf(Grid::class); // Should contain color_start, color_end, gradient_direction, gradient_style $gridChildren = $gradientGrid->getChildComponents(); @@ -63,7 +70,7 @@ it('configures color preview component', function () { // Test that the color preview field is properly set up - $resource = new \Eclipse\Catalogue\Filament\Resources\PropertyValueResource; + $resource = new PropertyValueResource; $reflection = new ReflectionClass($resource); $method = $reflection->getMethod('buildColorGroupSchema'); $method->setAccessible(true); @@ -72,6 +79,6 @@ $groupSchema = $colorGroupSchema[0]->getChildComponents(); $previewField = $groupSchema[3]; - expect($previewField)->toBeInstanceOf(\Filament\Forms\Components\ViewField::class); + expect($previewField)->toBeInstanceOf(ViewField::class); expect($previewField->getName())->toBe('preview'); }); diff --git a/tests/Pest.php b/tests/Pest.php index 777e215..8943345 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,5 +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, ]); }) ->in(__DIR__); diff --git a/tests/Unit/ColorBackgroundTest.php b/tests/Unit/ColorBackgroundTest.php index a622724..f3e21eb 100644 --- a/tests/Unit/ColorBackgroundTest.php +++ b/tests/Unit/ColorBackgroundTest.php @@ -26,7 +26,7 @@ // Test invalid types throw exception expect(function () { Property::factory()->create(['type' => 'invalid']); - })->toThrow(\InvalidArgumentException::class, 'Invalid type'); + })->toThrow(InvalidArgumentException::class, 'Invalid type'); }); it('validates background type enum constraints', function () { diff --git a/workbench/app/Providers/AdminPanelProvider.php b/workbench/app/Providers/AdminPanelProvider.php index 225ae9a..3a65f0d 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 Filament\Support\Facades\FilamentView; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Cookie\Middleware\EncryptCookies; @@ -20,6 +19,7 @@ use Illuminate\Session\Middleware\StartSession; use Illuminate\Support\Facades\Blade; use Illuminate\View\Middleware\ShareErrorsFromSession; +use LaraZeus\SpatieTranslatable\SpatieTranslatablePlugin; class AdminPanelProvider extends PanelProvider { @@ -47,7 +47,7 @@ public function panel(Panel $panel): Panel ->plugins([ FilamentShieldPlugin::make(), CataloguePlugin::make(), - SpatieLaravelTranslatablePlugin::make() + SpatieTranslatablePlugin::make() ->defaultLocales(['en']), ]) ->pages([ 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 { From e7516272de918651921d3bb36648413f23373f64 Mon Sep 17 00:00:00 2001 From: Kilian Trunk Date: Thu, 25 Sep 2025 10:02:15 +0200 Subject: [PATCH 2/7] chore: fix tests setup --- tests/Pest.php | 15 +++++----- tests/TestCase.php | 75 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/tests/Pest.php b/tests/Pest.php index 8943345..d296adf 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,7 +1,6 @@ use(RefreshDatabase::class) ->beforeEach(function () { - // Seed roles and permissions with Filament Shield plugin - Artisan::call('shield:generate', [ - '--all' => null, - '--panel' => 'admin', - '--option' => 'permissions', - ]); + // 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 ee6d94c..a3f7045 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -56,8 +56,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); @@ -92,6 +100,69 @@ protected function setUpCommonUser(): self return $this; } + /** + * Create permissions for all resources + */ + protected function createPermissions(): self + { + $resources = [ + 'category', + 'custom::property', + 'group', + 'measure::unit', + 'price::list', + 'product', + 'product::status', + 'product::type', + 'property', + 'property::value', + 'role', + 'tax::class', + ]; + + $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::firstOrCreate([ + 'name' => $permission.'_'.$resource, + 'guard_name' => 'web', + ]); + } + } + + return $this; + } + + /** + * Create roles + */ + protected function createRoles(): self + { + \Spatie\Permission\Models\Role::firstOrCreate([ + 'name' => 'super_admin', + 'guard_name' => 'web', + ]); + + \Spatie\Permission\Models\Role::firstOrCreate([ + 'name' => 'panel_user', + 'guard_name' => 'web', + ]); + + return $this; + } + public function ignorePackageDiscoveriesFrom() { return [ From 12d24d88f6dca974a8432bd326617e70130b0d8f Mon Sep 17 00:00:00 2001 From: Kilian Trunk Date: Thu, 25 Sep 2025 10:58:52 +0200 Subject: [PATCH 3/7] chore: test fixes --- tests/Feature/MeasureUnitPermissionTest.php | 3 +++ tests/Feature/TaxClassPermissionTest.php | 3 +++ tests/TestCase.php | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/tests/Feature/MeasureUnitPermissionTest.php b/tests/Feature/MeasureUnitPermissionTest.php index 1521087..74955a9 100644 --- a/tests/Feature/MeasureUnitPermissionTest.php +++ b/tests/Feature/MeasureUnitPermissionTest.php @@ -75,6 +75,9 @@ $this->assertSoftDeleted($measureUnit); livewire(ListMeasureUnits::class) + ->filterTable('trashed') + ->assertTableActionExists('restore') + ->assertTableActionExists('forceDelete') ->assertTableActionDisabled('restore', $measureUnit) ->assertTableActionDisabled('forceDelete', $measureUnit); }); diff --git a/tests/Feature/TaxClassPermissionTest.php b/tests/Feature/TaxClassPermissionTest.php index 2b1495a..d3753c5 100644 --- a/tests/Feature/TaxClassPermissionTest.php +++ b/tests/Feature/TaxClassPermissionTest.php @@ -82,6 +82,9 @@ $this->assertSoftDeleted($taxClass); livewire(ListTaxClasses::class) + ->filterTable('trashed') + ->assertTableActionExists('restore') + ->assertTableActionExists('forceDelete') ->assertTableActionDisabled('restore', $taxClass) ->assertTableActionDisabled('forceDelete', $taxClass); }); diff --git a/tests/TestCase.php b/tests/TestCase.php index a3f7045..94960f5 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -18,6 +18,11 @@ abstract class TestCase extends BaseTestCase protected ?Site $site = null; + protected function getEnvironmentSetUp($app): void + { + $app['config']->set('filament-shield.register_role_policy', false); + } + protected function setUp(): void { // Always show errors when testing From 0072ad234e198cf2b04974cdf74c70802f1939a6 Mon Sep 17 00:00:00 2001 From: Kilian Trunk Date: Mon, 6 Oct 2025 13:46:15 +0200 Subject: [PATCH 4/7] chore: ci & test & permission fixes --- .github/workflows/test-runner.yml | 8 +- config/filament-shield.php | 206 ++++++++++++++++++ src/Filament/Resources/CategoryResource.php | 19 +- src/Filament/Resources/GroupResource.php | 15 +- .../Resources/MeasureUnitResource.php | 19 +- src/Filament/Resources/PriceListResource.php | 19 +- src/Filament/Resources/ProductResource.php | 19 +- .../Resources/ProductStatusResource.php | 15 +- .../Resources/ProductTypeResource.php | 19 +- src/Filament/Resources/PropertyResource.php | 19 +- src/Filament/Resources/TaxClassResource.php | 19 +- src/Policies/CategoryPolicy.php | 24 +- src/Policies/GroupPolicy.php | 24 +- src/Policies/MeasureUnitPolicy.php | 44 ++-- src/Policies/PriceListPolicy.php | 44 ++-- src/Policies/ProductPolicy.php | 24 +- src/Policies/ProductStatusPolicy.php | 28 +-- src/Policies/ProductTypePolicy.php | 52 ++--- src/Policies/PropertyPolicy.php | 24 +- src/Policies/TaxClassPolicy.php | 44 ++-- tests/Feature/MeasureUnitPermissionTest.php | 2 +- tests/Feature/PropertyValueColorFormTest.php | 10 +- tests/Feature/TaxClassPermissionTest.php | 8 +- tests/TestCase.php | 13 +- 24 files changed, 396 insertions(+), 322 deletions(-) create mode 100644 config/filament-shield.php diff --git a/.github/workflows/test-runner.yml b/.github/workflows/test-runner.yml index 17f7917..2e0de36 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/config/filament-shield.php b/config/filament-shield.php new file mode 100644 index 0000000..837a1c1 --- /dev/null +++ b/config/filament-shield.php @@ -0,0 +1,206 @@ + [ + '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' => 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', + ], + ], + + 'localization' => [ + 'enabled' => false, + 'key' => 'filament-shield::filament-shield', + ], + + 'resources' => [ + 'subject' => 'model', + 'manage' => [ + ProductResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + CategoryResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + ProductTypeResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + PropertyResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + 'restore', + 'restoreAny', + ], + PropertyValueResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'delete', + 'deleteAny', + ], + GroupResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'delete', + 'deleteAny', + ], + PriceListResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + MeasureUnitResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + TaxClassResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + ProductStatusResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'delete', + 'deleteAny', + ], + ], + '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/Filament/Resources/CategoryResource.php b/src/Filament/Resources/CategoryResource.php index 9fe04d7..404454a 100644 --- a/src/Filament/Resources/CategoryResource.php +++ b/src/Filament/Resources/CategoryResource.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages\CreateCategory; use Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages\EditCategory; use Eclipse\Catalogue\Filament\Resources\CategoryResource\Pages\ListCategories; @@ -45,7 +44,7 @@ use Illuminate\Support\Str; use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; -class CategoryResource extends Resource implements HasShieldPermissions +class CategoryResource extends Resource { use Translatable; @@ -388,20 +387,4 @@ public static function getGloballySearchableAttributes(): array { return ['name', 'short_desc', 'description', 'sef_key', 'code']; } - - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'view', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } } diff --git a/src/Filament/Resources/GroupResource.php b/src/Filament/Resources/GroupResource.php index 31226e7..0c63c9f 100644 --- a/src/Filament/Resources/GroupResource.php +++ b/src/Filament/Resources/GroupResource.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\Catalogue\Filament\Resources\GroupResource\Pages\CreateGroup; use Eclipse\Catalogue\Filament\Resources\GroupResource\Pages\EditGroup; use Eclipse\Catalogue\Filament\Resources\GroupResource\Pages\ListGroups; @@ -28,7 +27,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; -class GroupResource extends Resource implements HasShieldPermissions +class GroupResource extends Resource { protected static ?string $model = Group::class; @@ -185,16 +184,4 @@ public static function getGlobalSearchResultDetails(Model $record): array 'Code' => $record->code, ]); } - - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'view', - 'create', - 'update', - 'delete', - 'delete_any', - ]; - } } diff --git a/src/Filament/Resources/MeasureUnitResource.php b/src/Filament/Resources/MeasureUnitResource.php index 2f9d3d8..3751761 100644 --- a/src/Filament/Resources/MeasureUnitResource.php +++ b/src/Filament/Resources/MeasureUnitResource.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\Catalogue\Filament\Resources\MeasureUnitResource\Pages\CreateMeasureUnit; use Eclipse\Catalogue\Filament\Resources\MeasureUnitResource\Pages\EditMeasureUnit; use Eclipse\Catalogue\Filament\Resources\MeasureUnitResource\Pages\ListMeasureUnits; @@ -23,7 +22,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; -class MeasureUnitResource extends Resource implements HasShieldPermissions +class MeasureUnitResource extends Resource { protected static ?string $model = MeasureUnit::class; @@ -122,20 +121,4 @@ public static function getEloquentQuery(): Builder SoftDeletingScope::class, ]); } - - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'view', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } } diff --git a/src/Filament/Resources/PriceListResource.php b/src/Filament/Resources/PriceListResource.php index b1a7335..02925ef 100644 --- a/src/Filament/Resources/PriceListResource.php +++ b/src/Filament/Resources/PriceListResource.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\Catalogue\Filament\Resources\PriceListResource\Pages\CreatePriceList; use Eclipse\Catalogue\Filament\Resources\PriceListResource\Pages\EditPriceList; use Eclipse\Catalogue\Filament\Resources\PriceListResource\Pages\ListPriceLists; @@ -20,7 +19,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; -class PriceListResource extends Resource implements HasShieldPermissions +class PriceListResource extends Resource { protected static ?string $model = PriceList::class; @@ -122,20 +121,4 @@ public static function getEloquentQuery(): Builder SoftDeletingScope::class, ]); } - - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'view', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } } diff --git a/src/Filament/Resources/ProductResource.php b/src/Filament/Resources/ProductResource.php index 41c9b1b..80caef9 100644 --- a/src/Filament/Resources/ProductResource.php +++ b/src/Filament/Resources/ProductResource.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\Catalogue\Enums\PropertyInputType; use Eclipse\Catalogue\Filament\Filters\CustomPropertyConstraint; use Eclipse\Catalogue\Filament\Forms\Components\ImageManager; @@ -64,7 +63,7 @@ use Illuminate\Database\Eloquent\SoftDeletingScope; use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; -class ProductResource extends Resource implements HasShieldPermissions +class ProductResource extends Resource { use HandlesTenantData, HasTenantFields, Translatable; @@ -999,22 +998,6 @@ protected static function getPlaceholderImageUrl(): string return 'data:image/svg+xml;base64,'.base64_encode($svg); } - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'view', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } - protected static function getCustomPropertyColumns(): array { $customProperties = Property::where('type', 'custom')->get(); diff --git a/src/Filament/Resources/ProductStatusResource.php b/src/Filament/Resources/ProductStatusResource.php index 8122cfe..71c83e1 100644 --- a/src/Filament/Resources/ProductStatusResource.php +++ b/src/Filament/Resources/ProductStatusResource.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\Catalogue\Enums\StructuredData\ItemAvailability; use Eclipse\Catalogue\Filament\Resources\ProductStatusResource\Pages\CreateProductStatus; use Eclipse\Catalogue\Filament\Resources\ProductStatusResource\Pages\EditProductStatus; @@ -29,7 +28,7 @@ use Illuminate\Support\HtmlString; use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; -class ProductStatusResource extends Resource implements HasShieldPermissions +class ProductStatusResource extends Resource { use Translatable; @@ -178,16 +177,4 @@ public static function getEloquentQuery(): Builder return $query; } - - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'view', - 'create', - 'update', - 'delete', - 'delete_any', - ]; - } } diff --git a/src/Filament/Resources/ProductTypeResource.php b/src/Filament/Resources/ProductTypeResource.php index 6a7830e..424b466 100644 --- a/src/Filament/Resources/ProductTypeResource.php +++ b/src/Filament/Resources/ProductTypeResource.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\Catalogue\Filament\Resources\ProductTypeResource\Pages\CreateProductType; use Eclipse\Catalogue\Filament\Resources\ProductTypeResource\Pages\EditProductType; use Eclipse\Catalogue\Filament\Resources\ProductTypeResource\Pages\ListProductTypes; @@ -22,7 +21,7 @@ use Illuminate\Database\Eloquent\SoftDeletingScope; use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; -class ProductTypeResource extends Resource implements HasShieldPermissions +class ProductTypeResource extends Resource { use Translatable; @@ -119,20 +118,4 @@ public static function getEloquentQuery(): Builder SoftDeletingScope::class, ]); } - - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'view', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } } diff --git a/src/Filament/Resources/PropertyResource.php b/src/Filament/Resources/PropertyResource.php index 95c0970..95a7b8c 100644 --- a/src/Filament/Resources/PropertyResource.php +++ b/src/Filament/Resources/PropertyResource.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\Catalogue\Enums\PropertyInputType; use Eclipse\Catalogue\Enums\PropertyType; use Eclipse\Catalogue\Filament\Resources\PropertyResource\Pages\CreateProperty; @@ -33,7 +32,7 @@ use Filament\Tables\Table; use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable; -class PropertyResource extends Resource implements HasShieldPermissions +class PropertyResource extends Resource { use Translatable; @@ -269,20 +268,4 @@ public static function getPages(): array 'edit' => EditProperty::route('/{record}/edit'), ]; } - - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'view', - 'create', - 'update', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - 'restore', - 'restore_any', - ]; - } } diff --git a/src/Filament/Resources/TaxClassResource.php b/src/Filament/Resources/TaxClassResource.php index e8a3680..d82a6e9 100644 --- a/src/Filament/Resources/TaxClassResource.php +++ b/src/Filament/Resources/TaxClassResource.php @@ -2,7 +2,6 @@ namespace Eclipse\Catalogue\Filament\Resources; -use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions; use Eclipse\Catalogue\Filament\Resources\TaxClassResource\Pages\CreateTaxClass; use Eclipse\Catalogue\Filament\Resources\TaxClassResource\Pages\EditTaxClass; use Eclipse\Catalogue\Filament\Resources\TaxClassResource\Pages\ListTaxClasses; @@ -25,7 +24,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; -class TaxClassResource extends Resource implements HasShieldPermissions +class TaxClassResource extends Resource { protected static ?string $model = TaxClass::class; @@ -165,20 +164,4 @@ public static function getEloquentQuery(): Builder SoftDeletingScope::class, ]); } - - public static function getPermissionPrefixes(): array - { - return [ - 'view_any', - 'view', - 'create', - 'update', - 'restore', - 'restore_any', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ]; - } } diff --git a/src/Policies/CategoryPolicy.php b/src/Policies/CategoryPolicy.php index 5d5508b..40363ae 100644 --- a/src/Policies/CategoryPolicy.php +++ b/src/Policies/CategoryPolicy.php @@ -1,10 +1,12 @@ can('view_any_category'); } @@ -21,7 +23,7 @@ public function viewAny(Authorizable $user): bool /** * Determine whether the user can view the model. */ - public function view(Authorizable $user, Category $category): bool + public function view(AuthUser $user, Category $category): bool { return $user->can('view_category'); } @@ -29,7 +31,7 @@ public function view(Authorizable $user, Category $category): bool /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { return $user->can('create_category'); } @@ -37,7 +39,7 @@ public function create(Authorizable $user): bool /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, Category $category): bool + public function update(AuthUser $user, Category $category): bool { return $user->can('update_category'); } @@ -45,7 +47,7 @@ public function update(Authorizable $user, Category $category): bool /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, Category $category): bool + public function delete(AuthUser $user, Category $category): bool { return $user->can('delete_category'); } @@ -53,7 +55,7 @@ public function delete(Authorizable $user, Category $category): 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_category'); } @@ -61,7 +63,7 @@ public function deleteAny(Authorizable $user): bool /** * Determine whether the user can permanently delete. */ - public function forceDelete(Authorizable $user, Category $category): bool + public function forceDelete(AuthUser $user, Category $category): bool { return $user->can('force_delete_category'); } @@ -69,7 +71,7 @@ public function forceDelete(Authorizable $user, Category $category): 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_category'); } @@ -77,7 +79,7 @@ public function forceDeleteAny(Authorizable $user): bool /** * Determine whether the user can restore. */ - public function restore(Authorizable $user, Category $category): bool + public function restore(AuthUser $user, Category $category): bool { return $user->can('restore_category'); } @@ -85,7 +87,7 @@ public function restore(Authorizable $user, Category $category): 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_category'); } diff --git a/src/Policies/GroupPolicy.php b/src/Policies/GroupPolicy.php index 6fce310..e035bac 100644 --- a/src/Policies/GroupPolicy.php +++ b/src/Policies/GroupPolicy.php @@ -1,61 +1,63 @@ can('view_any_group'); } - public function view(Authorizable $user, Group $group): bool + public function view(AuthUser $user, Group $group): bool { return $user->can('view_group'); } - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { return $user->can('create_group'); } - public function update(Authorizable $user, Group $group): bool + public function update(AuthUser $user, Group $group): bool { return $user->can('update_group'); } - public function delete(Authorizable $user, Group $group): bool + public function delete(AuthUser $user, Group $group): bool { return $user->can('delete_group'); } - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { return $user->can('delete_any_group'); } - public function forceDelete(Authorizable $user, Group $group): bool + public function forceDelete(AuthUser $user, Group $group): bool { return $user->can('force_delete_group'); } - public function forceDeleteAny(Authorizable $user): bool + public function forceDeleteAny(AuthUser $user): bool { return $user->can('force_delete_any_group'); } - public function restore(Authorizable $user, Group $group): bool + public function restore(AuthUser $user, Group $group): bool { return $user->can('restore_group'); } - public function restoreAny(Authorizable $user): bool + public function restoreAny(AuthUser $user): bool { return $user->can('restore_any_group'); } diff --git a/src/Policies/MeasureUnitPolicy.php b/src/Policies/MeasureUnitPolicy.php index 37bd213..cd0626e 100644 --- a/src/Policies/MeasureUnitPolicy.php +++ b/src/Policies/MeasureUnitPolicy.php @@ -1,10 +1,12 @@ can('view_any_measure::unit'); + return $user->can('view_any_measure_unit'); } /** * Determine whether the user can view the model. */ - public function view(Authorizable $user, MeasureUnit $measureUnit): bool + public function view(AuthUser $user, MeasureUnit $measureUnit): bool { - return $user->can('view_measure::unit'); + return $user->can('view_measure_unit'); } /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { - return $user->can('create_measure::unit'); + return $user->can('create_measure_unit'); } /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, MeasureUnit $measureUnit): bool + public function update(AuthUser $user, MeasureUnit $measureUnit): bool { - return $user->can('update_measure::unit'); + return $user->can('update_measure_unit'); } /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, MeasureUnit $measureUnit): bool + public function delete(AuthUser $user, MeasureUnit $measureUnit): bool { // Prevent deletion of default unit if ($measureUnit->is_default) { return false; } - return $user->can('delete_measure::unit'); + return $user->can('delete_measure_unit'); } /** * Determine whether the user can bulk delete. */ - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { - return $user->can('delete_any_measure::unit'); + return $user->can('delete_any_measure_unit'); } /** * Determine whether the user can permanently delete. */ - public function forceDelete(Authorizable $user, MeasureUnit $measureUnit): bool + public function forceDelete(AuthUser $user, MeasureUnit $measureUnit): bool { // Prevent force deletion of default unit if ($measureUnit->is_default) { return false; } - return $user->can('force_delete_measure::unit'); + return $user->can('force_delete_measure_unit'); } /** * 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_measure::unit'); + return $user->can('force_delete_any_measure_unit'); } /** * Determine whether the user can restore. */ - public function restore(Authorizable $user, MeasureUnit $measureUnit): bool + public function restore(AuthUser $user, MeasureUnit $measureUnit): bool { - return $user->can('restore_measure::unit'); + return $user->can('restore_measure_unit'); } /** * Determine whether the user can bulk restore. */ - public function restoreAny(Authorizable $user): bool + public function restoreAny(AuthUser $user): bool { - return $user->can('restore_any_measure::unit'); + return $user->can('restore_any_measure_unit'); } } diff --git a/src/Policies/PriceListPolicy.php b/src/Policies/PriceListPolicy.php index f3e40d9..7d817fd 100644 --- a/src/Policies/PriceListPolicy.php +++ b/src/Policies/PriceListPolicy.php @@ -1,10 +1,12 @@ can('view_any_price::list'); + return $user->can('view_any_price_list'); } /** * Determine whether the user can view the model. */ - public function view(Authorizable $user, PriceList $priceList): bool + public function view(AuthUser $user, PriceList $priceList): bool { - return $user->can('view_price::list'); + return $user->can('view_price_list'); } /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { - return $user->can('create_price::list'); + return $user->can('create_price_list'); } /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, PriceList $priceList): bool + public function update(AuthUser $user, PriceList $priceList): bool { - return $user->can('update_price::list'); + return $user->can('update_price_list'); } /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, PriceList $priceList): bool + public function delete(AuthUser $user, PriceList $priceList): bool { // Prevent deletion of default price lists if ($priceList->is_default || $priceList->is_default_purchase) { return false; } - return $user->can('delete_price::list'); + return $user->can('delete_price_list'); } /** * Determine whether the user can bulk delete. */ - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { - return $user->can('delete_any_price::list'); + return $user->can('delete_any_price_list'); } /** * Determine whether the user can restore the model. */ - public function restore(Authorizable $user, PriceList $priceList): bool + public function restore(AuthUser $user, PriceList $priceList): bool { - return $user->can('restore_price::list'); + return $user->can('restore_price_list'); } /** * Determine whether the user can bulk restore. */ - public function restoreAny(Authorizable $user): bool + public function restoreAny(AuthUser $user): bool { - return $user->can('restore_any_price::list'); + return $user->can('restore_any_price_list'); } /** * Determine whether the user can permanently delete the model. */ - public function forceDelete(Authorizable $user, PriceList $priceList): bool + public function forceDelete(AuthUser $user, PriceList $priceList): bool { // Prevent force deletion of default price lists if ($priceList->is_default || $priceList->is_default_purchase) { return false; } - return $user->can('force_delete_price::list'); + return $user->can('force_delete_price_list'); } /** * 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_price::list'); + return $user->can('force_delete_any_price_list'); } } diff --git a/src/Policies/ProductPolicy.php b/src/Policies/ProductPolicy.php index e8ca29a..14ae539 100644 --- a/src/Policies/ProductPolicy.php +++ b/src/Policies/ProductPolicy.php @@ -1,10 +1,12 @@ can('view_any_product'); } @@ -21,7 +23,7 @@ public function viewAny(Authorizable $user): bool /** * Determine whether the user can view the model. */ - public function view(Authorizable $user, Product $product): bool + public function view(AuthUser $user, Product $product): bool { return $user->can('view_product'); } @@ -29,7 +31,7 @@ public function view(Authorizable $user, Product $product): bool /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { return $user->can('create_product'); } @@ -37,7 +39,7 @@ public function create(Authorizable $user): bool /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, Product $product): bool + public function update(AuthUser $user, Product $product): bool { return $user->can('update_product'); } @@ -45,7 +47,7 @@ public function update(Authorizable $user, Product $product): bool /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, Product $product): bool + public function delete(AuthUser $user, Product $product): bool { return $user->can('delete_product'); } @@ -53,7 +55,7 @@ public function delete(Authorizable $user, Product $product): 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_product'); } @@ -61,7 +63,7 @@ public function deleteAny(Authorizable $user): bool /** * Determine whether the user can permanently delete. */ - public function forceDelete(Authorizable $user, Product $product): bool + public function forceDelete(AuthUser $user, Product $product): bool { return $user->can('force_delete_product'); } @@ -69,7 +71,7 @@ public function forceDelete(Authorizable $user, Product $product): 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_product'); } @@ -77,7 +79,7 @@ public function forceDeleteAny(Authorizable $user): bool /** * Determine whether the user can restore. */ - public function restore(Authorizable $user, Product $product): bool + public function restore(AuthUser $user, Product $product): bool { return $user->can('restore_product'); } @@ -85,7 +87,7 @@ public function restore(Authorizable $user, Product $product): 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_product'); } diff --git a/src/Policies/ProductStatusPolicy.php b/src/Policies/ProductStatusPolicy.php index 4878e38..51ac542 100644 --- a/src/Policies/ProductStatusPolicy.php +++ b/src/Policies/ProductStatusPolicy.php @@ -1,10 +1,12 @@ can('view_any_product::status'); + return $user->can('view_any_product_status'); } /** * Determine whether the user can view the model. */ - public function view(Authorizable $user, ProductStatus $productStatus): bool + public function view(AuthUser $user, ProductStatus $productStatus): bool { - return $user->can('view_product::status'); + return $user->can('view_product_status'); } /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { - return $user->can('create_product::status'); + return $user->can('create_product_status'); } /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, ProductStatus $productStatus): bool + public function update(AuthUser $user, ProductStatus $productStatus): bool { - return $user->can('update_product::status'); + return $user->can('update_product_status'); } /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, ProductStatus $productStatus): bool + public function delete(AuthUser $user, ProductStatus $productStatus): bool { // Prevent deletion of default status if ($productStatus->is_default) { return false; } - return $user->can('delete_product::status'); + return $user->can('delete_product_status'); } /** * Determine whether the user can bulk delete. */ - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { - return $user->can('delete_any_product::status'); + return $user->can('delete_any_product_status'); } } diff --git a/src/Policies/ProductTypePolicy.php b/src/Policies/ProductTypePolicy.php index 28fac4d..85f38af 100644 --- a/src/Policies/ProductTypePolicy.php +++ b/src/Policies/ProductTypePolicy.php @@ -1,10 +1,12 @@ can('view_any_product::type'); + return $user->can('view_any_product_type'); } /** * Determine whether the user can view the model. */ - public function view(Authorizable $user, ProductType $productType): bool + public function view(AuthUser $user, ProductType $productType): bool { - return $user->can('view_product::type'); + return $user->can('view_product_type'); } /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { - return $user->can('create_product::type'); + return $user->can('create_product_type'); } /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, ProductType $productType): bool + public function update(AuthUser $user, ProductType $productType): bool { - return $user->can('update_product::type'); + return $user->can('update_product_type'); } /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, ProductType $productType): bool + public function delete(AuthUser $user, ProductType $productType): bool { - return $user->can('delete_product::type'); + return $user->can('delete_product_type'); } /** * Determine whether the user can bulk delete. */ - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { - return $user->can('delete_any_product::type'); + return $user->can('delete_any_product_type'); } /** * Determine whether the user can permanently delete. */ - public function forceDelete(Authorizable $user, ProductType $productType): bool + public function forceDelete(AuthUser $user, ProductType $productType): bool { - return $user->can('force_delete_product::type'); + return $user->can('force_delete_product_type'); } /** * 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_product::type'); + return $user->can('force_delete_any_product_type'); } /** * Determine whether the user can restore. */ - public function restore(Authorizable $user, ProductType $productType): bool + public function restore(AuthUser $user, ProductType $productType): bool { - return $user->can('restore_product::type'); + return $user->can('restore_product_type'); } /** * Determine whether the user can bulk restore. */ - public function restoreAny(Authorizable $user): bool + public function restoreAny(AuthUser $user): bool { - return $user->can('restore_any_product::type'); + return $user->can('restore_any_product_type'); } /** * Determine whether the user can replicate. */ - public function replicate(Authorizable $user, ProductType $productType): bool + public function replicate(AuthUser $user, ProductType $productType): bool { - return $user->can('{{ Replicate }}'); + return $user->can('replicate_product_type'); } /** * Determine whether the user can reorder. */ - public function reorder(Authorizable $user): bool + public function reorder(AuthUser $user): bool { - return $user->can('{{ Reorder }}'); + return $user->can('reorder_product_type'); } } diff --git a/src/Policies/PropertyPolicy.php b/src/Policies/PropertyPolicy.php index ae588d0..46c3416 100644 --- a/src/Policies/PropertyPolicy.php +++ b/src/Policies/PropertyPolicy.php @@ -1,10 +1,12 @@ can('view_any_property'); } @@ -21,7 +23,7 @@ public function viewAny(Authorizable $user): bool /** * Determine whether the user can view the model. */ - public function view(Authorizable $user, Property $property): bool + public function view(AuthUser $user, Property $property): bool { return $user->can('view_property'); } @@ -29,7 +31,7 @@ public function view(Authorizable $user, Property $property): bool /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { return $user->can('create_property'); } @@ -37,7 +39,7 @@ public function create(Authorizable $user): bool /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, Property $property): bool + public function update(AuthUser $user, Property $property): bool { return $user->can('update_property'); } @@ -45,7 +47,7 @@ public function update(Authorizable $user, Property $property): bool /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, Property $property): bool + public function delete(AuthUser $user, Property $property): bool { return $user->can('delete_property'); } @@ -53,7 +55,7 @@ public function delete(Authorizable $user, Property $property): 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_property'); } @@ -61,7 +63,7 @@ public function deleteAny(Authorizable $user): bool /** * Determine whether the user can permanently delete. */ - public function forceDelete(Authorizable $user, Property $property): bool + public function forceDelete(AuthUser $user, Property $property): bool { return $user->can('force_delete_property'); } @@ -69,7 +71,7 @@ public function forceDelete(Authorizable $user, Property $property): 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_property'); } @@ -77,7 +79,7 @@ public function forceDeleteAny(Authorizable $user): bool /** * Determine whether the user can restore. */ - public function restore(Authorizable $user, Property $property): bool + public function restore(AuthUser $user, Property $property): bool { return $user->can('restore_property'); } @@ -85,7 +87,7 @@ public function restore(Authorizable $user, Property $property): 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_property'); } diff --git a/src/Policies/TaxClassPolicy.php b/src/Policies/TaxClassPolicy.php index 074d86e..f12b69e 100644 --- a/src/Policies/TaxClassPolicy.php +++ b/src/Policies/TaxClassPolicy.php @@ -1,10 +1,12 @@ can('view_any_tax::class'); + return $user->can('view_any_tax_class'); } /** * Determine whether the user can view the model. */ - public function view(Authorizable $user, TaxClass $taxClass): bool + public function view(AuthUser $user, TaxClass $taxClass): bool { - return $user->can('view_tax::class'); + return $user->can('view_tax_class'); } /** * Determine whether the user can create models. */ - public function create(Authorizable $user): bool + public function create(AuthUser $user): bool { - return $user->can('create_tax::class'); + return $user->can('create_tax_class'); } /** * Determine whether the user can update the model. */ - public function update(Authorizable $user, TaxClass $taxClass): bool + public function update(AuthUser $user, TaxClass $taxClass): bool { - return $user->can('update_tax::class'); + return $user->can('update_tax_class'); } /** * Determine whether the user can delete the model. */ - public function delete(Authorizable $user, TaxClass $taxClass): bool + public function delete(AuthUser $user, TaxClass $taxClass): bool { // Prevent deletion of default class if ($taxClass->is_default) { return false; } - return $user->can('delete_tax::class'); + return $user->can('delete_tax_class'); } /** * Determine whether the user can bulk delete. */ - public function deleteAny(Authorizable $user): bool + public function deleteAny(AuthUser $user): bool { - return $user->can('delete_any_tax::class'); + return $user->can('delete_any_tax_class'); } /** * Determine whether the user can permanently delete. */ - public function forceDelete(Authorizable $user, TaxClass $taxClass): bool + public function forceDelete(AuthUser $user, TaxClass $taxClass): bool { // Prevent force deletion of default class if ($taxClass->is_default) { return false; } - return $user->can('force_delete_tax::class'); + return $user->can('force_delete_tax_class'); } /** * 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_tax::class'); + return $user->can('force_delete_any_tax_class'); } /** * Determine whether the user can restore. */ - public function restore(Authorizable $user, TaxClass $taxClass): bool + public function restore(AuthUser $user, TaxClass $taxClass): bool { - return $user->can('restore_tax::class'); + return $user->can('restore_tax_class'); } /** * Determine whether the user can bulk restore. */ - public function restoreAny(Authorizable $user): bool + public function restoreAny(AuthUser $user): bool { - return $user->can('restore_any_tax::class'); + return $user->can('restore_any_tax_class'); } } diff --git a/tests/Feature/MeasureUnitPermissionTest.php b/tests/Feature/MeasureUnitPermissionTest.php index 74955a9..370a656 100644 --- a/tests/Feature/MeasureUnitPermissionTest.php +++ b/tests/Feature/MeasureUnitPermissionTest.php @@ -55,7 +55,7 @@ ->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_measure::unit'); + $this->user->givePermissionTo('view_any_measure_unit'); // Create measure unit livewire(ListMeasureUnits::class) diff --git a/tests/Feature/PropertyValueColorFormTest.php b/tests/Feature/PropertyValueColorFormTest.php index 2fc35ed..0e56ec8 100644 --- a/tests/Feature/PropertyValueColorFormTest.php +++ b/tests/Feature/PropertyValueColorFormTest.php @@ -25,7 +25,7 @@ expect($colorGroupSchema[0])->toBeInstanceOf(Group::class); // Group should contain 4 form components - $groupSchema = $colorGroupSchema[0]->getChildComponents(); + $groupSchema = $colorGroupSchema[0]->getDefaultChildComponents(); expect($groupSchema)->toHaveCount(4); // Verify component types: Radio (background type), ColorPicker, Grid (gradient), ViewField (preview) @@ -43,7 +43,7 @@ $method->setAccessible(true); $colorGroupSchema = $method->invoke($resource); - $groupSchema = $colorGroupSchema[0]->getChildComponents(); + $groupSchema = $colorGroupSchema[0]->getDefaultChildComponents(); $colorPicker = $groupSchema[1]; expect($colorPicker)->toBeInstanceOf(ColorPicker::class); @@ -58,13 +58,13 @@ $method->setAccessible(true); $colorGroupSchema = $method->invoke($resource); - $groupSchema = $colorGroupSchema[0]->getChildComponents(); + $groupSchema = $colorGroupSchema[0]->getDefaultChildComponents(); $gradientGrid = $groupSchema[2]; expect($gradientGrid)->toBeInstanceOf(Grid::class); // Should contain color_start, color_end, gradient_direction, gradient_style - $gridChildren = $gradientGrid->getChildComponents(); + $gridChildren = $gradientGrid->getDefaultChildComponents(); expect($gridChildren)->toHaveCount(4); }); @@ -76,7 +76,7 @@ $method->setAccessible(true); $colorGroupSchema = $method->invoke($resource); - $groupSchema = $colorGroupSchema[0]->getChildComponents(); + $groupSchema = $colorGroupSchema[0]->getDefaultChildComponents(); $previewField = $groupSchema[3]; expect($previewField)->toBeInstanceOf(ViewField::class); diff --git a/tests/Feature/TaxClassPermissionTest.php b/tests/Feature/TaxClassPermissionTest.php index d3753c5..d26017e 100644 --- a/tests/Feature/TaxClassPermissionTest.php +++ b/tests/Feature/TaxClassPermissionTest.php @@ -1,6 +1,5 @@ false, ]); - // View table - $this->get(TaxClassResource::getUrl()) - ->assertForbidden(); + // Authorization: user should not be able to view any + expect((new TaxClassPolicy)->viewAny($this->user))->toBeFalse(); // Add direct permission to view the table, since otherwise any other action below is not available even for testing - $this->user->givePermissionTo('view_any_tax::class'); + $this->user->givePermissionTo('view_any_tax_class'); // Create tax class livewire(ListTaxClasses::class) diff --git a/tests/TestCase.php b/tests/TestCase.php index 94960f5..a464d77 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -112,17 +112,16 @@ protected function createPermissions(): self { $resources = [ 'category', - 'custom::property', 'group', - 'measure::unit', - 'price::list', + 'measure_unit', + 'price_list', 'product', - 'product::status', - 'product::type', + 'product_status', + 'product_type', 'property', - 'property::value', + 'property_value', 'role', - 'tax::class', + 'tax_class', ]; $permissions = [ From 507409912e15ef649650490d3dabac1171887979 Mon Sep 17 00:00:00 2001 From: Kilian Trunk Date: Wed, 8 Oct 2025 14:25:02 +0200 Subject: [PATCH 5/7] chore: update shield setup --- config/filament-shield.php | 130 ++----------------------------- src/CatalogueServiceProvider.php | 129 ++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 125 deletions(-) diff --git a/config/filament-shield.php b/config/filament-shield.php index 837a1c1..e14b8e5 100644 --- a/config/filament-shield.php +++ b/config/filament-shield.php @@ -1,16 +1,5 @@ [ 'slug' => 'shield/roles', @@ -48,7 +37,7 @@ 'policies' => [ 'path' => app_path('Policies'), - 'merge' => true, + 'merge' => false, 'generate' => true, 'methods' => [ 'viewAny', 'view', 'create', 'update', 'restore', 'restoreAny', @@ -66,116 +55,7 @@ 'resources' => [ 'subject' => 'model', - 'manage' => [ - ProductResource::class => [ - 'viewAny', - 'view', - 'create', - 'update', - 'restore', - 'restoreAny', - 'delete', - 'deleteAny', - 'forceDelete', - 'forceDeleteAny', - ], - CategoryResource::class => [ - 'viewAny', - 'view', - 'create', - 'update', - 'restore', - 'restoreAny', - 'delete', - 'deleteAny', - 'forceDelete', - 'forceDeleteAny', - ], - ProductTypeResource::class => [ - 'viewAny', - 'view', - 'create', - 'update', - 'restore', - 'restoreAny', - 'delete', - 'deleteAny', - 'forceDelete', - 'forceDeleteAny', - ], - PropertyResource::class => [ - 'viewAny', - 'view', - 'create', - 'update', - 'delete', - 'deleteAny', - 'forceDelete', - 'forceDeleteAny', - 'restore', - 'restoreAny', - ], - PropertyValueResource::class => [ - 'viewAny', - 'view', - 'create', - 'update', - 'delete', - 'deleteAny', - ], - GroupResource::class => [ - 'viewAny', - 'view', - 'create', - 'update', - 'delete', - 'deleteAny', - ], - PriceListResource::class => [ - 'viewAny', - 'view', - 'create', - 'update', - 'restore', - 'restoreAny', - 'delete', - 'deleteAny', - 'forceDelete', - 'forceDeleteAny', - ], - MeasureUnitResource::class => [ - 'viewAny', - 'view', - 'create', - 'update', - 'restore', - 'restoreAny', - 'delete', - 'deleteAny', - 'forceDelete', - 'forceDeleteAny', - ], - TaxClassResource::class => [ - 'viewAny', - 'view', - 'create', - 'update', - 'restore', - 'restoreAny', - 'delete', - 'deleteAny', - 'forceDelete', - 'forceDeleteAny', - ], - ProductStatusResource::class => [ - 'viewAny', - 'view', - 'create', - 'update', - 'delete', - 'deleteAny', - ], - ], + 'manage' => [], 'exclude' => [], ], @@ -197,9 +77,9 @@ ], 'discovery' => [ - 'discover_all_resources' => false, - 'discover_all_widgets' => false, - 'discover_all_pages' => false, + 'discover_all_resources' => true, + 'discover_all_widgets' => true, + 'discover_all_pages' => true, ], 'register_role_policy' => true, diff --git a/src/CatalogueServiceProvider.php b/src/CatalogueServiceProvider.php index 8f5a7c6..b12a2c4 100644 --- a/src/CatalogueServiceProvider.php +++ b/src/CatalogueServiceProvider.php @@ -2,6 +2,16 @@ namespace Eclipse\Catalogue; +use Eclipse\Catalogue\Filament\Resources\CategoryResource; +use Eclipse\Catalogue\Filament\Resources\GroupResource; +use Eclipse\Catalogue\Filament\Resources\MeasureUnitResource; +use Eclipse\Catalogue\Filament\Resources\PriceListResource; +use Eclipse\Catalogue\Filament\Resources\ProductResource; +use Eclipse\Catalogue\Filament\Resources\ProductStatusResource; +use Eclipse\Catalogue\Filament\Resources\ProductTypeResource; +use Eclipse\Catalogue\Filament\Resources\PropertyResource; +use Eclipse\Catalogue\Filament\Resources\PropertyValueResource; +use Eclipse\Catalogue\Filament\Resources\TaxClassResource; use Eclipse\Catalogue\Livewire\TenantSwitcher; use Eclipse\Catalogue\Models\Category; use Eclipse\Catalogue\Models\Product; @@ -46,6 +56,125 @@ public function boot() { parent::boot(); + // Merge per-resource abilities into the effective config + $this->app->booted(function () { + $manage = config('filament-shield.resources.manage', []); + + $pluginManage = [ + ProductResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + CategoryResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + ProductTypeResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + PropertyResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + 'restore', + 'restoreAny', + ], + PropertyValueResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'delete', + 'deleteAny', + ], + GroupResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'delete', + 'deleteAny', + ], + PriceListResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + MeasureUnitResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + TaxClassResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'restore', + 'restoreAny', + 'delete', + 'deleteAny', + 'forceDelete', + 'forceDeleteAny', + ], + ProductStatusResource::class => [ + 'viewAny', + 'view', + 'create', + 'update', + 'delete', + 'deleteAny', + ], + ]; + + $manage = array_replace_recursive($manage, $pluginManage); + config()->set('filament-shield.resources.manage', $manage); + }); + // Register Livewire components if (class_exists(Livewire::class)) { Livewire::component('eclipse-catalogue::tenant-switcher', TenantSwitcher::class); From 98b746793961e384f957f4783e76e8fbd6e6941c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omer=20=C5=A0abi=C4=87?= Date: Sat, 11 Oct 2025 16:14:44 +0200 Subject: [PATCH 6/7] build(deps): revert eclipse deps to dev-main --- composer.json | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index 34dec38..7a69dfd 100644 --- a/composer.json +++ b/composer.json @@ -47,8 +47,8 @@ "php": "^8.2", "bezhansalleh/filament-shield": "^4.0", "datalinx/php-utils": "^2.5", - "eclipsephp/common": "dev-f4@dev", - "eclipsephp/world-plugin": "dev-f4@dev", + "eclipsephp/common": "dev-main", + "eclipsephp/world-plugin": "dev-main", "filament/filament": "^4.0", "filament/spatie-laravel-media-library-plugin": "^4.0", "lara-zeus/spatie-translatable": "^1.0", @@ -59,16 +59,6 @@ "spatie/laravel-package-tools": "^1.19", "spatie/laravel-translatable": "^6.11" }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/KilianTrunk/eclipsephp-common.git" - }, - { - "type": "vcs", - "url": "https://github.com/KilianTrunk/eclipsephp-world-plugin.git" - } - ], "require-dev": { "laravel/pint": "^1.21", "orchestra/testbench": "^9.0|^10.1", From 1f0c1327505eac99ee7054bf2796ace6225855d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omer=20=C5=A0abi=C4=87?= Date: Sat, 11 Oct 2025 16:18:05 +0200 Subject: [PATCH 7/7] ci(tests): fix workflow --- .github/workflows/test-runner.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-runner.yml b/.github/workflows/test-runner.yml index 2e0de36..d093e6f 100644 --- a/.github/workflows/test-runner.yml +++ b/.github/workflows/test-runner.yml @@ -66,7 +66,7 @@ jobs: - name: Install dependencies run: | - composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" "filament/support:^3.3" --no-interaction --no-update + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update composer update --${{ matrix.dependency-version }} --prefer-dist --no-progress --no-interaction - name: Run test suite