columns(1) ->components([ Section::make(__('User Information')) ->schema([ TextInput::make('name') ->label(__('Name')) ->required() ->maxLength(255), TextInput::make('username') ->label(__('Username')) ->required() ->maxLength(32) ->alphaNum() ->unique(ignoreRecord: true) ->rules(['regex:/^[a-z][a-z0-9_]{0,31}$/']) ->helperText(__('Lowercase letters, numbers, and underscores only. Must start with a letter.')) ->disabled(fn (string $operation): bool => $operation === 'edit'), TextInput::make('email') ->label(__('Email address')) ->email() ->required() ->unique(ignoreRecord: true) ->maxLength(255), TextInput::make('password') ->password() ->revealable() ->dehydrateStateUsing(fn ($state) => filled($state) ? Hash::make($state) : null) ->dehydrated(fn ($state) => filled($state)) ->required(fn (string $operation): bool => $operation === 'create') ->minLength(8) ->rules([ 'regex:/[a-z]/', // lowercase 'regex:/[A-Z]/', // uppercase 'regex:/[0-9]/', // number ]) ->suffixActions([ Action::make('generatePassword') ->icon('heroicon-o-arrow-path') ->tooltip(__('Generate secure password')) ->action(function ($set) { $password = self::generateSecurePassword(); $set('password', $password); }), Action::make('copyPassword') ->icon('heroicon-o-clipboard-document') ->tooltip(__('Copy to clipboard')) ->action(function ($state, $livewire) { if ($state) { $escaped = addslashes($state); $livewire->js("navigator.clipboard.writeText('{$escaped}')"); \Filament\Notifications\Notification::make() ->title(__('Copied to clipboard')) ->success() ->duration(2000) ->send(); } }), ]) ->helperText(__('Minimum 8 characters with uppercase, lowercase, and numbers')) ->label(fn (string $operation): string => $operation === 'create' ? __('Password') : __('New Password')), ]) ->columns(2), Section::make(__('Account Settings')) ->schema([ Toggle::make('is_admin') ->label(__('Administrator')) ->helperText(__('Grant full administrative access')) ->inline(false), Toggle::make('is_active') ->label(__('Active')) ->default(true) ->helperText(__('Inactive users cannot log in')) ->inline(false), Toggle::make('create_linux_user') ->label(__('Create Linux User')) ->default(true) ->helperText(__('Create a system user account')) ->visibleOn('create') ->dehydrated(false) ->inline(false), DateTimePicker::make('email_verified_at') ->label(__('Email Verified At')), ]) ->columns(4), Section::make(__('Disk Quota')) ->schema([ Placeholder::make('current_usage') ->label(__('Current Usage')) ->content(function ($record) { if (!$record) { return __('N/A'); } $used = $record->disk_usage_formatted; $quotaMb = $record->disk_quota_mb; if (!$quotaMb || $quotaMb <= 0) { return "{$used} (" . __('Unlimited') . ")"; } $quota = $quotaMb >= 1024 ? number_format($quotaMb / 1024, 1) . ' GB' : $quotaMb . ' MB'; $percent = $record->disk_usage_percent; return "{$used} / {$quota} ({$percent}%)"; }) ->visibleOn('edit'), Toggle::make('unlimited_quota') ->label(__('Unlimited Quota')) ->helperText(__('No disk space limit')) ->default(fn () => (int) DnsSetting::get('default_quota_mb', 5120) === 0) ->live() ->afterStateHydrated(function (Toggle $component, $state, $record) { if ($record) { $component->state(!$record->disk_quota_mb || $record->disk_quota_mb <= 0); } }) ->afterStateUpdated(function ($state, callable $set) { if ($state) { $set('disk_quota_mb', 0); } else { $set('disk_quota_mb', (int) DnsSetting::get('default_quota_mb', 5120)); } }) ->inline(false), TextInput::make('disk_quota_mb') ->label(__('Disk Quota')) ->numeric() ->minValue(1) ->default(fn () => (int) DnsSetting::get('default_quota_mb', 5120)) ->helperText(fn ($state) => $state && $state > 0 ? number_format($state / 1024, 1) . ' GB' : null) ->suffix('MB') ->visible(fn ($get) => !$get('unlimited_quota')) ->required(fn ($get) => !$get('unlimited_quota')), ]) ->description(fn () => !(bool) DnsSetting::get('quotas_enabled', false) ? __('Note: Quotas are currently disabled in Server Settings.') : null) ->columns(3), Section::make(__('System Information')) ->schema([ Placeholder::make('home_directory_display') ->label(__('Home Directory')) ->content(fn ($record) => $record?->home_directory ?? '/home/' . __('username')), Placeholder::make('created_at_display') ->label(__('Created')) ->content(fn ($record) => $record?->created_at?->format('M d, Y H:i') ?? __('N/A')), Placeholder::make('updated_at_display') ->label(__('Last Updated')) ->content(fn ($record) => $record?->updated_at?->format('M d, Y H:i') ?? __('N/A')), ]) ->columns(3) ->visibleOn('edit') ->collapsible(), ]); } }