= feaa8b6c93 Feat: Add modular URL app creation with role-based access and Microsoft integration support
- Introduced `StoreURLAppForm` and `StoreURLAppData` for form handling and data transformation.
- Added `UrlAppService` to streamline URL app creation with settings like `accessUrl` and `isConnectedToMicrosoft`.
- Enhanced user access controls with role-based permissions using `UserAccessTypeEnum`.
- Updated UI for URL app creation with support for logos and dynamic role selection.
- Implemented feature tests to validate URL app creation and access URL formatting.
2026-06-22 07:21:26 +00:00

174 lines
6.7 KiB
PHP

<?php
use App\Concerns\HandlesOperations;
use App\Data\Application\StoreURLAppData;
use App\Enums\{ConnectionProtocolEnum, Permissions\AppPermissionEnum, UserAccessTypeEnum};
use App\Livewire\Concerns\Choices\{ChoiceField, WithSearchableChoices};
use App\Livewire\Concerns\WithRepeaterFields;
use App\Livewire\Forms\StoreURLAppForm;
use App\Services\{Applications\URL\UrlAppService, RoleService};
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithFileUploads;
new
class extends Component {
use HandlesOperations, WithRepeaterFields, WithSearchableChoices, WithFileUploads;
#[Url]
public string $protocol = '';
public StoreURLAppForm $form;
public ConnectionProtocolEnum $connectionProtocol = ConnectionProtocolEnum::URL;
private RoleService $roleService;
private UrlAppService $urlAppService;
public function boot(RoleService $roleService, UrlAppService $urlAppService): void
{
$this->roleService = $roleService;
$this->urlAppService = $urlAppService;
}
public function render()
{
/** @phpstan-ignore-next-line */
return $this->view()->title($this->title());
}
public function save(bool $goBack = true): void
{
$this->authorize(AppPermissionEnum::Create->value);
$this->form->validate();
$this->attempt(
function () use ($goBack) {
$data = StoreURLAppData::fromArray($this->form->pull());
$this->urlAppService->createApp($data);
if ($goBack) {
$this->goBack();
} else {
$this->form->reset();
}
}
);
}
public function goBack(): void
{
$this->redirectRoute("apps.index", navigate: true);
}
public function title(): string
{
return "New Redirected App Integration";
}
public function searchRoles(string $q = ''): void
{
$this->searchChoice('roles', $q);
}
public function selectAllRoles(): void
{
$this->selectAllChoice('roles');
}
public function clearRoles(): void
{
$this->clearChoice('roles');
}
protected function choiceFields(): array
{
return [
'roles' => new ChoiceField(
search: fn(string $q): array => $this->roleService->searchRolesForSelect($q)->toArray(),
allIds: $this->roleService->getAllRoleIds(...),
formPath: 'form.roleIds',
),
];
}
};
?>
<div>
<x-shared.card :title="$this->title()" icon="lucide-package-plus">
<x-slot:actions>
<x-mary-button wire:click="goBack" icon="lucide.corner-up-left" class="btn-ghost">Go Back
</x-mary-button>
</x-slot:actions>
<x-mary-form wire:submit="save" class="p-4 gap-y-8">
<!-- General settings start -->
<div class="flex gap-4 flex-col w-full md:flex-row">
<article class="w-full md:w-2/5">
<h2 class="font-bold">General Settings</h2>
</article>
<div class="w-full md:w-3/5">
<div class="flex items-center gap-4 w-full">
<div class="flex-1">
<x-mary-input required label="App Name" wire:model="form.name"
placeholder="Keka, MS 365 etc."
hint="A basic name that matches the actual application"/>
</div>
<div class="max-w-90">
<x-mary-checkbox label="Connected to Microsoft ?" wire:model="form.isConnectedToMicrosoft"/>
</div>
</div>
<x-mary-input required label="Access Url" wire:model="form.accessUrl"
placeholder="https://app.example.com"
hint="The URL by which user will access this application. We will show this url in user dashboard."/>
<x-mary-file wire:model="form.logo" label="Logo" hint="Optional"
accept="application/jpg, application/png, image/jpeg, image/png"/>
</div>
</div>
<!-- General settings end -->
<!-- Access start -->
{{-- <hr>--}}
{{-- <div class="flex gap-4 flex-col w-full md:flex-row">--}}
{{-- <article class="w-full md:w-2/5">--}}
{{-- <h2 class="font-bold">User Access</h2>--}}
{{-- <p class="text-sm text-gray-500 max-w-70 mt-4">--}}
{{-- Choose whether to allow all users be able to connect this app or selected ones.--}}
{{-- </p>--}}
{{-- </article>--}}
{{-- <div class="w-full md:w-3/5">--}}
{{-- <x-mary-radio--}}
{{-- :options="UserAccessTypeEnum::asOptions()"--}}
{{-- option-value="value"--}}
{{-- wire:model.change.live="form.userAccessOption"--}}
{{-- />--}}
{{-- <div class=""--}}
{{-- x-show="$wire.form.userAccessOption === '{{UserAccessTypeEnum::Role->value}}'"--}}
{{-- x-cloak--}}
{{-- >--}}
{{-- <x-shared.choices--}}
{{-- wire:model.live="form.roleIds"--}}
{{-- :options="$choicesSearchable['roles'] ?? []"--}}
{{-- search-function="searchRoles"--}}
{{-- select-all-action="selectAllRoles"--}}
{{-- clear-action="clearRoles"--}}
{{-- label="Roles"--}}
{{-- />--}}
{{-- </div>--}}
{{-- </div>--}}
{{-- </div>--}}
<!-- Access end -->
<div class="flex gap-x-4 font-medium justify-end">
<x-mary-button wire:click.prevent="goBack" spinner="goBack">Cancel</x-mary-button>
<x-mary-button wire:click.prevent="save(false)">Save & Add Another</x-mary-button>
<x-mary-button type="submit"
class="btn-primary">
Save
</x-mary-button>
</div>
</x-mary-form>
</x-shared.card>
</div>