Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
86 lines
3.3 KiB
PHP
86 lines
3.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Resources\Roles\Schemas;
|
|
|
|
use App\Support\Permissions;
|
|
use Filament\Forms\Components\CheckboxList;
|
|
use Filament\Forms\Components\TextInput;
|
|
use Filament\Schemas\Components\Section;
|
|
use Filament\Schemas\Schema;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class RoleForm
|
|
{
|
|
public static function configure(Schema $schema): Schema
|
|
{
|
|
return $schema->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;
|
|
}
|
|
}
|