components([ // Everything the identity server owns. Shown for context, disabled // because any edit here would be overwritten on the user's next // sign-in — these fields are changed at oauth.pireon.dev. Section::make(__('panel.users.sections.identity')) ->description(__('panel.users.sections.identity_hint')) ->columns(2) ->schema([ TextInput::make('name') ->label(__('panel.users.fields.name')) ->disabled(), TextInput::make('email') ->label(__('panel.users.fields.email')) ->disabled(), TextInput::make('oauth_id') ->label(__('panel.users.fields.oauth_id')) ->disabled(), TextInput::make('remote_roles') ->label(__('panel.users.fields.remote_roles')) ->formatStateUsing(fn ($state) => implode(', ', (array) $state) ?: '—') ->helperText(__('pireon.account.remote_roles_hint')) ->disabled() ->dehydrated(false), ]), // Everything this application owns. Section::make(__('panel.users.sections.access')) ->description(__('panel.users.sections.access_hint')) ->columns(2) ->schema([ Select::make('roles') ->label(__('panel.users.fields.roles')) ->relationship('roles', 'name') ->multiple() ->preload() ->searchable() // Only a super admin can hand out super_admin; without // this, an admin could promote themselves. ->options(fn () => Role::query() ->when( ! Auth::user()?->hasRole('super_admin'), fn ($q) => $q->where('name', '!=', 'super_admin') ) ->pluck('name', 'name') ->all()) ->saveRelationshipsUsing(function ($record, ?array $state): void { $roles = $state ?? []; // Preserve a super_admin assignment the current // editor was not allowed to see in the list. if ($record->hasRole('super_admin') && ! Auth::user()?->hasRole('super_admin')) { $roles[] = 'super_admin'; } $record->syncRoles(array_unique($roles)); }) ->columnSpanFull(), Select::make('locale') ->label(__('panel.users.fields.locale')) ->options(fn () => collect(config('locales.supported')) ->map(fn (array $meta, string $code) => $meta['native'] ?? $code) ->all()) ->native(false), Toggle::make('is_active') ->label(__('panel.users.fields.is_active')) // Deactivating locally cuts off both the panel and the // API immediately, without touching the OAuth server. ->disabled(fn ($record) => $record?->id === Auth::id()), ]), ]); } }