Implements workspace-scoped managed tenant onboarding wizard (Filament v5 / Livewire v4) with strict RBAC (404/403 semantics), resumable sessions, provider connection selection/creation, verification OperationRun, and optional bootstrap. Removes legacy onboarding entrypoints and adds Pest coverage + spec artifacts (073). ## Summary <!-- Kurz: Was ändert sich und warum? --> ## Spec-Driven Development (SDD) - [ ] Es gibt eine Spec unter `specs/<NNN>-<feature>/` - [ ] Enthaltene Dateien: `plan.md`, `tasks.md`, `spec.md` - [ ] Spec beschreibt Verhalten/Acceptance Criteria (nicht nur Implementation) - [ ] Wenn sich Anforderungen während der Umsetzung geändert haben: Spec/Plan/Tasks wurden aktualisiert ## Implementation - [ ] Implementierung entspricht der Spec - [ ] Edge cases / Fehlerfälle berücksichtigt - [ ] Keine unbeabsichtigten Änderungen außerhalb des Scopes ## Tests - [ ] Tests ergänzt/aktualisiert (Pest/PHPUnit) - [ ] Relevante Tests lokal ausgeführt (`./vendor/bin/sail artisan test` oder `php artisan test`) ## Migration / Config / Ops (falls relevant) - [ ] Migration(en) enthalten und getestet - [ ] Rollback bedacht (rückwärts kompatibel, sichere Migration) - [ ] Neue Env Vars dokumentiert (`.env.example` / Doku) - [ ] Queue/cron/storage Auswirkungen geprüft ## UI (Filament/Livewire) (falls relevant) - [ ] UI-Flows geprüft - [ ] Screenshots/Notizen hinzugefügt ## Notes <!-- Links, Screenshots, Follow-ups, offene Punkte --> Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.fritz.box> Reviewed-on: #88
171 lines
9.5 KiB
PHP
171 lines
9.5 KiB
PHP
<x-filament-panels::page>
|
|
<x-filament::section>
|
|
<div class="flex flex-col gap-4">
|
|
<div class="text-sm text-gray-600 dark:text-gray-300">
|
|
Workspace: <span class="font-medium text-gray-900 dark:text-gray-100">{{ $this->workspace->name }}</span>
|
|
</div>
|
|
|
|
<div class="rounded-md border border-gray-200 bg-gray-50 p-4 text-sm text-gray-700 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-200">
|
|
<div class="font-medium text-gray-900 dark:text-gray-100">
|
|
Managed tenant onboarding
|
|
</div>
|
|
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">
|
|
This wizard will guide you through identifying a managed tenant and verifying access.
|
|
</div>
|
|
</div>
|
|
|
|
@if ($this->managedTenant)
|
|
<div class="rounded-md border border-gray-200 bg-white p-4 text-sm text-gray-700 dark:border-gray-800 dark:bg-gray-950 dark:text-gray-200">
|
|
<div class="font-medium text-gray-900 dark:text-gray-100">Identified tenant</div>
|
|
<dl class="mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2">
|
|
<div>
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">Name</dt>
|
|
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">{{ $this->managedTenant->name }}</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">Tenant ID</dt>
|
|
<dd class="mt-1 font-mono text-sm text-gray-900 dark:text-gray-100">{{ $this->managedTenant->tenant_id }}</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
@endif
|
|
|
|
@php
|
|
$verificationSucceeded = $this->verificationSucceeded();
|
|
$hasTenant = (bool) $this->managedTenant;
|
|
$hasConnection = $hasTenant && is_int($this->selectedProviderConnectionId) && $this->selectedProviderConnectionId > 0;
|
|
@endphp
|
|
|
|
<div class="grid grid-cols-1 gap-3 lg:grid-cols-2">
|
|
<div class="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-950">
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Step 1 — Identify managed tenant</div>
|
|
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">Provide tenant ID + display name to start or resume the flow.</div>
|
|
</div>
|
|
<div class="text-xs font-medium {{ $hasTenant ? 'text-emerald-700 dark:text-emerald-400' : 'text-gray-500 dark:text-gray-400' }}">
|
|
{{ $hasTenant ? 'Done' : 'Pending' }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 flex flex-col gap-2 sm:flex-row">
|
|
<x-filament::button
|
|
type="button"
|
|
color="primary"
|
|
wire:click="mountAction('identifyManagedTenant')"
|
|
>
|
|
{{ $hasTenant ? 'Change tenant' : 'Identify tenant' }}
|
|
</x-filament::button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-950">
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Step 2 — Provider connection</div>
|
|
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">Create or pick the connection used to verify access.</div>
|
|
</div>
|
|
<div class="text-xs font-medium {{ $hasConnection ? 'text-emerald-700 dark:text-emerald-400' : 'text-gray-500 dark:text-gray-400' }}">
|
|
{{ $hasConnection ? 'Selected' : ($hasTenant ? 'Pending' : 'Locked') }}
|
|
</div>
|
|
</div>
|
|
|
|
@if ($hasTenant)
|
|
<div class="mt-3 text-sm text-gray-700 dark:text-gray-200">
|
|
<span class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">Selected connection ID</span>
|
|
<div class="mt-1 font-mono">{{ $this->selectedProviderConnectionId ?? '—' }}</div>
|
|
</div>
|
|
|
|
<div class="mt-4 flex flex-col gap-2 sm:flex-row">
|
|
<x-filament::button
|
|
type="button"
|
|
color="gray"
|
|
wire:click="mountAction('createProviderConnection')"
|
|
>
|
|
Create connection
|
|
</x-filament::button>
|
|
|
|
<x-filament::button
|
|
type="button"
|
|
color="gray"
|
|
wire:click="mountAction('selectProviderConnection')"
|
|
>
|
|
Select connection
|
|
</x-filament::button>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-950">
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Step 3 — Verify access</div>
|
|
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">Runs a verification operation and records the result.</div>
|
|
</div>
|
|
<div class="text-xs font-medium {{ $verificationSucceeded ? 'text-emerald-700 dark:text-emerald-400' : 'text-gray-500 dark:text-gray-400' }}">
|
|
{{ $verificationSucceeded ? 'Succeeded' : ($hasConnection ? 'Pending' : 'Locked') }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 flex flex-col gap-2 sm:flex-row">
|
|
<x-filament::button
|
|
type="button"
|
|
color="primary"
|
|
:disabled="! $hasConnection"
|
|
wire:click="mountAction('startVerification')"
|
|
>
|
|
Run verification
|
|
</x-filament::button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-950">
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Step 4 — Bootstrap (optional)</div>
|
|
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">Start inventory/compliance sync after verification.</div>
|
|
</div>
|
|
<div class="text-xs font-medium text-gray-500 dark:text-gray-400">
|
|
{{ $verificationSucceeded ? 'Available' : 'Locked' }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 flex flex-col gap-2 sm:flex-row">
|
|
<x-filament::button
|
|
type="button"
|
|
color="gray"
|
|
:disabled="! $verificationSucceeded"
|
|
wire:click="mountAction('startBootstrap')"
|
|
>
|
|
Start bootstrap
|
|
</x-filament::button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-950">
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Step 5 — Complete onboarding</div>
|
|
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">Marks the tenant as active after successful verification.</div>
|
|
</div>
|
|
<div class="text-xs font-medium {{ $verificationSucceeded ? 'text-emerald-700 dark:text-emerald-400' : 'text-gray-500 dark:text-gray-400' }}">
|
|
{{ $verificationSucceeded ? 'Ready' : 'Locked' }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 flex flex-col gap-2 sm:flex-row">
|
|
<x-filament::button
|
|
type="button"
|
|
color="success"
|
|
:disabled="! $verificationSucceeded"
|
|
wire:click="mountAction('completeOnboarding')"
|
|
>
|
|
Complete onboarding
|
|
</x-filament::button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</x-filament::section>
|
|
</x-filament-panels::page>
|