- Canonical /admin/onboarding entry point; legacy routes 404\n- Tenantless run viewer at /admin/operations/{run} with membership-based 404\n- RBAC UX (disabled controls + tooltips) and server-side 403\n- DB-only rendering/refresh; contract registry enforced\n- Adds migrations + tests + spec artifacts
67 lines
1.6 KiB
PHP
67 lines
1.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Pages\Operations;
|
|
|
|
use App\Models\OperationRun;
|
|
use App\Models\User;
|
|
use App\Models\WorkspaceMembership;
|
|
use Filament\Actions\Action;
|
|
use Filament\Pages\Page;
|
|
|
|
class TenantlessOperationRunViewer extends Page
|
|
{
|
|
protected static string $layout = 'filament-panels::components.layout.simple';
|
|
|
|
protected static bool $shouldRegisterNavigation = false;
|
|
|
|
protected static bool $isDiscovered = false;
|
|
|
|
protected static ?string $title = 'Operation run';
|
|
|
|
protected string $view = 'filament.pages.operations.tenantless-operation-run-viewer';
|
|
|
|
public OperationRun $run;
|
|
|
|
/**
|
|
* @return array<Action>
|
|
*/
|
|
protected function getHeaderActions(): array
|
|
{
|
|
return [
|
|
Action::make('refresh')
|
|
->label('Refresh')
|
|
->icon('heroicon-o-arrow-path')
|
|
->color('gray')
|
|
->url(fn (): string => url()->current()),
|
|
];
|
|
}
|
|
|
|
public function mount(OperationRun $run): void
|
|
{
|
|
$user = auth()->user();
|
|
|
|
if (! $user instanceof User) {
|
|
abort(403);
|
|
}
|
|
|
|
$workspaceId = (int) ($run->workspace_id ?? 0);
|
|
|
|
if ($workspaceId <= 0) {
|
|
abort(404);
|
|
}
|
|
|
|
$isMember = WorkspaceMembership::query()
|
|
->where('workspace_id', $workspaceId)
|
|
->where('user_id', (int) $user->getKey())
|
|
->exists();
|
|
|
|
if (! $isMember) {
|
|
abort(404);
|
|
}
|
|
|
|
$this->run = $run->loadMissing(['workspace', 'tenant', 'user']);
|
|
}
|
|
}
|