5587026446
1. Roles list now uses a Rappasoft table (RoleTable): search/sort, per-row
view/edit/delete, and built-in bulk selection + 'Delete selected'. The
/admin/roles page is a plain view embedding <livewire:role-table />.
RoleForm create/edit now only has Name + Description (permissions removed).
2. New RoleView page (/admin/roles/{role}) with two tabs:
- 'Details': header with role name + Back button; description with Edit/Delete
buttons; table of users holding the role (avatar+name | last name | status).
- 'Permissions': all permissions grouped by section (by resource), each with a
toggle switch to grant/revoke for this role (Admin keeps 'manage all').
Removed the old RoleManager component/view (superseded).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
96 lines
3.0 KiB
PHP
96 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire;
|
|
|
|
use Livewire\Component;
|
|
use Livewire\Attributes\Layout;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Str;
|
|
use Spatie\Permission\Models\Role;
|
|
use Spatie\Permission\Models\Permission;
|
|
use Spatie\Permission\PermissionRegistrar;
|
|
|
|
#[Layout('layouts.app')]
|
|
class RoleView extends Component
|
|
{
|
|
public Role $role;
|
|
public string $tab = 'ficha'; // ficha | permisos
|
|
|
|
private const PROTECTED_ROLES = ['Admin'];
|
|
private const CORE_PERMISSION = 'manage all';
|
|
|
|
public function mount(Role $role): void
|
|
{
|
|
abort_unless(Auth::user()?->can(self::CORE_PERMISSION), 403);
|
|
$this->role = $role;
|
|
}
|
|
|
|
public function setTab(string $tab): void
|
|
{
|
|
$this->tab = in_array($tab, ['ficha', 'permisos'], true) ? $tab : 'ficha';
|
|
}
|
|
|
|
public function togglePermission(string $permissionName): void
|
|
{
|
|
// Admin must always keep the core permission
|
|
if ($this->role->name === 'Admin'
|
|
&& $permissionName === self::CORE_PERMISSION
|
|
&& $this->role->hasPermissionTo($permissionName)) {
|
|
$this->dispatch('notify', "El rol Admin no puede perder '" . self::CORE_PERMISSION . "'.");
|
|
return;
|
|
}
|
|
|
|
if ($this->role->hasPermissionTo($permissionName)) {
|
|
$this->role->revokePermissionTo($permissionName);
|
|
} else {
|
|
$this->role->givePermissionTo($permissionName);
|
|
}
|
|
|
|
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
|
$this->role->load('permissions');
|
|
$this->dispatch('notify', 'Permisos actualizados');
|
|
}
|
|
|
|
public function delete()
|
|
{
|
|
if (in_array($this->role->name, self::PROTECTED_ROLES, true)) {
|
|
$this->dispatch('notify', "El rol '{$this->role->name}' está protegido y no se puede borrar.");
|
|
return;
|
|
}
|
|
$this->role->delete();
|
|
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
|
session()->flash('message', 'Rol eliminado.');
|
|
|
|
return $this->redirect(route('admin.roles'), navigate: true);
|
|
}
|
|
|
|
/** Section title for a permission name (groups by the resource / last word). */
|
|
private function sectionFor(string $name): string
|
|
{
|
|
if ($name === self::CORE_PERMISSION) {
|
|
return 'General';
|
|
}
|
|
$resource = Str::afterLast($name, ' ');
|
|
return Str::headline($resource ?: 'General');
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
$users = $this->role->users()
|
|
->orderBy('first_name')
|
|
->orderBy('name')
|
|
->get();
|
|
|
|
$grouped = Permission::orderBy('name')->get()
|
|
->groupBy(fn ($perm) => $this->sectionFor($perm->name))
|
|
->sortKeys();
|
|
|
|
return view('livewire.roles.role-view', [
|
|
'users' => $users,
|
|
'grouped' => $grouped,
|
|
'rolePerms' => $this->role->permissions->pluck('name')->toArray(),
|
|
'isProtected' => in_array($this->role->name, self::PROTECTED_ROLES, true),
|
|
]);
|
|
}
|
|
}
|