diff --git a/app/Livewire/Admin/Roles.php b/app/Livewire/Admin/Roles.php index ad24f95..d9bb28d 100644 --- a/app/Livewire/Admin/Roles.php +++ b/app/Livewire/Admin/Roles.php @@ -154,6 +154,13 @@ class Roles extends Component ->withCount('users') ->orderBy('name') ->get(), + // Nach dem Präfix gruppiert — die Namen tragen ihre Ordnung längst + // in sich (`billing.`, `customers.`, `provisioning.`), und + // einundzwanzig Kästchen flach untereinander sind eine Wand, in + // der niemand das eine findet, das er sucht. + 'groups' => collect($this->allPermissions()) + ->groupBy(fn (string $name) => str_contains($name, '.') ? strtok($name, '.') : 'sonstiges') + ->sortKeys(), 'permissions' => $this->allPermissions(), // Wie viele Menschen an dieser Rolle hängen — damit niemand blind // etwas wegnimmt, das gerade sechs Leute benutzen. diff --git a/lang/de/roles.php b/lang/de/roles.php index 78e33c5..268318f 100644 --- a/lang/de/roles.php +++ b/lang/de/roles.php @@ -16,6 +16,8 @@ return [ 'in_use' => 'Die Rolle :role wird noch gehalten. Wer sie hat, stünde beim nächsten Anmelden ohne Rolle da und käme nicht mehr in die Konsole.', 'holders' => '{0} Niemand hat diese Rolle|{1} :count Person hat diese Rolle|[2,*] :count Personen haben diese Rolle', + 'granted_count' => ':granted von :total Rechten', + 'can' => [ 'billing.manage' => 'Rechnungen, Gutschriften, Zahlungsprobleme', 'console.view' => 'Die Konsole überhaupt betreten', diff --git a/lang/en/roles.php b/lang/en/roles.php index 9a01b1e..cba9a4e 100644 --- a/lang/en/roles.php +++ b/lang/en/roles.php @@ -16,6 +16,8 @@ return [ 'in_use' => 'The role :role is still held. Whoever has it would be left with no role on their next sign-in and could not enter the console.', 'holders' => '{0} Nobody holds this role|{1} :count person holds this role|[2,*] :count people hold this role', + 'granted_count' => ':granted of :total capabilities', + 'can' => [ 'billing.manage' => 'Invoices, credit notes, payment problems', 'console.view' => 'Enter the console at all', diff --git a/resources/views/livewire/admin/roles.blade.php b/resources/views/livewire/admin/roles.blade.php index 4bcff90..95edf75 100644 --- a/resources/views/livewire/admin/roles.blade.php +++ b/resources/views/livewire/admin/roles.blade.php @@ -4,84 +4,113 @@

{{ __('roles.subtitle') }}

- {{-- Neue Rolle. Ein Feld, ein Knopf — die Rechte bekommt sie danach in - ihrer eigenen Karte, weil eine leere Rolle noch nichts kaputtmachen - kann und die Matrix im selben Formular unlesbar würde. --}} -
-
- -
- - {{ __('roles.create') }} - -
+ {{-- Neue Rolle. - @foreach ($roles as $role) - @php $isProtected = $role->name === $protectedRole; @endphp -
-
-
-

- {{ $role->name }} + Vorher stand das Feld auf `flex-1` neben einem Knopf ohne `shrink-0`, + und beide auf `items-end` — bei schmalem Fenster schob der Hinweistext + unter dem Feld den Knopf aus der Karte heraus. Jetzt ein Raster mit + zwei Spuren: das Feld nimmt, was übrig ist, der Knopf behält seine + Breite, und der Hinweis steht UNTER der Reihe statt in ihr. --}} +
+
+ + + {{ __('roles.create') }} + +
+

{{ __('roles.new_hint') }}

+ @error('newRole')

{{ $message }}

