Feat: Bringin Privacy to Filament v4, the managers and resources were built with filament v3

This commit is contained in:
2026-09-16 00:24:18 +03:00
parent 58d165acc3
commit c084eb47cb
12 changed files with 50 additions and 41 deletions
+4 -2
View File
@@ -2,6 +2,8 @@
namespace Modules\Core\Export; namespace Modules\Core\Export;
use Closure;
/** /**
* One column in a CsvWriter schema: a header label plus a closure that pulls this * One column in a CsvWriter schema: a header label plus a closure that pulls this
* column's value out of one record. The closure doesn't care what shape a record * column's value out of one record. The closure doesn't care what shape a record
@@ -12,10 +14,10 @@ namespace Modules\Core\Export;
final class CsvColumn final class CsvColumn
{ {
/** /**
* @param \Closure(mixed): (string|int|float|null) $value * @param Closure(mixed):((string|int|float|null)) $value
*/ */
public function __construct( public function __construct(
public readonly string $header, public readonly string $header,
public readonly \Closure $value, public readonly Closure $value,
) {} ) {}
} }
@@ -60,9 +60,9 @@ class PaymentMethodResource extends Resource
{ {
protected static ?string $model = PaymentMethod::class; protected static ?string $model = PaymentMethod::class;
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-credit-card'; protected static string | \BackedEnum | null $navigationIcon = 'heroicon-o-credit-card';
protected static string|\UnitEnum|null $navigationGroup = 'Settings'; protected static string | \UnitEnum | null $navigationGroup = 'Settings';
protected static ?string $modelLabel = 'Payment Method'; protected static ?string $modelLabel = 'Payment Method';
@@ -2,6 +2,7 @@
namespace Modules\Core\Payment\Filament\Resources\PaymentMethodResource\Pages; namespace Modules\Core\Payment\Filament\Resources\PaymentMethodResource\Pages;
use Filament\Actions\CreateAction;
use Filament\Actions; use Filament\Actions;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Modules\Core\Payment\Filament\Resources\PaymentMethodResource; use Modules\Core\Payment\Filament\Resources\PaymentMethodResource;
@@ -15,7 +16,7 @@ class ListPaymentMethods extends ListRecords
protected function getHeaderActions(): array protected function getHeaderActions(): array
{ {
return [ return [
Actions\CreateAction::make() CreateAction::make()
->schema(PaymentMethodResource::getFormComponents()) ->schema(PaymentMethodResource::getFormComponents())
->fillForm(fn () => [ ->fillForm(fn () => [
'position' => (PaymentMethod::max('position') ?? 0) + 1, 'position' => (PaymentMethod::max('position') ?? 0) + 1,
@@ -33,7 +33,7 @@ class CustomerErasureActionsExtension extends BaseExtension
->color('danger') ->color('danger')
->requiresConfirmation() ->requiresConfirmation()
->modalDescription('Opens a cancellable grace-period erasure request for this Customer account. No linked User\'s login is affected.') ->modalDescription('Opens a cancellable grace-period erasure request for this Customer account. No linked User\'s login is affected.')
->form([ ->schema([
Checkbox::make('immediate') Checkbox::make('immediate')
->label('Erase immediately (skip the 30-day grace period)') ->label('Erase immediately (skip the 30-day grace period)')
->helperText('Staff-only, for a formal legal request or regulator inquiry that genuinely requires urgency — not a routine deletion. Runs synchronously, cannot be cancelled once submitted.') ->helperText('Staff-only, for a formal legal request or regulator inquiry that genuinely requires urgency — not a routine deletion. Runs synchronously, cannot be cancelled once submitted.')
@@ -2,13 +2,15 @@
namespace Modules\Core\Privacy\Filament\Resources; namespace Modules\Core\Privacy\Filament\Resources;
use Filament\Schemas\Schema;
use Filament\Actions\ViewAction;
use Filament\Actions\Action;
use Modules\Core\Privacy\Filament\Resources\DataErasureRequestResource\Pages\ListDataErasureRequests;
use Modules\Core\Privacy\Filament\Resources\DataErasureRequestResource\Pages\ViewDataErasureRequest;
use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\KeyValue;
use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table; use Filament\Tables\Table;
@@ -30,17 +32,17 @@ class DataErasureRequestResource extends Resource
{ {
protected static ?string $model = DataErasureRequest::class; protected static ?string $model = DataErasureRequest::class;
protected static ?string $navigationIcon = 'heroicon-o-shield-exclamation'; protected static string | \BackedEnum | null $navigationIcon = 'heroicon-o-shield-exclamation';
protected static ?string $navigationGroup = 'Privacy'; protected static string | \UnitEnum | null $navigationGroup = 'Privacy';
protected static ?string $modelLabel = 'Erasure Request'; protected static ?string $modelLabel = 'Erasure Request';
protected static ?string $pluralModelLabel = 'Erasure Requests'; protected static ?string $pluralModelLabel = 'Erasure Requests';
public static function form(Form $form): Form public static function form(Schema $schema): Schema
{ {
return $form->schema([ return $schema->components([
Placeholder::make('subject') Placeholder::make('subject')
->label('Subject') ->label('Subject')
->content(fn (DataErasureRequest $record) => sprintf( ->content(fn (DataErasureRequest $record) => sprintf(
@@ -139,7 +141,7 @@ class DataErasureRequestResource extends Resource
]; ];
}), }),
]) ])
->actions([ ->recordActions([
ViewAction::make(), ViewAction::make(),
Action::make('cancel') Action::make('cancel')
->label('Cancel') ->label('Cancel')
@@ -154,8 +156,8 @@ class DataErasureRequestResource extends Resource
public static function getPages(): array public static function getPages(): array
{ {
return [ return [
'index' => Pages\ListDataErasureRequests::route('/'), 'index' => ListDataErasureRequests::route('/'),
'view' => Pages\ViewDataErasureRequest::route('/{record}'), 'view' => ViewDataErasureRequest::route('/{record}'),
]; ];
} }
@@ -2,12 +2,14 @@
namespace Modules\Core\Privacy\Filament\Resources; namespace Modules\Core\Privacy\Filament\Resources;
use Filament\Schemas\Schema;
use Filament\Actions\ViewAction;
use Filament\Actions\Action;
use Modules\Core\Privacy\Filament\Resources\DataExportRequestResource\Pages\ListDataExportRequests;
use Modules\Core\Privacy\Filament\Resources\DataExportRequestResource\Pages\ViewDataExportRequest;
use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table; use Filament\Tables\Table;
@@ -25,17 +27,17 @@ class DataExportRequestResource extends Resource
{ {
protected static ?string $model = DataExportRequest::class; protected static ?string $model = DataExportRequest::class;
protected static ?string $navigationIcon = 'heroicon-o-arrow-down-tray'; protected static string | \BackedEnum | null $navigationIcon = 'heroicon-o-arrow-down-tray';
protected static ?string $navigationGroup = 'Privacy'; protected static string | \UnitEnum | null $navigationGroup = 'Privacy';
protected static ?string $modelLabel = 'Export Request'; protected static ?string $modelLabel = 'Export Request';
protected static ?string $pluralModelLabel = 'Export Requests'; protected static ?string $pluralModelLabel = 'Export Requests';
public static function form(Form $form): Form public static function form(Schema $schema): Schema
{ {
return $form->schema([ return $schema->components([
Placeholder::make('subject') Placeholder::make('subject')
->label('Subject') ->label('Subject')
->content(fn (DataExportRequest $record) => sprintf( ->content(fn (DataExportRequest $record) => sprintf(
@@ -100,7 +102,7 @@ class DataExportRequestResource extends Resource
ExportRequestStatus::Failed->value => 'Failed', ExportRequestStatus::Failed->value => 'Failed',
]), ]),
]) ])
->actions([ ->recordActions([
ViewAction::make(), ViewAction::make(),
Action::make('download') Action::make('download')
->label('Download') ->label('Download')
@@ -113,8 +115,8 @@ class DataExportRequestResource extends Resource
public static function getPages(): array public static function getPages(): array
{ {
return [ return [
'index' => Pages\ListDataExportRequests::route('/'), 'index' => ListDataExportRequests::route('/'),
'view' => Pages\ViewDataExportRequest::route('/{record}'), 'view' => ViewDataExportRequest::route('/{record}'),
]; ];
} }
+2 -1
View File
@@ -2,6 +2,7 @@
namespace Modules\Core\Privacy\Jobs; namespace Modules\Core\Privacy\Jobs;
use Throwable;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
@@ -60,7 +61,7 @@ class ExportDataSubjectJob implements ShouldQueue
)); ));
} }
public function failed(\Throwable $exception): void public function failed(Throwable $exception): void
{ {
$this->request->update(['status' => ExportRequestStatus::Failed]); $this->request->update(['status' => ExportRequestStatus::Failed]);
} }
+2 -1
View File
@@ -2,6 +2,7 @@
namespace Modules\Core\Privacy; namespace Modules\Core\Privacy;
use LogicException;
use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Container\Container;
use Modules\Core\Privacy\Contracts\PersonalDataProvider; use Modules\Core\Privacy\Contracts\PersonalDataProvider;
@@ -41,7 +42,7 @@ class PrivacyManager
$duplicates = array_diff_assoc($names, array_unique($names)); $duplicates = array_diff_assoc($names, array_unique($names));
if ($duplicates !== []) { if ($duplicates !== []) {
throw new \LogicException( throw new LogicException(
'Duplicate Modules\Core\Privacy provider name(s): '.implode(', ', array_unique($duplicates)) 'Duplicate Modules\Core\Privacy provider name(s): '.implode(', ', array_unique($duplicates))
.'. Each provider registered in config(\'core.privacy.providers\') must return a unique name().' .'. Each provider registered in config(\'core.privacy.providers\') must return a unique name().'
); );
@@ -2,9 +2,9 @@
namespace Modules\Core\Privacy\RelationManagers; namespace Modules\Core\Privacy\RelationManagers;
use Filament\Actions\ViewAction;
use Filament\Actions\Action;
use Filament\Resources\RelationManagers\RelationManager; use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table; use Filament\Tables\Table;
@@ -65,7 +65,7 @@ class ErasureRequestsRelationManager extends RelationManager
]), ]),
]) ])
->headerActions([]) ->headerActions([])
->actions([ ->recordActions([
ViewAction::make() ViewAction::make()
->url(fn (DataErasureRequest $record) => DataErasureRequestResource::getUrl('view', ['record' => $record])), ->url(fn (DataErasureRequest $record) => DataErasureRequestResource::getUrl('view', ['record' => $record])),
Action::make('cancel') Action::make('cancel')
@@ -2,9 +2,9 @@
namespace Modules\Core\Privacy\RelationManagers; namespace Modules\Core\Privacy\RelationManagers;
use Filament\Actions\ViewAction;
use Filament\Actions\Action;
use Filament\Resources\RelationManagers\RelationManager; use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table; use Filament\Tables\Table;
@@ -56,7 +56,7 @@ class ExportRequestsRelationManager extends RelationManager
]), ]),
]) ])
->headerActions([]) ->headerActions([])
->actions([ ->recordActions([
ViewAction::make() ViewAction::make()
->url(fn (DataExportRequest $record) => DataExportRequestResource::getUrl('view', ['record' => $record])), ->url(fn (DataExportRequest $record) => DataExportRequestResource::getUrl('view', ['record' => $record])),
Action::make('download') Action::make('download')
@@ -2,11 +2,11 @@
namespace Modules\Core\Privacy\RelationManagers; namespace Modules\Core\Privacy\RelationManagers;
use Filament\Actions\Action;
use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Checkbox;
use Filament\Infolists\Components\RepeatableEntry; use Filament\Infolists\Components\RepeatableEntry;
use Filament\Infolists\Components\TextEntry; use Filament\Infolists\Components\TextEntry;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Tables\Actions\Action;
use Filament\Tables\Table; use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Modules\Core\Customer\RelationManagers\UserRelationManager as CoreUserRelationManager; use Modules\Core\Customer\RelationManagers\UserRelationManager as CoreUserRelationManager;
@@ -31,7 +31,7 @@ class UserRelationManager extends CoreUserRelationManager
{ {
$table = parent::getDefaultTable($table); $table = parent::getDefaultTable($table);
return $table->actions([ return $table->recordActions([
...$table->getActions(), ...$table->getActions(),
Action::make('privacyRequests') Action::make('privacyRequests')
->label('Privacy Requests') ->label('Privacy Requests')
@@ -39,14 +39,14 @@ class UserRelationManager extends CoreUserRelationManager
->modalHeading(fn (Model $record) => "Privacy requests for {$record->name}") ->modalHeading(fn (Model $record) => "Privacy requests for {$record->name}")
->modalSubmitAction(false) ->modalSubmitAction(false)
->modalCancelActionLabel('Close') ->modalCancelActionLabel('Close')
->infolist(fn (Model $record) => $this->requestsInfolist($record)), ->schema(fn (Model $record) => $this->requestsInfolist($record)),
Action::make('requestErasure') Action::make('requestErasure')
->label('Request Erasure') ->label('Request Erasure')
->icon('heroicon-o-shield-exclamation') ->icon('heroicon-o-shield-exclamation')
->color('danger') ->color('danger')
->requiresConfirmation() ->requiresConfirmation()
->modalDescription('Opens a cancellable grace-period erasure request for this individual — deactivates their login and detaches them from every linked Customer account once it completes. No Customer account\'s own data is affected.') ->modalDescription('Opens a cancellable grace-period erasure request for this individual — deactivates their login and detaches them from every linked Customer account once it completes. No Customer account\'s own data is affected.')
->form([ ->schema([
Checkbox::make('immediate') Checkbox::make('immediate')
->label('Erase immediately (skip the 30-day grace period)') ->label('Erase immediately (skip the 30-day grace period)')
->helperText('Staff-only, for a formal legal request or regulator inquiry that genuinely requires urgency — not a routine deletion. Runs synchronously, cannot be cancelled once submitted.') ->helperText('Staff-only, for a formal legal request or regulator inquiry that genuinely requires urgency — not a routine deletion. Runs synchronously, cannot be cancelled once submitted.')
@@ -47,7 +47,7 @@ class ShippingMethodResourceExtension extends ResourceExtension
} }
if (in_array(HasChildComponents::class, class_uses_recursive($component), true)) { if (in_array(HasChildComponents::class, class_uses_recursive($component), true)) {
$component->schema($this->replaceNameField($component->getChildComponents())); $component->schema($this->replaceNameField($component->getDefaultChildComponents()));
} }
return $component; return $component;
@@ -158,7 +158,7 @@ class ShippingMethodResourceExtension extends ResourceExtension
if (in_array(HasChildComponents::class, class_uses_recursive($component), true)) { if (in_array(HasChildComponents::class, class_uses_recursive($component), true)) {
$component->schema( $component->schema(
$this->replaceChargeByField($component->getChildComponents()) $this->replaceChargeByField($component->getDefaultChildComponents())
); );
} }
@@ -269,7 +269,7 @@ class ShippingMethodResourceExtension extends ResourceExtension
if (in_array(HasChildComponents::class, class_uses_recursive($component), true)) { if (in_array(HasChildComponents::class, class_uses_recursive($component), true)) {
$component->schema( $component->schema(
$this->replaceDriverField($component->getChildComponents()) $this->replaceDriverField($component->getDefaultChildComponents())
); );
} }