Hello everybody,
Just looking for guidance, suggestions and quality of life improvements for future developement.
I'm creating an admin control panel for Spatie Laravel Permissions, using Flux UI Pro.
With the below code I have crud functionality to add/edit/delete and view: users, roles and permissions. I've also implemented the logic so that if you can't "add permission" that it throws errors where needed etc.
Once I've finished I'll use this boilerplate for next applications such as blogs, site settings etc.
Known issues:
- When using paginate the query string from list.blade.php will also try and change the pages of roles and permissions. (temp fix: removed pagination from roles and permissions).
Fixed by, and thank you: @tykus
Todo:
index.blade.php
<?php
use Livewire\Attributes\{Url, Layout, On};
use Livewire\Volt\Component;
new class extends Component {
#[Url]
#[Layout('layouts.admin')]
public $tab = 'user-list';
#[On('refreshComponents')]
public function refreshComponents()
{
$this->dispatch('refreshComponents')->to('admin.user-management.list');
$this->dispatch('refreshComponents')->to('admin.user-management.roles');
$this->dispatch('refreshComponents')->to('admin.user-management.permissions');
}
}; ?>
<section>
<x-slot name="heading">
User Management
</x-slot>
<x-slot name="subheading">
A place for you to control the users, roles and permissions.
</x-slot>
<div class="container">
<div class="w-full md:w-1/2 mx-auto">
<flux:tab.group>
<flux:tabs wire:model="tab">
@can('view users')
<flux:tab name="user-list">Users</flux:tab>
@endcan
@can('view roles')
<flux:tab name="roles">Roles</flux:tab>
@endcan
@can('view permissions')
<flux:tab name="permissions">Permissions</flux:tab>
@endcan
</flux:tabs>
@can('view users')
<flux:tab.panel name="user-list">
@livewire('admin.user-management.list')
</flux:tab.panel>
@endcan
@can('view roles')
<flux:tab.panel name="roles">
@livewire('admin.user-management.roles')
</flux:tab.panel>
@endcan
@can('view permissions')
<flux:tab.panel name="permissions">
@livewire('admin.user-management.permissions')
</flux:tab.panel>
@endcan
</flux:tab.group>
</div>
</div>
</section>
list.blade.php
<?php
use App\Models\User;
use Illuminate\Validation\Rules;
use Spatie\Permission\Models\Role;
use Livewire\Volt\Component;
use Livewire\WithPagination;
use Livewire\Attributes\{Url, Validate, Computed, On};
/**
* User Management Component
*
* Handles all user management operations including listing, creation,
* editing, and deletion of users with role management integration.
*
* @package App\Livewire
*/
new class extends Component {
use WithPagination;
#[Url]
public $sortBy = 'id';
#[Url]
public $sortDirection = 'asc';
/**
* Form properties for user management
*/
public $userId = '';
public $name = '';
public $email = '';
public $email_verified_at = null;
public $username = '';
public $password = '';
public $password_confirmation = '';
public $roles = [];
public $selectedRoles = [];
public $selectedUser = null;
/**
* Initialize component state
*/
#[On('refreshComponents')]
public function mount(): void
{
if (!auth()->user()->can('view users')) {
throw new AuthorizationException('You do not have permission to delete users.');
}
$this->roles = Role::all();
}
/**
* Handle column sorting
*
* @param string $column The column to sort by
*/
public function sort(string $column): void
{
if ($this->sortBy === $column) {
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
} else {
$this->sortBy = $column;
$this->sortDirection = 'asc';
}
}
/**
* Define validation rules for user data
*
* @param User $user The user being validated
* @return array<string, mixed>
*/
public function rules(User $user): array
{
return [
'name' => 'required|min:3',
'email' => 'required|email|unique:users,email,' . $user->id,
'username' => 'required|unique:users,username,' . $user->id,
'selectedRoles' => 'required',
'password' => ['nullable', 'string', 'confirmed', Rules\Password::defaults()],
];
}
/**
* Get paginated users list with roles
*
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
#[Computed]
public function users()
{
return User::query()
->tap(fn($query) => $this->sortBy ? $query->orderBy($this->sortBy, $this->sortDirection) : $query)
->with('roles')
->paginate(15);
}
/**
* Show the user form modal for adding or editing a user
*
* @param User|null $user The user to edit. If null, shows add form
* @return void
*/
public function showUserForm(?User $user = null): void
{
$this->resetValidation();
if ($user) {
$this->userId = $user->id;
$this->name = $user->name;
$this->email = $user->email;
$this->email_verified_at = ($user->email_verified_at)?true:null;
$this->username = $user->username;
$this->selectedRoles = $user->getRoleNames();
} else {
$this->resetFormFields();
}
Flux::modal('user-form')->show();
}
/**
* Show delete confirmation modal
*
* @param User $user The user to delete
*/
public function confirmDelete(User $user): void
{
$this->selectedUser = $user;
Flux::modal('delete-user')->show();
}
/**
* Reset form fields to default values
*/
private function resetFormFields(): void
{
$this->userId = '';
$this->name = '';
$this->email = '';
$this->username = '';
$this->password = '';
$this->password_confirmation = '';
$this->selectedRoles = [];
$this->selectedUser = null;
}
/**
* Save user data (create or update)
*
* @param int|null $userId ID of user to update, null for create
*/
public function save(?int $userId = null): void
{
$userId ? $this->update(User::find($userId) ?: new User) : $this->create();
}
/**
* Create a new user
*/
public function create(): void
{
if (!auth()->user()->can('create users')) {
throw new AuthorizationException('You do not have permission to delete users.');
}
$this->validate($this->rules(new User()));
$user = User::create([
'name' => $this->name,
'email' => $this->email,
'email_verified_at' => now(),
'username' => $this->username,
'password' => bcrypt($this->password ?: 'password'),
]);
$user->syncRoles($this->selectedRoles);
Flux::modals()->close();
Flux::Toast(variant: 'success', text: 'User added successfully.');
$this->dispatch('refreshComponents');
}
/**
* Update existing user
*
* @param User $user The user to update
*/
public function update(User $user): void
{
if (!auth()->user()->can('edit users')) {
throw new AuthorizationException('You do not have permission to delete users.');
}
$this->validate($this->rules($user));
$user->update([
'name' => $this->name,
'email' => $this->email,
'email_verified_at' => $this->email_verified_at ? now() : null,
'username' => $this->username,
'password' => $this->password ? bcrypt($this->password) : $user->password,
]);
$user->syncRoles($this->selectedRoles);
Flux::modals()->close();
Flux::Toast(variant: 'success', text: 'User updated successfully.');
$this->dispatch('refreshComponents');
}
/**
* Delete selected user
*/
public function delete(): void
{
if (!auth()->user()->can('delete users')) {
throw new AuthorizationException('You do not have permission to delete users.');
}
if ($this->selectedUser) {
$this->selectedUser->delete();
Flux::modals()->close();
Flux::Toast(variant: 'danger', text: 'User deleted successfully.');
$this->resetFormFields();
$this->dispatch('refreshComponents');
}
}
}; ?>
<section>
<div class="flex justify-between items-center">
<div>
<flux:heading>Users</flux:heading>
<flux:subheading>A list of our current users.</flux:subheading>
</div>
<div class="flex">
<flux:spacer />
@can('create users')
<flux:button wire:click="showUserForm">Add User</flux:button>
@endcan
</div>
</div>
<flux:table :paginate="$this->users" class="mt-4">
<flux:columns>
<flux:column sortable :sorted="$sortBy === 'id'" :direction="$sortDirection" wire:click="sort('id')" class="w-2">ID</flux:column>
<flux:column sortable :sorted="$sortBy === 'name'" :direction="$sortDirection" wire:click="sort('name')">Name</flux:column>
<flux:column sortable :sorted="$sortBy === 'email'" :direction="$sortDirection" wire:click="sort('email')">Email</flux:column>
<flux:column>Role(s)</flux:column>
<flux:column></flux:column>
</flux:columns>
<flux:rows>
@foreach ($this->users as $user)
<flux:row :key="$user->id">
<flux:cell class="whitespace-nowrap">{{ $user->id }}</flux:cell>
<flux:cell class="whitespace-nowrap">{{ $user->name }}</flux:cell>
<flux:cell class="whitespace-nowrap">
{{ $user->email }}
@if ($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && ! $user->hasVerifiedEmail())
<flux:badge color="red">unverified</flux:badge>
@elseif ($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && $user->hasVerifiedEmail())
<flux:badge color="green">verified</flux:badge>
@endif
</flux:cell>
<flux:cell class="whitespace-nowrap">
@foreach($user->roles as $role)
<flux:badge>{{ $role->name }}</flux:badge>
@endforeach
</flux:cell>
<flux:cell class="text-right">
@can('edit users')
<flux:button icon="pencil-square" size="sm" inset="top bottom" wire:click="showUserForm({{ $user->id }})" />
@endcan
@can('delete users')
@unless($user->hasRole('Super Admin'))
<flux:button variant="danger" icon="trash" size="sm" inset="top bottom" wire:click="confirmDelete({{ $user->id }})" />
@endunless
@endcan
</flux:cell>
</flux:row>
@endforeach
</flux:rows>
</flux:table>
@canany(['create users', 'edit users'])
<flux:modal variant="flyout" name="user-form" class="space-y-6">
<flux:heading size="lg">{{ (! $this->userId)?'Add':'Edit' }} User</flux:heading>
<flux:input wire:model="name" label="Name:" />
<flux:input wire:model="email" label="Email:" />
@if (Auth::user() instanceof \Illuminate\Contracts\Auth\MustVerifyEmail)
<flux:checkbox wire:model="email_verified_at" label="Verified Email:" />
@endif
<flux:input wire:model="username" label="Username:" />
<flux:select wire:model="selectedRoles" searchable variant="listbox" multiple placeholder="Choose roles..." label="Roles:">
@foreach($this->roles as $role)
<flux:option value="{{ $role->name }}">{{ $role->name }}</flux:option>
@endforeach
</flux:select>
<flux:input label="{{ __('Password') }}" wire:model="password" type="password" description="{{ (! $this->userId)?'Leaving the password blank will give the user a default password of: password':'Leave blank if you do not wish to change the password.' }}" />
<flux:input label="{{ __('Confirm Password') }}" wire:model="password_confirmation" type="password" />
<div class="flex gap-2">
<flux:spacer />
<flux:modal.close>
<flux:button variant="ghost">Cancel</flux:button>
</flux:modal.close>
<flux:button type="submit" variant="primary" wire:click="save({{ $this->userId }})">{{ (! $this->userId)?'Add':'Edit' }} User</flux:button>
</div>
</flux:modal>
@endcanany
@can('delete users')
<flux:modal name="delete-user" class="min-w-[22rem] space-y-6">
<div>
<flux:heading size="lg">Delete User?</flux:heading>
<flux:subheading>
@if($selectedUser)
<p>You're about to delete the user: {{ $selectedUser->name }}.</p>
<p>This action cannot be reversed.</p>
@endif
</flux:subheading>
</div>
<div class="flex gap-2">
<flux:spacer />
<flux:modal.close>
<flux:button variant="ghost">Cancel</flux:button>
</flux:modal.close>
<flux:button type="submit" variant="danger" wire:click="delete">Delete User</flux:button>
</div>
</flux:modal>
@endcan
</section>
roles.blade.php
<?php
use App\Models\User;
use Illuminate\Validation\Rules;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Livewire\Volt\Component;
use Livewire\WithPagination;
use Livewire\Attributes\{Url, Computed, On};
/**
* Role Management Component
*
* Handles all role management operations including listing, creation,
* editing, and deletion of roles with permission management integration.
*
* @package App\Livewire
*/
new class extends Component {
use WithPagination;
#[Url]
public $sortBy = 'id';
#[Url]
public $sortDirection = 'asc';
/**
* Current permissions list
*/
public $permissions = [];
/**
* Form state properties
*/
public $roleId = '';
public $name = '';
public $selectedPermissions = [];
public $selectedRole = null;
/**
* Initialize component state
*/
#[On('refreshComponents')]
public function mount(): void
{
if (!auth()->user()->can('view roles')) {
throw new AuthorizationException('You do not have permission to view roles.');
}
$this->permissions = Permission::all();
}
/**
* Handle column sorting
*
* @param string $column The column to sort by
*/
public function sort(string $column): void
{
if ($this->sortBy === $column) {
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
} else {
$this->sortBy = $column;
$this->sortDirection = 'asc';
}
}
/**
* Get paginated roles list
*
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
#[Computed]
public function roles()
{
return Role::query()
->tap(fn($query) => $this->sortBy ? $query->orderBy($this->sortBy, $this->sortDirection) : $query)
->withCount('permissions')
->paginate(25, pageName: 'roles-page');
}
/**
* Show the role form modal for adding or editing a role
*
* @param Role|null $role The role to edit. If null, shows add form
*/
public function showRoleForm(?Role $role = null): void
{
$this->resetValidation();
if ($role) {
$this->roleId = $role->id;
$this->name = $role->name;
$this->selectedPermissions = $role->permissions->pluck('name')->toArray();
} else {
$this->resetFormFields();
}
Flux::modal('role-form')->show();
}
/**
* Reset form fields to default values
*/
private function resetFormFields(): void
{
$this->roleId = '';
$this->name = '';
$this->selectedPermissions = [];
$this->selectedRole = null;
}
/**
* Show delete confirmation modal
*
* @param Role $role The role to delete
*/
public function confirmDelete(Role $role): void
{
$this->selectedRole = $role;
Flux::modal('delete-role')->show();
}
/**
* Save role data (create or update)
*
* @param int|null $roleId ID of role to update, null for create
*/
public function save(?int $roleId = null): void
{
if (!auth()->user()->can('create roles') ||
!auth()->user()->can('edit roles')) {
throw new AuthorizationException('You do not have permission to create or edit roles.');
}
$this->validate([
'name' => 'required|min:3|unique:roles,name,' . $roleId,
'selectedPermissions' => 'required|array|min:1'
]);
$role = $roleId ? Role::findOrFail($roleId) : Role::create(['name' => $this->name]);
$role->name = $this->name;
$role->save();
$role->syncPermissions($this->selectedPermissions);
Flux::modals()->close();
Flux::toast(
variant: 'success',
text: $roleId ? 'Role updated successfully.' : 'Role added successfully.'
);
$this->dispatch('refreshComponents');
}
/**
* Delete selected role
*/
public function delete(): void
{
if (!auth()->user()->can('delete roles')) {
throw new AuthorizationException('You do not have permission to create or delete roles.');
}
if ($this->selectedRole) {
$this->selectedRole->delete();
Flux::modals()->close();
Flux::toast(variant: 'danger', text: 'Role deleted successfully.');
$this->selectedRole = null;
$this->dispatch('refreshComponents');
}
}
}; ?>
<section>
<div class="flex justify-between items-center">
<div>
<flux:heading>Roles</flux:heading>
<flux:subheading>A list of our roles.</flux:subheading>
</div>
<div class="flex">
<flux:spacer />
@can('create roles')
<flux:button wire:click="showRoleForm">Add Role</flux:button>
@endcan
</div>
</div>
<flux:table :paginate="$this->roles" class="mt-4">
<flux:columns>
<flux:column sortable :sorted="$sortBy === 'id'" :direction="$sortDirection" wire:click="sort('id')" class="w-2">ID</flux:column>
<flux:column sortable :sorted="$sortBy === 'name'" :direction="$sortDirection" wire:click="sort('name')">Name</flux:column>
<flux:column>Permissions</flux:column>
<flux:column></flux:column>
</flux:columns>
<flux:rows>
@foreach ($this->roles as $role)
<flux:row :key="$role->id">
<flux:cell class="whitespace-nowrap">{{ $role->id }}</flux:cell>
<flux:cell class="whitespace-nowrap">{{ $role->name }}</flux:cell>
<flux:cell class="whitespace-nowrap">{{ $role->permissions_count }}</flux:cell>
<flux:cell class="text-right">
@can('edit roles')
<flux:button icon="pencil-square" size="sm" inset="top bottom" wire:click="showRoleForm({{ $role->id }})" />
@endcan
@can('delete roles')
@unless(in_array($role->name, ['Super Admin', 'Admin', 'User']))
<flux:button variant="danger" icon="trash" size="sm" inset="top bottom" wire:click="confirmDelete({{ $role->id }})" />
@endunless
@endcan
</flux:cell>
</flux:row>
@endforeach
</flux:rows>
</flux:table>
<flux:modal name="role-form" class="w-full space-y-6">
<flux:heading size="lg">{{ (! $this->roleId)?'Add':'Edit' }} Role</flux:heading>
<flux:input wire:model="name" label="Name:" />
<flux:select wire:model="selectedPermissions" searchable variant="listbox" multiple placeholder="Choose permissions..." label="Permissions:">
@foreach($this->permissions as $permission)
<flux:option value="{{ $permission->name }}">{{ $permission->name }}</flux:option>
@endforeach
</flux:select>
<div class="flex gap-2">
<flux:spacer />
<flux:modal.close>
<flux:button variant="ghost">Cancel</flux:button>
</flux:modal.close>
<flux:button type="submit" variant="primary" wire:click="save({{ $this->roleId }})">
{{ (! $this->roleId)?'Add':'Edit' }} Role
</flux:button>
</div>
</flux:modal>
<flux:modal name="delete-role" class="min-w-[22rem] space-y-6">
<div>
<flux:heading size="lg">Delete Role?</flux:heading>
<flux:subheading>
@if($selectedRole)
<p>You're about to delete the role: {{ $selectedRole->name }}.</p>
<p>This action cannot be reversed.</p>
@endif
</flux:subheading>
</div>
<div class="flex gap-2">
<flux:spacer />
<flux:modal.close>
<flux:button variant="ghost">Cancel</flux:button>
</flux:modal.close>
<flux:button type="submit" variant="danger" wire:click="delete">Delete Role</flux:button>
</div>
</flux:modal>
</section>
permissions.blade.php
<?php
use App\Models\User;
use Illuminate\Validation\Rules;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Livewire\Volt\Component;
use Livewire\WithPagination;
use Livewire\Attributes\{Url, Computed, On};
/**
* Permission Management Component
*
* Handles all permission management operations including listing, creation,
* editing, and deletion of permissions.
*
* @package App\Livewire
*/
new class extends Component {
use WithPagination;
#[Url]
public $sortBy = 'id';
#[Url]
public $sortDirection = 'asc';
/**
* Form state properties
*/
public $permissionId = '';
public $name = '';
public $resource = '';
public $selectedPermission = null;
public $searchTerm = '';
/**
* Initialize component state
*/
#[On('refreshComponents')]
public function mount(): void
{
if (!auth()->user()->can('view permissions')) {
throw new AuthorizationException('You do not have permission to view permissions.');
}
$this->roles = Role::all();
}
/**
* Handle column sorting
*
* @param string $column The column to sort by
*/
public function sort(string $column): void
{
if ($this->sortBy === $column) {
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
} else {
$this->sortBy = $column;
$this->sortDirection = 'asc';
}
}
/**
* Get paginated permissions list
*
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
#[Computed]
public function permissions()
{
return Permission::query()
->when($this->searchTerm, function ($query) {
$query->where('name', 'like', '%' . $this->searchTerm . '%');
})
->tap(fn($query) => $this->sortBy ? $query->orderBy($this->sortBy, $this->sortDirection) : $query)
->paginate(25, pageName: 'permissions-page');
}
/**
* Show the permission form modal for adding or editing a permission
*
* @param Permission|null $permission The permission to edit. If null, shows add form
*/
public function showPermissionForm(?Permission $permission = null): void
{
$this->resetValidation();
if ($permission) {
$this->permissionId = $permission->id;
$this->name = $permission->name;
} else {
$this->resetFormFields();
}
Flux::modal('permission-form')->show();
}
/**
* Reset form fields to default values
*/
private function resetFormFields(): void
{
$this->permissionId = '';
$this->name = '';
$this->resource = '';
$this->selectedPermission = null;
}
/**
* Show delete confirmation modal
*
* @param Permission $permission The permission to delete
*/
public function confirmDelete(Permission $permission): void
{
$this->selectedPermission = $permission;
Flux::modal('delete-permission')->show();
}
/**
* Save permission data (create or update)
*
* @param int|null $permissionId ID of permission to update, null for create
*/
public function save(?int $permissionId = null): void
{
if (!auth()->user()->can('create permissions') ||
!auth()->user()->can('edit permissions')) {
throw new AuthorizationException('You do not have permission to create or edit permissions.');
}
$this->validate([
'name' => 'required|min:3|unique:permissions,name,' . $permissionId,
]);
$permissionsAdded = false;
if ($this->resource) {
$resources = ['create', 'edit', 'view', 'delete'];
foreach ($resources as $resource) {
$permissionName = $resource . ' ' . $this->name;
if (!Permission::where('name', $permissionName)->exists()) {
Permission::create(['name' => $permissionName])->save();
$permissionsAdded = true;
}
}
} else {
$permission = $permissionId ? Permission::findOrFail($permissionId) : Permission::create(['name' => $this->name]);
$permission->name = $this->name;
$permission->save();
$permissionsAdded = true;
}
Flux::modals()->close();
$toastVariant = $permissionsAdded ? 'success' : 'danger';
$toastText = $permissionsAdded
? ($permissionId ? 'Permission updated successfully.' : 'Permission(s) added successfully.')
: 'No permissions were created as they already exist.';
Flux::toast(variant: $toastVariant, text: $toastText);
$this->dispatch('refreshComponents');
}
/**
* Delete selected permission and sync roles
*/
public function delete(): void
{
if (!auth()->user()->can('delete permissions')) {
throw new AuthorizationException('You do not have permission to delete permissions.');
}
if ($this->selectedPermission) {
// Remove the permission from all roles
$rolesWithPermission = Role::whereHas('permissions', function($query) {
$query->where('id', $this->selectedPermission->id);
})->get();
foreach ($rolesWithPermission as $role) {
$role->revokePermissionTo($this->selectedPermission);
}
$this->selectedPermission->delete();
Flux::modals()->close();
Flux::toast(variant: 'danger', text: 'Permission deleted successfully.');
$this->selectedPermission = null;
$this->dispatch('refreshComponents');
}
}
};
?>
<section>
<div class="flex justify-between items-center">
<div>
<flux:heading>Permissions</flux:heading>
<flux:subheading>A list of our permissions.</flux:subheading>
</div>
<div class="flex">
<flux:spacer />
@can('create permissions')
<flux:button wire:click="showPermissionForm">Add Permission</flux:button>
@endcan
</div>
</div>
<flux:field class="mt-4">
<flux:input wire:model.live="searchTerm" placeholder="Search..." />
</flux:field>
<flux:table :paginate="$this->permissions" class="mt-4">
<flux:columns>
<flux:column sortable :sorted="$sortBy === 'id'" :direction="$sortDirection" wire:click="sort('id')" class="w-2">ID</flux:column>
<flux:column sortable :sorted="$sortBy === 'name'" :direction="$sortDirection" wire:click="sort('name')">Name</flux:column>
<flux:column></flux:column>
</flux:columns>
<flux:rows>
@foreach ($this->permissions as $permission)
<flux:row :key="$permission->id">
<flux:cell class="whitespace-nowrap">{{ $permission->id }}</flux:cell>
<flux:cell class="whitespace-nowrap">{{ $permission->name }}</flux:cell>
<flux:cell class="text-right">
@can('edit permissions')
<flux:button icon="pencil-square" size="sm" inset="top bottom" wire:click="showPermissionForm({{ $permission->id }})" />
@endcan
@can('delete permissions')
<flux:button variant="danger" icon="trash" size="sm" inset="top bottom" wire:click="confirmDelete({{ $permission->id }})" />
@endcan
</flux:cell>
</flux:row>
@endforeach
</flux:rows>
</flux:table>
@canany(['create permissions','edit permissions'])
<flux:modal name="permission-form" class="w-full space-y-6">
<flux:heading size="lg">{{ (! $this->permissionId)?'Add':'Edit' }} Permission</flux:heading>
<flux:input wire:model="name" label="Name:" />
@if(! $this->permissionId)
<flux:checkbox wire:model="resource" label="Create as resource" description="Creating as a resource will create add, edit, view and delete permissions." />
@endif
<div class="flex gap-2">
<flux:spacer />
<flux:modal.close>
<flux:button variant="ghost">Cancel</flux:button>
</flux:modal.close>
<flux:button type="submit" variant="primary" wire:click="save({{ $this->permissionId }})">
{{ (! $this->permissionId)?'Add':'Edit' }} Permission
</flux:button>
</div>
</flux:modal>
@endcanany
@can('delete permissions')
<flux:modal name="delete-permission" class="min-w-[22rem] space-y-6">
<div>
<flux:heading size="lg">Delete Permission?</flux:heading>
<flux:subheading>
@if($selectedPermission)
<p>You're about to delete the permission: {{ $selectedPermission->name }}.</p>
<p>This action cannot be reversed.</p>
@endif
</flux:subheading>
</div>
<div class="flex gap-2">
<flux:spacer />
<flux:modal.close>
<flux:button variant="ghost">Cancel</flux:button>
</flux:modal.close>
<flux:button type="submit" variant="danger" wire:click="delete">Delete Permission</flux:button>
</div>
</flux:modal>
@endcan
</section>