@enderror +
+ + {{-- Eine Karte je Rolle, zugeklappt. + + Sechs Rollen mal einundzwanzig Rechte waren über hundert Kästchen + untereinander — man scrollte an der Rolle vorbei, die man ändern + wollte. Zugeklappt ist die Seite sechs Zeilen lang, und die Zeile sagt + schon, was sie enthält: wie viele Rechte, wie viele Menschen. --}} +
+ @foreach ($roles as $role) + @php + $isProtected = $role->name === $protectedRole; + // NICHT $granted nennen: das ist die Eigenschaft des + // Bauteils, und in der zweiten Runde der Schleife wäre sie + // eine Zahl statt der Liste. + $grantedCount = count($granted[$role->id] ?? []); + @endphp +
+ + {{-- Die Kopfzeile IST der Schalter. Ein eigener Pfeil-Knopf + daneben wäre ein zweites Ziel für dieselbe Absicht. --}} +

-

- {{ trans_choice('roles.holders', $role->users_count, ['count' => $role->users_count]) }} -

-
+ - @unless ($isProtected) -
- - {{ __('common.save') }} - - @if ($role->users_count === 0) - - {{ __('roles.delete') }} - - @endif + + {{ __('roles.granted_count', ['granted' => $grantedCount, 'total' => count($permissions)]) }} + + {{ trans_choice('roles.holders', $role->users_count, ['count' => $role->users_count]) }} + + + +
+ @if ($isProtected) + {{ __('roles.owner_locked') }} + @endif + + @error('granted.'.$role->id)

{{ $message }}

@enderror + +
+ @foreach ($groups as $prefix => $names) +
+

{{ $prefix }}

+
+ @foreach ($names as $permission) + + @endforeach +
+
+ @endforeach
- @endunless + + @unless ($isProtected) +
+ + {{ __('common.save') }} + + @if ($role->users_count === 0) + + {{ __('roles.delete') }} + + @endif +
+ @endunless +
- - @error('granted.'.$role->id)

{{ $message }}

@enderror - - @if ($isProtected) -

{{ __('roles.owner_locked') }}

- @endif - - {{-- Die Matrix. Auch für Owner sichtbar, nur nicht änderbar: was - der Owner darf, ist die Antwort auf „was gibt es überhaupt", - und die soll man nachlesen können. --}} -
- @foreach ($permissions as $permission) - - @endforeach -
-
- @endforeach - - @error('newRole')

{{ $message }}

@enderror + @endforeach +
diff --git a/tests/Feature/Admin/RoleManagementTest.php b/tests/Feature/Admin/RoleManagementTest.php index 35914ab..50134c1 100644 --- a/tests/Feature/Admin/RoleManagementTest.php +++ b/tests/Feature/Admin/RoleManagementTest.php @@ -121,3 +121,28 @@ it('is not reachable without staff.manage', function () { ->test(Roles::class) ->assertForbidden(); }); + +it('keeps counting capabilities correctly past the first role', function () { + // Ein Fehler, den ich beim Umbau selbst gebaut habe: die Ansicht nannte + // die Zählvariable `$granted` — genauso wie die Eigenschaft des Bauteils. + // Ab der zweiten Rolle war sie eine Zahl statt der Liste, und die Seite + // starb an `count(int)`. Mit einer Rolle wäre es nie aufgefallen. + Role::findOrCreate('Buchhaltung', 'operator')->givePermissionTo('console.view'); + Role::findOrCreate('Werkstatt', 'operator'); + + Livewire::actingAs(operator('Owner'), 'operator') + ->test(Roles::class) + ->assertOk() + ->assertSee('Buchhaltung') + ->assertSee('Werkstatt'); +}); + +it('groups the capabilities instead of listing twenty-one in a row', function () { + $groups = Livewire::actingAs(operator('Owner'), 'operator') + ->test(Roles::class) + ->viewData('groups'); + + expect($groups)->toHaveKey('billing') + ->and($groups)->toHaveKey('provisioning') + ->and(count($groups))->toBeLessThan(21); +});