- 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.
174 lines
6.7 KiB
PHP
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>
|