Spec 107: Workspace Chooser v1 (Enterprise) + In-App Switch Entry Point ## Core changes - Refactor EnsureWorkspaceSelected middleware: 7-step algorithm with auto-resume (single membership + last_workspace_id), stale session detection, ?choose=1 forced chooser, workspace-optional path bypass - Create WorkspaceRedirectResolver for DRY tenant-count branching (0→managed-tenants, 1→tenant-dashboard, >1→choose-tenant) - Add WorkspaceAutoSelected + WorkspaceSelected audit enum cases - Rewrite ChooseWorkspace page: role badges, tenant counts, wire:click selection, audit logging, WorkspaceRedirectResolver - Add 'Switch workspace' user menu item in AdminPanelProvider - Rewrite SwitchWorkspaceController with audit + resolver - Replace inline tenant branching in routes/web.php with resolver ## New test files (6) - WorkspaceRedirectResolverTest (5 tests Spec 107: Workspace Chooser v1 (Enterprise) + In-App Switch Entry Point ## Core changes - Refactor EnsureWorkspaceSelected middleware: 7-step algorithmst ## Core changes - Refactor EnsureWorkspaceSelected middleware: 7-stepes - Refactor Ensng auto-resume (single membership + last_workspace_id), stale sessioid detection, ?choose=1 forced chooser, w (security invariant preserve- Create WorkspaceRedirectResolver for DRY tenant-count branching (0→managed-tenants, 1→tenant-dashboapped (8163 assertions)
100 lines
4.8 KiB
PHP
100 lines
4.8 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">
|
|
Select a workspace to continue.
|
|
</div>
|
|
|
|
@php
|
|
$workspaces = $this->getWorkspaces();
|
|
$workspaceRoles = $this->workspaceRoles;
|
|
|
|
$user = auth()->user();
|
|
$recommendedWorkspaceId = $user instanceof \App\Models\User ? (int) ($user->last_workspace_id ?? 0) : 0;
|
|
|
|
if ($recommendedWorkspaceId > 0) {
|
|
[$recommended, $other] = $workspaces->partition(fn ($workspace) => (int) $workspace->id === $recommendedWorkspaceId);
|
|
$workspaces = $recommended->concat($other)->values();
|
|
}
|
|
|
|
$roleColorMap = [
|
|
'owner' => 'primary',
|
|
'manager' => 'info',
|
|
'operator' => 'gray',
|
|
'readonly' => 'gray',
|
|
];
|
|
@endphp
|
|
|
|
@if ($workspaces->isEmpty())
|
|
<div class="rounded-md border border-gray-200 bg-gray-50 p-4 text-center text-sm text-gray-700 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-200">
|
|
You don't have access to any workspace yet.
|
|
</div>
|
|
@else
|
|
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
|
@foreach ($workspaces as $workspace)
|
|
@php
|
|
$isRecommended = $recommendedWorkspaceId > 0 && (int) $workspace->id === $recommendedWorkspaceId;
|
|
$role = $workspaceRoles[(int) $workspace->id] ?? null;
|
|
$tenantCount = (int) ($workspace->tenants_count ?? 0);
|
|
@endphp
|
|
|
|
<div
|
|
wire:key="workspace-{{ $workspace->id }}"
|
|
wire:click="selectWorkspace({{ (int) $workspace->id }})"
|
|
class="cursor-pointer rounded-lg border p-4 transition hover:shadow-sm dark:border-gray-800 {{ $isRecommended ? 'border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/30' : 'border-gray-200 hover:border-gray-300 dark:hover:border-gray-700' }}"
|
|
>
|
|
<div class="flex flex-col gap-3">
|
|
<div class="flex flex-col gap-2">
|
|
<div class="font-medium text-gray-900 dark:text-gray-100">
|
|
{{ $workspace->name }}
|
|
</div>
|
|
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
@if ($isRecommended)
|
|
<x-filament::badge color="warning" size="sm">
|
|
Last used
|
|
</x-filament::badge>
|
|
@endif
|
|
|
|
@if ($role)
|
|
<x-filament::badge :color="$roleColorMap[$role] ?? 'gray'" size="sm">
|
|
{{ ucfirst($role) }}
|
|
</x-filament::badge>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-xs text-gray-500 dark:text-gray-400">
|
|
{{ $tenantCount }} {{ \Illuminate\Support\Str::plural('tenant', $tenantCount) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
|
|
@php
|
|
$canManageWorkspaces = false;
|
|
|
|
if ($user instanceof \App\Models\User && $workspaces->count() > 0) {
|
|
foreach ($workspaces as $ws) {
|
|
$wsRole = $workspaceRoles[(int) $ws->id] ?? null;
|
|
if ($wsRole === 'owner') {
|
|
$canManageWorkspaces = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
@endphp
|
|
|
|
@if ($canManageWorkspaces)
|
|
<div class="mt-2 text-center">
|
|
<a href="/admin/workspaces" class="text-sm text-primary-600 hover:underline dark:text-primary-400">
|
|
Manage workspaces
|
|
</a>
|
|
</div>
|
|
@endif
|
|
@endif
|
|
</div>
|
|
</x-filament::section>
|
|
</x-filament-panels::page>
|