diff --git a/src/CustomFieldsPlugin.php b/src/CustomFieldsPlugin.php index c8d03ca0..3b8e5241 100644 --- a/src/CustomFieldsPlugin.php +++ b/src/CustomFieldsPlugin.php @@ -5,8 +5,7 @@ use Filament\Contracts\Plugin; use Filament\Navigation\MenuItem; use Filament\Panel; -use Relaticle\CustomFields\Filament\Pages\CustomFieldsNext; -use Relaticle\CustomFields\Filament\Resources\CustomFieldResource; +use Relaticle\CustomFields\Filament\Pages\CustomFields; use Relaticle\CustomFields\Http\Middleware\ApplyTenantScopes; class CustomFieldsPlugin implements Plugin @@ -19,11 +18,8 @@ public function getId(): string public function register(Panel $panel): void { $panel - ->resources([ - CustomFieldResource::class, - ]) ->pages([ - CustomFieldsNext::class + CustomFields::class ]) ->discoverPages(in: __DIR__.'/Filament/Pages', for: 'ManukMinasyan\\FilamentCustomField\\Filament\\Pages'); } diff --git a/src/Filament/FormSchemas/FieldForm.php b/src/Filament/FormSchemas/FieldForm.php index ee0c0fa4..d77acd0a 100644 --- a/src/Filament/FormSchemas/FieldForm.php +++ b/src/Filament/FormSchemas/FieldForm.php @@ -3,16 +3,16 @@ namespace Relaticle\CustomFields\Filament\FormSchemas; use Filament\Facades\Filament; +use Filament\Forms; use Illuminate\Support\Str; use Illuminate\Validation\Rules\Unique; use Relaticle\CustomFields\Enums\CustomFieldType; -use Relaticle\CustomFields\Filament\Forms\Components\CustomFieldResource\CustomFieldValidationComponent; +use Relaticle\CustomFields\Filament\Forms\Components\CustomFieldValidationComponent; use Relaticle\CustomFields\Filament\Forms\Components\TypeField; use Relaticle\CustomFields\Models\CustomField; use Relaticle\CustomFields\Services\EntityTypeService; use Relaticle\CustomFields\Services\LookupTypeService; use Relaticle\CustomFields\Support\Utils; -use Filament\Forms; class FieldForm implements FormInterface { diff --git a/src/Filament/Forms/Components/CustomFieldResource/CustomFieldValidationComponent.php b/src/Filament/Forms/Components/CustomFieldValidationComponent.php similarity index 98% rename from src/Filament/Forms/Components/CustomFieldResource/CustomFieldValidationComponent.php rename to src/Filament/Forms/Components/CustomFieldValidationComponent.php index 0fe6ae7a..4a0ae595 100644 --- a/src/Filament/Forms/Components/CustomFieldResource/CustomFieldValidationComponent.php +++ b/src/Filament/Forms/Components/CustomFieldValidationComponent.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace Relaticle\CustomFields\Filament\Forms\Components\CustomFieldResource; +namespace Relaticle\CustomFields\Filament\Forms\Components; use Filament\Forms; use Filament\Forms\Components\Component; use Filament\Forms\Get; use Filament\Forms\Set; -use Relaticle\CustomFields\Enums\CustomFieldValidationRule; use Relaticle\CustomFields\Enums\CustomFieldType; +use Relaticle\CustomFields\Enums\CustomFieldValidationRule; final class CustomFieldValidationComponent extends Component { diff --git a/src/Filament/Pages/CustomFieldsNext.php b/src/Filament/Pages/CustomFields.php similarity index 81% rename from src/Filament/Pages/CustomFieldsNext.php rename to src/Filament/Pages/CustomFields.php index 69ec73dc..92fb05cb 100644 --- a/src/Filament/Pages/CustomFieldsNext.php +++ b/src/Filament/Pages/CustomFields.php @@ -14,8 +14,9 @@ use Relaticle\CustomFields\Models\CustomField; use Relaticle\CustomFields\Services\EntityTypeService; use Livewire\Attributes\Url; +use Relaticle\CustomFields\Support\Utils; -class CustomFieldsNext extends Page +class CustomFields extends Page { protected static ?string $navigationIcon = 'heroicon-m-document-text'; @@ -140,4 +141,42 @@ private function storeSection(array $data): CustomFieldSection $data['type'] ??= CustomFieldSectionType::SECTION->value; return CustomFieldSection::create($data); } + + + public static function getCluster(): ?string + { + return Utils::getResourceCluster() ?? static::$cluster; + } + + public static function shouldRegisterNavigation(): bool + { + return Utils::isResourceNavigationRegistered(); + } + + public static function getNavigationGroup(): ?string + { + return Utils::isResourceNavigationGroupEnabled() + ? __('custom-fields::custom-fields.nav.group') + : ''; + } + + public static function getNavigationLabel(): string + { + return __('custom-fields::custom-fields.nav.label'); + } + + public static function getNavigationIcon(): string + { + return __('custom-fields::custom-fields.nav.icon'); + } + + public static function getNavigationSort(): ?int + { + return Utils::getResourceNavigationSort(); + } + + public static function getSlug(): string + { + return Utils::getResourceSlug(); + } } diff --git a/src/Filament/Resources/CustomFieldResource.php b/src/Filament/Resources/CustomFieldResource.php deleted file mode 100644 index b0bcbcbf..00000000 --- a/src/Filament/Resources/CustomFieldResource.php +++ /dev/null @@ -1,282 +0,0 @@ -schema([ - Forms\Components\Tabs::make() - ->tabs([ - Forms\Components\Tabs\Tab::make('General') - ->schema([ - Forms\Components\Select::make('entity_type') - ->disabled(fn(?CustomField $record): bool => (bool)$record?->exists) - ->options(EntityTypeService::getOptions()) - ->searchable() - ->default(fn() => request('entityType', EntityTypeService::getDefaultOption())) - ->required(), - TypeField::make('type') - ->disabled(fn(?CustomField $record): bool => (bool)$record?->exists) - ->reactive() - ->required(), - Forms\Components\TextInput::make('name') - ->helperText("The field's label shown in the table's and form's.") - ->live(onBlur: true) - ->required() - ->maxLength(50) - ->unique( - table: CustomField::class, - column: 'name', - ignoreRecord: true, - modifyRuleUsing: function (Unique $rule, Forms\Get $get) { - return $rule->where('entity_type', $get('entity_type')) - ->when( - Utils::isTenantEnabled(), - function (Unique $rule) { - return $rule->where( - config('custom-fields.column_names.tenant_foreign_key'), - Filament::getTenant()?->id - ); - }); - }, - ) - ->afterStateUpdated(function (Forms\Get $get, Forms\Set $set, ?string $old, ?string $state): void { - $old ??= ''; - $state ??= ''; - - if (($get('code') ?? '') !== Str::of($old)->slug('_')->toString()) { - return; - } - - $set('code', Str::of($state)->slug('_')->toString()); - }), - Forms\Components\TextInput::make('code') - ->helperText('Unique code to identify this field throughout the resource.') - ->live(onBlur: true) - ->required() - ->alphaDash() - ->maxLength(50) - ->unique( - table: CustomField::class, - column: 'code', - ignoreRecord: true, - modifyRuleUsing: function (Unique $rule, Forms\Get $get) { - return $rule->where('entity_type', $get('entity_type')) - ->when( - Utils::isTenantEnabled(), - function (Unique $rule) { - return $rule->where( - config('custom-fields.column_names.tenant_foreign_key'), - Filament::getTenant()?->id - ); - }); - }, - ) - ->afterStateUpdated(function (Forms\Set $set, ?string $state): void { - $set('code', Str::of($state)->slug('_')->toString()); - }), - Forms\Components\Select::make('options_lookup_type') - ->visible(fn(Forms\Get $get): bool => in_array($get('type'), CustomFieldType::optionables()->pluck('value')->toArray())) - ->reactive() - ->options([ - 'options' => 'Options', - 'lookup' => 'Lookup', - ]) - ->afterStateHydrated(function (Forms\Components\Select $component, $state, $record): void { - if (blank($state)) { - $optionsLookupType = $record?->lookup_type ? 'lookup' : 'options'; - $component->state($optionsLookupType); - } - }) - ->dehydrated(false) - ->required(), - Forms\Components\Select::make('lookup_type') - ->visible(fn(Forms\Get $get): bool => $get('options_lookup_type') === 'lookup') - ->reactive() - ->options(LookupTypeService::getOptions()) - ->default(LookupTypeService::getDefaultOption()) - ->required(), - Forms\Components\Fieldset::make('Options') - ->visible(fn(Forms\Get $get): bool => $get('options_lookup_type') === 'options' && in_array($get('type'), CustomFieldType::optionables()->pluck('value')->toArray())) - ->schema([ - Forms\Components\Repeater::make('options') - ->relationship() - ->simple( - Forms\Components\TextInput::make('name') - ->columnSpanFull() - ->required(), - ) - ->columns(2) - ->requiredUnless('type', CustomFieldType::TAGS_INPUT->value) - ->hiddenLabel() - ->defaultItems(1) - ->addActionLabel('Add Option') - ->reorderable() - ->orderColumn('sort_order') - ->columnSpanFull() - ->mutateRelationshipDataBeforeCreateUsing(function (array $data): array { - $data[config('custom-fields.column_names.tenant_foreign_key')] = Filament::getTenant()?->id; - - return $data; - }) - ]) - ]), - Forms\Components\Tabs\Tab::make('Validation') - ->schema([ - CustomFieldValidationComponent::make(), - ]), - ]) - ->columns(2) - ->columnSpanFull() - ->contained(false), - ]); - } - - public static function table(Tables\Table $table): Tables\Table - { - return $table - ->columns([ - Tables\Columns\TextColumn::make('name') - ->searchable(), - Tables\Columns\TextColumn::make('code') - ->searchable(), - TypeColumn::make('type'), - ]) - ->filters([ - Tables\Filters\SelectFilter::make('type') - ->multiple() - ->options(CustomFieldType::class), - ]) - ->actions([ - Tables\Actions\ActionGroup::make([ - EditAction::make()->slideOver(), - Tables\Actions\RestoreAction::make('Restore'), - Tables\Actions\Action::make('activate') - ->icon('heroicon-o-archive-box') - ->requiresConfirmation() - ->visible(fn(CustomField $record): bool => !$record->isActive()) - ->action(fn(CustomField $record) => $record->activate()), - Tables\Actions\Action::make('deactivate') - ->icon('heroicon-o-archive-box-x-mark') - ->requiresConfirmation() - ->visible(fn(CustomField $record): bool => $record->isActive()) - ->action(fn(CustomField $record) => $record->deactivate()), - DeleteAction::make()->visible(fn(CustomField $record): bool => !$record->isActive() && !$record->isSystemDefined()), - ])->iconButton(), - - ]) - ->defaultGroup('active') - ->groups([ - Tables\Grouping\Group::make('active') - ->titlePrefixedWithLabel(false) - ->getTitleFromRecordUsing(fn(CustomField $record): string => $record->active ? 'Active' : 'Inactive') - ->orderQueryUsing(fn(Builder $query, string $direction) => $query->orderByDesc('active')) - ->label('Active') - ->collapsible(), - ]) - ->groupingSettingsHidden() - ->paginated(false) - ->reorderable('sort_order'); - } - - public static function getEloquentQuery(): Builder - { - return parent::getEloquentQuery() - ->withoutGlobalScopes([ - ActivableScope::class, - ]); - } - - public static function getPages(): array - { - return [ - 'index' => Pages\ManageCustomFields::route('/'), - ]; - } - - public static function getCluster(): ?string - { - return Utils::getResourceCluster() ?? static::$cluster; - } - - public static function shouldRegisterNavigation(): bool - { - return Utils::isResourceNavigationRegistered(); - } - - public static function getNavigationGroup(): ?string - { - return Utils::isResourceNavigationGroupEnabled() - ? __('custom-fields::custom-fields.nav.group') - : ''; - } - - public static function getNavigationLabel(): string - { - return __('custom-fields::custom-fields.nav.label'); - } - - public static function getNavigationIcon(): string - { - return __('custom-fields::custom-fields.nav.icon'); - } - - public static function getNavigationSort(): ?int - { - return Utils::getResourceNavigationSort(); - } - - public static function getSlug(): string - { - return Utils::getResourceSlug(); - } - - public static function getNavigationBadge(): ?string - { - return Utils::isResourceNavigationBadgeEnabled() - ? strval(static::getEloquentQuery()->count()) - : null; - } - - public static function isScopedToTenant(): bool - { - return Utils::isScopedToTenant(); - } - - public static function canGloballySearch(): bool - { - return Utils::isResourceGloballySearchable() && count(static::getGloballySearchableAttributes()) && static::canViewAny(); - } -} diff --git a/src/Filament/Resources/CustomFieldResource/Pages/ManageCustomFields.php b/src/Filament/Resources/CustomFieldResource/Pages/ManageCustomFields.php deleted file mode 100644 index 3fea8b53..00000000 --- a/src/Filament/Resources/CustomFieldResource/Pages/ManageCustomFields.php +++ /dev/null @@ -1,63 +0,0 @@ - ['except' => ''], - 'tableColumnSearchQueries', - ]; - - protected function getHeaderActions(): array - { - return [ - CreateAction::make() - ->slideOver() - ->fillForm([ - 'entity_type' => $this->entityType ?? EntityTypeService::getDefaultOption(), - ]) - ->url(function (array $data): string { - return CustomFieldResource::getUrl(parameters: [ - ...$data, - 'action' => CreateAction::getDefaultName(), - 'entityType' => $this->entityType ?? EntityTypeService::getDefaultOption() - ]); - }), - ]; - } - - public function getSubNavigation(): array - { - return EntityTypeService::getOptions() - ->map(fn ($label, $value) => NavigationItem::make($label) - ->url(CustomFieldResource::getUrl('index', ['entityType' => $value])) - ->isActiveWhen(fn () => ($this->entityType ?? EntityTypeService::getDefaultOption()) === $value) - ) - ->values() - ->toArray(); - } - - public function table(Table $table): Table - { - return parent::table($table)->modifyQueryUsing(fn (Builder $query): Builder => $query->forMorphEntity($this->entityType ?? EntityTypeService::getDefaultOption())); - } -} diff --git a/src/Migrations/CustomFieldsMigrator.php b/src/Migrations/CustomFieldsMigrator.php index 69bb6f0a..621d48c0 100644 --- a/src/Migrations/CustomFieldsMigrator.php +++ b/src/Migrations/CustomFieldsMigrator.php @@ -112,7 +112,7 @@ public function create(): void try { DB::beginTransaction(); - $data = $this->customFieldData->except('options')->toArray(); + $data = $this->customFieldData->except('section', 'options')->toArray(); $sectionData = $this->customFieldData->section->toArray(); if (Utils::isTenantEnabled()) { diff --git a/src/Services/AbstractOptionsService.php b/src/Services/AbstractOptionsService.php index 0a47fbe5..60033633 100644 --- a/src/Services/AbstractOptionsService.php +++ b/src/Services/AbstractOptionsService.php @@ -5,7 +5,6 @@ use Filament\Facades\Filament; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Support\Collection; -use Relaticle\CustomFields\Filament\Resources\CustomFieldResource; abstract class AbstractOptionsService { @@ -21,7 +20,7 @@ abstract class AbstractOptionsService public static function getOptions(): Collection { return static::getFilteredResources() - ->mapWithKeys(fn (string $resource) => static::mapResourceToOption($resource)); + ->mapWithKeys(fn(string $resource) => static::mapResourceToOption($resource)); } public static function getDefaultOption(): string @@ -32,7 +31,7 @@ public static function getDefaultOption(): string protected static function getFilteredResources(): Collection { return collect(Filament::getResources()) - ->reject(fn (string $resource) => static::shouldRejectResource($resource)); + ->reject(fn(string $resource) => static::shouldRejectResource($resource)); } protected static function shouldRejectResource(string $resource): bool @@ -40,8 +39,7 @@ protected static function shouldRejectResource(string $resource): bool $allowedResources = config(static::$allowedConfigKey, []); $disallowedResources = config(static::$disallowedConfigKey, []); - return $resource === CustomFieldResource::class - || (! empty($allowedResources) && ! in_array($resource, $allowedResources)) + return (!empty($allowedResources) && !in_array($resource, $allowedResources)) || in_array($resource, $disallowedResources); } @@ -66,7 +64,7 @@ public static function getEntityFromModel(string $model): string try { $modelInstance = app($model); return $modelInstance->getMorphClass(); - }catch (\Exception $e){ + } catch (\Exception $e) { return $model; } }