- Applied `Confirmation` trait to multiple Livewire components for unified confirmation handling. - Replaced inline confirmation modals with `requireConfirmation` method for streamlined interaction. - Updated button styles and added reusable confirmation prompts for delete/detach actions. - Enhanced `AppRoleService` and `ConnectionProviderService` to support deletion with confirmation.
220 lines
7.1 KiB
PHP
220 lines
7.1 KiB
PHP
<?php
|
|
|
|
use App\Concerns\Confirmation;
|
|
use App\Concerns\HandlesOperations;
|
|
use App\Livewire\Forms\CreateRoleForm;
|
|
use App\Services\AppRoleService;
|
|
use App\Data\Role\{AssignAppsToRoleData, CreateRoleData, RoleAppData, RoleUserData};
|
|
use App\Data\Ui\TableHeader;
|
|
use App\Services\RoleService;
|
|
use Livewire\Attributes\{Computed, Layout, Title, Validate};
|
|
use Livewire\Component;
|
|
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
|
use Spatie\LaravelData\DataCollection;
|
|
use Spatie\LaravelData\PaginatedDataCollection;
|
|
|
|
new
|
|
#[Title('Roles and Apps')]
|
|
class extends Component {
|
|
use HandlesOperations, Confirmation;
|
|
|
|
protected AppRoleService $appRoleService;
|
|
public bool $showCreateModal = false;
|
|
public CreateRoleForm $form;
|
|
protected RoleService $roleService;
|
|
public array $appsSearchable = [];
|
|
|
|
#[DataCollectionOf(TableHeader::class)]
|
|
public DataCollection $headers;
|
|
|
|
public function boot(RoleService $roleService, AppRoleService $appRoleService): void
|
|
{
|
|
$this->roleService = $roleService;
|
|
$this->appRoleService = $appRoleService;
|
|
}
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->headers = TableHeader::collect([
|
|
new TableHeader(key: 'name', label: 'Name'),
|
|
new TableHeader(key: 'apps', label: 'Apps'),
|
|
new TableHeader(key: 'users', label: 'Users'),
|
|
], DataCollection::class);
|
|
}
|
|
|
|
#[Computed]
|
|
public function getRoles(): PaginatedDataCollection
|
|
{
|
|
return $this->roleService->getAll();
|
|
}
|
|
|
|
|
|
public function searchApps(string $value = ''): void
|
|
{
|
|
$this->appsSearchable = $this
|
|
->appRoleService
|
|
->searchAppsForSelect($value)
|
|
->toArray();
|
|
}
|
|
|
|
public function selectAllApps(): void
|
|
{
|
|
$this->form->appIds = $this->appRoleService->getAllAppIds();
|
|
$this->appsSearchable = $this->appRoleService->searchAppsForSelect('')->toArray();
|
|
}
|
|
|
|
public function clearApps(): void
|
|
{
|
|
$this->form->appIds = [];
|
|
}
|
|
|
|
public function test()
|
|
{
|
|
dd('hi');
|
|
}
|
|
|
|
public function openCreateModal(): void
|
|
{
|
|
$this->form->reset();
|
|
$this->searchApps();
|
|
$this->showCreateModal = true;
|
|
}
|
|
|
|
public function save(): void
|
|
{
|
|
$this->form->validate();
|
|
$this->attempt(
|
|
action: function (): void {
|
|
$role = $this->roleService->create(new CreateRoleData(name: $this->form->name));
|
|
$this->appRoleService->assign(new AssignAppsToRoleData(
|
|
roleId: $role->id,
|
|
validUpto: $this->form->isUnlimited ? now()->addYears(15) : $this->form->validUpto,
|
|
appIds: $this->form->appIds,
|
|
));
|
|
$this->showCreateModal = false;
|
|
$this->form->reset();
|
|
unset($this->getRoles);
|
|
},
|
|
successMessage: 'Role created successfully!',
|
|
);
|
|
}
|
|
|
|
public function delete(int $roleId): void
|
|
{
|
|
$this->attempt(
|
|
action: function () use ($roleId): void {
|
|
$this->roleService->delete($roleId);
|
|
unset($this->getRoles);
|
|
},
|
|
successMessage: 'Role deleted successfully!',
|
|
);
|
|
}
|
|
};
|
|
?>
|
|
|
|
<div>
|
|
<x-shared.card title="Roles" icon="lucide-shield-check" class="pb-2">
|
|
<x-slot:actions>
|
|
<x-mary-button wire:click="openCreateModal" icon="lucide.plus">
|
|
Add new role
|
|
</x-mary-button>
|
|
</x-slot:actions>
|
|
|
|
<x-mary-table
|
|
:headers="$headers->toArray()"
|
|
:rows="$this->getRoles->items()"
|
|
>
|
|
@scope('cell_name', $row)
|
|
<span class="font-medium text-gray-900">{{ $row->name }}</span>
|
|
@endscope
|
|
|
|
@scope('cell_apps', $row)
|
|
@foreach($row->apps as $app)
|
|
@php /** @var RoleAppData $app */ @endphp
|
|
<x-mary-badge class="badge-soft badge-primary" :value="$app->appName"/>
|
|
@endforeach
|
|
@endscope
|
|
|
|
@scope('cell_users', $row)
|
|
<div class="flex -space-x-2 overflow-hidden">
|
|
@foreach($row->users as $user)
|
|
@php /** @var RoleUserData $user */ @endphp
|
|
<x-mary-avatar :placeholder="$user->initials"
|
|
class="w-8! h-8! bg-blue-100 text-blue-600 border-2 border-white ring-0"
|
|
tooltip="{{ $user->name }}"/>
|
|
@endforeach
|
|
</div>
|
|
@endscope
|
|
|
|
@scope('actions', $row)
|
|
<div class="flex gap-1">
|
|
<x-mary-button
|
|
icon="lucide.eye"
|
|
:link="route('access-manager.roles-and-apps.show', $row->id)"
|
|
wire:navigate
|
|
tooltip="View details"
|
|
class="btn-sm btn-circle btn-soft"
|
|
/>
|
|
<x-mary-button
|
|
icon="lucide.trash"
|
|
wire:click="requireConfirmation('delete', {{ $row->id }})"
|
|
spinner="requireConfirmation('delete', {{ $row->id }})"
|
|
variant="danger"
|
|
class="btn-sm btn-circle btn-error btn-soft"
|
|
/>
|
|
</div>
|
|
@endscope
|
|
</x-mary-table>
|
|
</x-shared.card>
|
|
|
|
<x-mary-modal wire:model="showCreateModal" title="Add New Role">
|
|
<x-mary-form wire:submit="save">
|
|
<x-mary-input
|
|
label="Role Name"
|
|
wire:model="form.name"
|
|
id="role-name-input"
|
|
type="text"
|
|
placeholder="e.g. editor, manager"
|
|
autofocus
|
|
/>
|
|
|
|
<x-shared.choices
|
|
wire:model="form.appIds"
|
|
:options="$appsSearchable"
|
|
search-function="searchApps"
|
|
select-all-action="selectAllApps"
|
|
clear-action="clearApps"
|
|
label="Apps"
|
|
/>
|
|
<div x-data="{ isUnlimited: @entangle('assignForm.isUnlimited') }"
|
|
class="flex gap-2 items-baseline-last">
|
|
|
|
<div class="flex-1 transition-opacity duration-200"
|
|
x-bind:class="isUnlimited ? 'opacity-50 pointer-events-none' : ''">
|
|
<x-mary-datepicker
|
|
label="Date"
|
|
wire:model="form.validUpto"
|
|
icon="lucide.calendar"
|
|
x-bind:disabled="isUnlimited"
|
|
x-bind:readonly="isUnlimited"
|
|
/>
|
|
</div>
|
|
|
|
<x-mary-toggle
|
|
class="toggle-secondary"
|
|
label="Unlimited"
|
|
x-model="isUnlimited"
|
|
/>
|
|
</div>
|
|
<x-slot:actions>
|
|
<x-mary-button @click="$wire.showCreateModal = false" class="btn-ghost">
|
|
Cancel
|
|
</x-mary-button>
|
|
<x-mary-button type="submit" class="btn-primary" icon="lucide.save" spinner="save">
|
|
Save
|
|
</x-mary-button>
|
|
</x-slot:actions>
|
|
</x-mary-form>
|
|
</x-mary-modal>
|
|
</div>
|