Summary Consolidates the “Tenant Operate Hub” work (Spec 085) and the follow-up adjustments from the 086 session merge into a single branch ready to merge into dev. Primary focus: stabilize Ops/Operate Hub UX flows, tighten/align authorization semantics, and make the full Sail test suite green. Key Changes Ops UX / Verification Readonly members can view verification operation runs (reports) while starting verification remains restricted. Normalized failure reason-code handling and aligned UX expectations with the provider reason-code taxonomy. Onboarding wizard UX “Start verification” CTA is hidden while a verification run is active; “Refresh” is shown during in-progress runs. Treats provider_permission_denied as a blocking reason (while keeping legacy compatibility). Test + fixture hardening Standardized use of default provider connection fixtures in tests where sync/restore flows require it. Fixed multiple Filament URL/tenant-context test cases to avoid 404s and reduce tenancy routing brittleness. Policy sync / restore safety Enrollment configuration type collision classification tests now exercise the real sync path (with required provider connection present). Restore edge-case safety tests updated to reflect current provider-connection requirements. Testing vendor/bin/sail artisan test --compact (green) vendor/bin/sail bin pint --dirty (green) Notes Includes merged 086 session work already (no separate PR needed). Co-authored-by: Ahmed Darrazi <ahmeddarrazi@ebc83aaa-d947-4a08-b88e-bd72ac9645f7.fritz.box> Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box> Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.fritz.box> Reviewed-on: #103
143 lines
4.1 KiB
PHP
143 lines
4.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Pages\Operations;
|
|
|
|
use App\Filament\Resources\OperationRunResource;
|
|
use App\Models\OperationRun;
|
|
use App\Models\Tenant;
|
|
use App\Models\User;
|
|
use App\Services\Auth\CapabilityResolver;
|
|
use App\Support\OperateHub\OperateHubShell;
|
|
use App\Support\OperationRunLinks;
|
|
use Filament\Actions\Action;
|
|
use Filament\Actions\ActionGroup;
|
|
use Filament\Pages\Page;
|
|
use Filament\Schemas\Components\EmbeddedSchema;
|
|
use Filament\Schemas\Schema;
|
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
use Illuminate\Support\Str;
|
|
|
|
class TenantlessOperationRunViewer extends Page
|
|
{
|
|
use AuthorizesRequests;
|
|
|
|
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;
|
|
|
|
public bool $opsUxIsTabHidden = false;
|
|
|
|
/**
|
|
* @return array<Action|ActionGroup>
|
|
*/
|
|
protected function getHeaderActions(): array
|
|
{
|
|
$operateHubShell = app(OperateHubShell::class);
|
|
|
|
$actions = [
|
|
Action::make('operate_hub_scope_run_detail')
|
|
->label($operateHubShell->scopeLabel(request()))
|
|
->color('gray')
|
|
->disabled(),
|
|
];
|
|
|
|
$activeTenant = $operateHubShell->activeEntitledTenant(request());
|
|
|
|
if ($activeTenant instanceof Tenant) {
|
|
$actions[] = Action::make('operate_hub_back_to_tenant_run_detail')
|
|
->label('← Back to '.$activeTenant->name)
|
|
->color('gray')
|
|
->url(\App\Filament\Pages\TenantDashboard::getUrl(panel: 'tenant', tenant: $activeTenant));
|
|
|
|
$actions[] = Action::make('operate_hub_show_all_operations')
|
|
->label('Show all operations')
|
|
->color('gray')
|
|
->url(fn (): string => route('admin.operations.index'));
|
|
} else {
|
|
$actions[] = Action::make('operate_hub_back_to_operations')
|
|
->label('Back to Operations')
|
|
->color('gray')
|
|
->url(fn (): string => route('admin.operations.index'));
|
|
}
|
|
|
|
$actions[] = Action::make('refresh')
|
|
->label('Refresh')
|
|
->icon('heroicon-o-arrow-path')
|
|
->color('gray')
|
|
->url(fn (): string => isset($this->run)
|
|
? route('admin.operations.view', ['run' => (int) $this->run->getKey()])
|
|
: route('admin.operations.index'));
|
|
|
|
if (! isset($this->run)) {
|
|
return $actions;
|
|
}
|
|
|
|
$user = auth()->user();
|
|
$tenant = $this->run->tenant;
|
|
|
|
if ($tenant instanceof Tenant && (! $user instanceof User || ! app(CapabilityResolver::class)->isMember($user, $tenant))) {
|
|
$tenant = null;
|
|
}
|
|
|
|
$related = OperationRunLinks::related($this->run, $tenant);
|
|
|
|
$relatedActions = [];
|
|
|
|
foreach ($related as $label => $url) {
|
|
$relatedActions[] = Action::make(Str::slug((string) $label, '_'))
|
|
->label((string) $label)
|
|
->url((string) $url)
|
|
->openUrlInNewTab();
|
|
}
|
|
|
|
if ($relatedActions !== []) {
|
|
$actions[] = ActionGroup::make($relatedActions)
|
|
->label('Open')
|
|
->icon('heroicon-o-arrow-top-right-on-square')
|
|
->color('gray');
|
|
}
|
|
|
|
return $actions;
|
|
}
|
|
|
|
public function mount(OperationRun $run): void
|
|
{
|
|
$user = auth()->user();
|
|
|
|
if (! $user instanceof User) {
|
|
abort(403);
|
|
}
|
|
|
|
$this->authorize('view', $run);
|
|
|
|
$this->run = $run->loadMissing(['workspace', 'tenant', 'user']);
|
|
}
|
|
|
|
public function infolist(Schema $schema): Schema
|
|
{
|
|
return OperationRunResource::infolist($schema);
|
|
}
|
|
|
|
public function defaultInfolist(Schema $schema): Schema
|
|
{
|
|
return $schema
|
|
->record($this->run)
|
|
->columns(2);
|
|
}
|
|
|
|
public function content(Schema $schema): Schema
|
|
{
|
|
return $schema->schema([
|
|
EmbeddedSchema::make('infolist'),
|
|
]);
|
|
}
|
|
}
|