88 lines
4.6 KiB
PHP
88 lines
4.6 KiB
PHP
<div class="mx-auto max-w-[1120px] space-y-6">
|
|
<div class="animate-rise">
|
|
<h1 class="text-2xl font-bold tracking-tight text-ink">{{ __('roles.title') }}</h1>
|
|
<p class="mt-1 max-w-[70ch] text-sm text-muted">{{ __('roles.subtitle') }}</p>
|
|
</div>
|
|
|
|
{{-- 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. --}}
|
|
<div class="flex flex-wrap items-end gap-3 rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise">
|
|
<div class="min-w-56 flex-1">
|
|
<x-ui.input name="newRole" wire:model="newRole"
|
|
:label="__('roles.new_label')" :hint="__('roles.new_hint')" />
|
|
</div>
|
|
<x-ui.button variant="primary" wire:click="create" wire:loading.attr="disabled" wire:target="create">
|
|
{{ __('roles.create') }}
|
|
</x-ui.button>
|
|
</div>
|
|
|
|
@foreach ($roles as $role)
|
|
@php $isProtected = $role->name === $protectedRole; @endphp
|
|
<div wire:key="role-{{ $role->id }}"
|
|
class="space-y-4 rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise">
|
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
|
<div class="min-w-0">
|
|
<h2 class="flex flex-wrap items-center gap-2 font-semibold text-ink">
|
|
{{ $role->name }}
|
|
@if ($isProtected)
|
|
<span class="rounded-pill border border-warning-border bg-warning-bg px-2.5 py-0.5 text-xs font-medium text-warning">
|
|
{{ __('roles.locked_badge') }}
|
|
</span>
|
|
@endif
|
|
@if (in_array($role->name, $ownRoles, true))
|
|
<span class="rounded-pill border border-info-border bg-info-bg px-2.5 py-0.5 text-xs font-medium text-info">
|
|
{{ __('roles.your_role') }}
|
|
</span>
|
|
@endif
|
|
</h2>
|
|
<p class="mt-0.5 text-xs text-muted">
|
|
{{ trans_choice('roles.holders', $role->users_count, ['count' => $role->users_count]) }}
|
|
</p>
|
|
</div>
|
|
|
|
@unless ($isProtected)
|
|
<div class="flex flex-wrap gap-2">
|
|
<x-ui.button variant="primary" wire:click="save({{ $role->id }})"
|
|
wire:loading.attr="disabled" wire:target="save({{ $role->id }})">
|
|
{{ __('common.save') }}
|
|
</x-ui.button>
|
|
@if ($role->users_count === 0)
|
|
<x-ui.button variant="ghost" wire:click="delete({{ $role->id }})"
|
|
wire:loading.attr="disabled" wire:target="delete({{ $role->id }})">
|
|
{{ __('roles.delete') }}
|
|
</x-ui.button>
|
|
@endif
|
|
</div>
|
|
@endunless
|
|
</div>
|
|
|
|
@error('granted.'.$role->id)<p class="text-xs text-danger">{{ $message }}</p>@enderror
|
|
|
|
@if ($isProtected)
|
|
<p class="text-sm text-muted">{{ __('roles.owner_locked') }}</p>
|
|
@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. --}}
|
|
<div class="grid grid-cols-1 gap-x-6 gap-y-2 sm:grid-cols-2 lg:grid-cols-3">
|
|
@foreach ($permissions as $permission)
|
|
<label class="flex items-start gap-2 text-sm text-body">
|
|
<input type="checkbox" value="{{ $permission }}"
|
|
wire:model="granted.{{ $role->id }}"
|
|
@disabled($isProtected)
|
|
class="mt-0.5 size-4 shrink-0 rounded border-line-strong accent-[var(--accent-active)] disabled:opacity-50">
|
|
<span class="min-w-0">
|
|
<span class="font-mono text-xs">{{ $permission }}</span>
|
|
<span class="block text-xs text-muted">{{ __('roles.can.'.$permission) }}</span>
|
|
</span>
|
|
</label>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
|
|
@error('newRole')<p class="text-sm text-danger">{{ $message }}</p>@enderror
|
|
</div>
|