## Summary - cut over the admin runtime to the workspace-first environment and operations routes from spec 280 - retarget governance artifact resources, related navigation, and operation drillthroughs to the surviving admin panel contract from spec 282 - add focused feature and browser coverage plus spec close-out updates for the shipped 280/282 slice ## Validation - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/WorkspaceFoundation tests/Feature/Workspaces tests/Feature/ManagedEnvironment tests/Feature/RequiredPermissions tests/Feature/Operations tests/Feature/MonitoringOperationsTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec280WorkspaceTenancyEnvironmentRoutingSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/GovernanceArtifacts/GovernanceArtifactAdminPanelRegistrationTest.php tests/Feature/Filament/GovernanceArtifacts/GovernanceArtifactEnvironmentContextTest.php tests/Feature/Filament/GovernanceArtifacts/GovernanceArtifactDeepLinkContractTest.php tests/Feature/Filament/GovernanceArtifacts/GovernanceArtifactLegacyTenantPanelGuardTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec282GovernanceArtifactRetargetingSmokeTest.php` ## Notes - provider registration remains in `apps/platform/bootstrap/providers.php` - Filament stays on v5 with Livewire v4 semantics - touched searchable governance surfaces remain truthful or disabled in the same slice Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #341
151 lines
4.8 KiB
PHP
151 lines
4.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Concerns;
|
|
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\Workspace;
|
|
use Filament\Facades\Filament;
|
|
use Filament\Panel;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
trait WorkspaceScopedTenantRoutes
|
|
{
|
|
public static function getSlug(?Panel $panel = null): string
|
|
{
|
|
return static::workspaceScopedSlug(parent::getSlug($panel), $panel);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $parameters
|
|
*/
|
|
public static function getUrl(?string $name = null, array $parameters = [], bool $isAbsolute = true, ?string $panel = null, ?Model $tenant = null, bool $shouldGuessMissingParameters = false): string
|
|
{
|
|
$panelId = $panel ?? Filament::getCurrentOrDefaultPanel()?->getId() ?? 'admin';
|
|
|
|
if ($panelId !== 'admin') {
|
|
return parent::getUrl($name, $parameters, $isAbsolute, $panelId, $tenant, $shouldGuessMissingParameters);
|
|
}
|
|
|
|
$resolvedTenant = static::resolveWorkspaceScopedTenant($parameters, $tenant);
|
|
|
|
if (! $resolvedTenant instanceof ManagedEnvironment) {
|
|
return url('/admin');
|
|
}
|
|
|
|
$workspace = static::resolveWorkspaceScopedWorkspace($resolvedTenant, $parameters);
|
|
|
|
if (! $workspace instanceof Workspace && ! is_string($workspace) && ! is_int($workspace)) {
|
|
return url('/admin');
|
|
}
|
|
|
|
$parameters['tenant'] ??= $resolvedTenant;
|
|
$parameters['workspace'] ??= $workspace;
|
|
|
|
return parent::getUrl($name, $parameters, $isAbsolute, $panelId, null, $shouldGuessMissingParameters);
|
|
}
|
|
|
|
protected static function workspaceScopedSlug(string $slug, ?Panel $panel = null): string
|
|
{
|
|
if (! static::shouldUseWorkspaceScopedTenantRoutes($panel)) {
|
|
return $slug;
|
|
}
|
|
|
|
$prefix = 'workspaces/{workspace}/environments/{tenant}/';
|
|
|
|
return str_starts_with($slug, $prefix)
|
|
? $slug
|
|
: $prefix.ltrim($slug, '/');
|
|
}
|
|
|
|
protected static function shouldUseWorkspaceScopedTenantRoutes(?Panel $panel = null): bool
|
|
{
|
|
$panelId = $panel?->getId() ?? Filament::getCurrentOrDefaultPanel()?->getId() ?? 'admin';
|
|
|
|
return $panelId === 'admin';
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $parameters
|
|
*/
|
|
protected static function resolveWorkspaceScopedTenant(array $parameters, ?Model $tenant = null): ?ManagedEnvironment
|
|
{
|
|
$parameterTenant = $parameters['tenant'] ?? $parameters['environment'] ?? null;
|
|
|
|
if ($parameterTenant instanceof ManagedEnvironment) {
|
|
return $parameterTenant;
|
|
}
|
|
|
|
if ($tenant instanceof ManagedEnvironment) {
|
|
return $tenant;
|
|
}
|
|
|
|
$record = $parameters['record'] ?? null;
|
|
|
|
if ($record instanceof Model) {
|
|
$relationshipName = static::workspaceScopedTenantRelationshipName();
|
|
|
|
if (method_exists($record, $relationshipName)) {
|
|
$recordTenant = $record->getRelationValue($relationshipName);
|
|
|
|
if (! $recordTenant instanceof ManagedEnvironment) {
|
|
$recordTenant = $record->{$relationshipName}()->first();
|
|
}
|
|
|
|
if ($recordTenant instanceof ManagedEnvironment) {
|
|
return $recordTenant;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (method_exists(static::class, 'resolveTenantContextForCurrentPanel')) {
|
|
$resolvedTenant = static::resolveTenantContextForCurrentPanel();
|
|
|
|
if ($resolvedTenant instanceof ManagedEnvironment) {
|
|
return $resolvedTenant;
|
|
}
|
|
}
|
|
|
|
if (method_exists(static::class, 'panelTenantContext')) {
|
|
$resolvedTenant = static::panelTenantContext();
|
|
|
|
if ($resolvedTenant instanceof ManagedEnvironment) {
|
|
return $resolvedTenant;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $parameters
|
|
*/
|
|
protected static function resolveWorkspaceScopedWorkspace(ManagedEnvironment $tenant, array $parameters): Workspace|string|int|null
|
|
{
|
|
$workspace = $parameters['workspace'] ?? null;
|
|
|
|
if ($workspace instanceof Workspace || is_string($workspace) || is_int($workspace)) {
|
|
return $workspace;
|
|
}
|
|
|
|
$tenantWorkspace = $tenant->workspace;
|
|
|
|
if ($tenantWorkspace instanceof Workspace) {
|
|
return $tenantWorkspace;
|
|
}
|
|
|
|
return $tenant->workspace()->first();
|
|
}
|
|
|
|
protected static function workspaceScopedTenantRelationshipName(): string
|
|
{
|
|
$relationshipName = property_exists(static::class, 'tenantOwnershipRelationshipName')
|
|
? static::$tenantOwnershipRelationshipName
|
|
: null;
|
|
|
|
return is_string($relationshipName) && $relationshipName !== ''
|
|
? $relationshipName
|
|
: 'tenant';
|
|
}
|
|
} |