components([ Section::make()->schema([ TextInput::make('name') ->label(__('panel.roles.fields.name')) ->required() ->maxLength(120) ->rules(fn ($record) => [ Rule::unique('roles', 'name')->ignore($record?->id), ]) // Renaming a structural role would break the code that // looks it up by name. ->disabled(fn ($record) => $record && in_array($record->name, Permissions::protectedRoles(), true)) ->helperText(fn ($record) => $record && in_array($record->name, Permissions::protectedRoles(), true) ? __('panel.roles.protected') : null), ]), // One collapsible section per resource, generated from // App\Support\Permissions — adding a permission there makes it // appear here with no further work. // // Each group writes to its own state path rather than binding the // `permissions` relationship directly: several components sharing // one relationship would overwrite each other on save. The page // classes flatten these back into a single syncPermissions() call // (see HandlesRolePermissions). ...collect(Permissions::grouped()) ->map(fn (array $permissions, string $group) => Section::make( __("panel.permissions.groups.{$group}") ) ->collapsible() ->collapsed($group !== 'general') ->schema([ CheckboxList::make("permission_groups.{$group}") ->hiddenLabel() ->options(collect($permissions) ->mapWithKeys(fn (string $name) => [$name => self::abilityLabel($name)]) ->all()) ->bulkToggleable() ->columns(3), ])) ->values() ->all(), ]); } /** * Human label for a permission, e.g. "pages.force_delete" becomes * "Eliminar definitivamente". */ public static function abilityLabel(string $permission): string { if ($permission === Permissions::PANEL_ACCESS) { return __('panel.permissions.abilities.panel_access'); } $ability = str_contains($permission, '.') ? substr($permission, strpos($permission, '.') + 1) : $permission; $key = "panel.permissions.abilities.{$ability}"; $label = __($key); // Fall back to the raw name if the catalogue grows a permission that // has no translation yet, rather than printing the missing key. return $label === $key ? $permission : $label; } }