create([ 'tenant_id' => null, 'external_id' => 'platform', ]); }); afterEach(function () { CarbonImmutable::setTestNow(); }); it('keeps the operations list scan-first with one go to runbooks cta', function () { $run = OperationRun::factory()->create([ 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Failed->value, 'type' => 'inventory_sync', ]); $viewOnlyUser = PlatformUser::factory()->create([ 'capabilities' => [ PlatformCapabilities::ACCESS_SYSTEM_PANEL, PlatformCapabilities::OPERATIONS_VIEW, ], 'is_active' => true, ]); $this->actingAs($viewOnlyUser, 'platform'); $livewire = Livewire::test(Runs::class) ->assertCanSeeTableRecords([$run]) ->assertActionVisible('go_to_runbooks') ->assertActionExists('go_to_runbooks', fn (Action $action): bool => $action->getLabel() === 'Go to runbooks' && $action->getUrl() === Runbooks::getUrl(panel: 'system')); $table = $livewire->instance()->getTable(); $emptyStateActions = collect($table->getEmptyStateActions()) ->map(fn (Action $action): array => [ 'name' => $action->getName(), 'label' => $action->getLabel(), 'url' => $action->getUrl(), ]) ->values() ->all(); expect($livewire->instance()->getTitle())->toBe('Operations') ->and($table->getActions())->toBeEmpty() ->and($table->getBulkActions())->toBeEmpty() ->and($table->getRecordUrl($run))->toBe(SystemOperationRunLinks::view($run)) ->and($emptyStateActions)->toBe([ [ 'name' => 'go_to_runbooks_empty', 'label' => 'Go to runbooks', 'url' => Runbooks::getUrl(panel: 'system'), ], ]); }); it('keeps the failed operations list scan-first with one show all operations cta', function () { $run = OperationRun::factory()->create([ 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Failed->value, 'type' => 'inventory_sync', ]); $viewOnlyUser = PlatformUser::factory()->create([ 'capabilities' => [ PlatformCapabilities::ACCESS_SYSTEM_PANEL, PlatformCapabilities::OPERATIONS_VIEW, ], 'is_active' => true, ]); $this->actingAs($viewOnlyUser, 'platform'); $livewire = Livewire::test(Failures::class) ->assertCanSeeTableRecords([$run]) ->assertActionVisible('show_all_operations') ->assertActionExists('show_all_operations', fn (Action $action): bool => $action->getLabel() === 'Show all operations' && $action->getUrl() === SystemOperationRunLinks::index()); $table = $livewire->instance()->getTable(); $emptyStateActions = collect($table->getEmptyStateActions()) ->map(fn (Action $action): array => [ 'name' => $action->getName(), 'label' => $action->getLabel(), 'url' => $action->getUrl(), ]) ->values() ->all(); expect($livewire->instance()->getTitle())->toBe('Failed operations') ->and($table->getActions())->toBeEmpty() ->and($table->getBulkActions())->toBeEmpty() ->and($table->getRecordUrl($run))->toBe(SystemOperationRunLinks::view($run)) ->and($emptyStateActions)->toBe([ [ 'name' => 'show_all_operations_empty', 'label' => 'Show all operations', 'url' => SystemOperationRunLinks::index(), ], ]); }); it('keeps the stuck operations list scan-first with one show all operations cta', function () { config()->set('tenantpilot.system_console.stuck_thresholds.queued_minutes', 10); config()->set('tenantpilot.system_console.stuck_thresholds.running_minutes', 20); CarbonImmutable::setTestNow(CarbonImmutable::parse('2026-02-27 10:00:00')); $run = OperationRun::factory()->create([ 'status' => OperationRunStatus::Queued->value, 'outcome' => OperationRunOutcome::Pending->value, 'type' => 'inventory_sync', 'created_at' => now()->subMinutes(30), 'started_at' => null, ]); $viewOnlyUser = PlatformUser::factory()->create([ 'capabilities' => [ PlatformCapabilities::ACCESS_SYSTEM_PANEL, PlatformCapabilities::OPERATIONS_VIEW, ], 'is_active' => true, ]); $this->actingAs($viewOnlyUser, 'platform'); $livewire = Livewire::test(Stuck::class) ->assertCanSeeTableRecords([$run]) ->assertActionVisible('show_all_operations') ->assertActionExists('show_all_operations', fn (Action $action): bool => $action->getLabel() === 'Show all operations' && $action->getUrl() === SystemOperationRunLinks::index()); $table = $livewire->instance()->getTable(); $emptyStateActions = collect($table->getEmptyStateActions()) ->map(fn (Action $action): array => [ 'name' => $action->getName(), 'label' => $action->getLabel(), 'url' => $action->getUrl(), ]) ->values() ->all(); expect($livewire->instance()->getTitle())->toBe('Stuck operations') ->and($table->getActions())->toBeEmpty() ->and($table->getBulkActions())->toBeEmpty() ->and($table->getRecordUrl($run))->toBe(SystemOperationRunLinks::view($run)) ->and($emptyStateActions)->toBe([ [ 'name' => 'show_all_operations_empty', 'label' => 'Show all operations', 'url' => SystemOperationRunLinks::index(), ], ]); }); it('keeps detail-page triage, return paths, and audit behavior for manage operators', function () { NotificationFacade::fake(); $failedRun = OperationRun::factory()->create([ 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Failed->value, 'type' => 'inventory_sync', ]); $runningRun = OperationRun::factory()->create([ 'status' => OperationRunStatus::Running->value, 'outcome' => OperationRunOutcome::Pending->value, 'type' => 'inventory_sync', 'created_at' => now()->subMinutes(15), 'started_at' => now()->subMinutes(10), ]); $manageUser = PlatformUser::factory()->create([ 'capabilities' => [ PlatformCapabilities::ACCESS_SYSTEM_PANEL, PlatformCapabilities::OPERATIONS_VIEW, PlatformCapabilities::OPERATIONS_MANAGE, ], 'is_active' => true, ]); $this->actingAs($manageUser, 'platform'); $failedRunView = Livewire::test(ViewRun::class, [ 'run' => $failedRun, ]) ->assertActionVisible('show_all_operations') ->assertActionExists('show_all_operations', fn (Action $action): bool => $action->getLabel() === 'Show all operations' && $action->getUrl() === SystemOperationRunLinks::index()) ->assertActionVisible('go_to_runbooks') ->assertActionExists('go_to_runbooks', fn (Action $action): bool => $action->getLabel() === 'Go to runbooks' && $action->getUrl() === Runbooks::getUrl(panel: 'system')) ->assertActionVisible('retry') ->assertActionExists('retry', fn (Action $action): bool => $action->getLabel() === 'Retry' && $action->isConfirmationRequired()) ->assertActionVisible('mark_investigated') ->assertActionExists('mark_investigated', fn (Action $action): bool => $action->getLabel() === 'Mark investigated' && $action->isConfirmationRequired()) ->assertActionHidden('cancel'); expect($failedRunView->instance()->getTitle())->toBe('Operation #'.(int) $failedRun->getKey()); Livewire::test(ViewRun::class, [ 'run' => $failedRun, ]) ->callAction('retry') ->assertHasNoActionErrors() ->assertNotified('Inventory sync queued'); NotificationFacade::assertNothingSent(); expect(DatabaseNotification::query()->count())->toBe(0); $retriedRun = OperationRun::query() ->whereKeyNot((int) $failedRun->getKey()) ->latest('id') ->first(); expect($retriedRun)->not->toBeNull(); expect((string) $retriedRun?->status)->toBe(OperationRunStatus::Queued->value); expect((int) data_get($retriedRun?->context, 'triage.retry_of_run_id'))->toBe((int) $failedRun->getKey()); $this->get(SystemOperationRunLinks::view($retriedRun)) ->assertSuccessful() ->assertSee('Operation #'.(int) $retriedRun?->getKey()) ->assertSee('Show all operations') ->assertSee('Go to runbooks'); Livewire::test(ViewRun::class, [ 'run' => $failedRun, ]) ->callAction('mark_investigated', data: [ 'reason' => 'Checked by platform operations', ]) ->assertHasNoActionErrors() ->assertNotified('Run marked as investigated'); Livewire::test(ViewRun::class, [ 'run' => $runningRun, ]) ->assertActionVisible('show_all_operations') ->assertActionVisible('go_to_runbooks') ->assertActionHidden('retry') ->assertActionVisible('cancel') ->assertActionExists('cancel', fn (Action $action): bool => $action->getLabel() === 'Cancel' && $action->isConfirmationRequired()) ->assertActionVisible('mark_investigated') ->callAction('cancel') ->assertHasNoActionErrors() ->assertNotified('Run cancelled'); expect(AuditLog::query()->where('action', 'platform.system_console.retry')->exists())->toBeTrue(); expect(AuditLog::query()->where('action', 'platform.system_console.cancel')->exists())->toBeTrue(); expect(AuditLog::query()->where('action', 'platform.system_console.mark_investigated')->exists())->toBeTrue(); $runningRun->refresh(); expect((string) $runningRun->status)->toBe(OperationRunStatus::Completed->value) ->and((string) $runningRun->outcome)->toBe(OperationRunOutcome::Failed->value); }); it('keeps detail inspection and navigation available while hiding triage for view-only operators', function () { $run = OperationRun::factory()->create([ 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Failed->value, 'type' => 'inventory_sync', ]); $viewOnlyUser = PlatformUser::factory()->create([ 'capabilities' => [ PlatformCapabilities::ACCESS_SYSTEM_PANEL, PlatformCapabilities::OPERATIONS_VIEW, ], 'is_active' => true, ]); $this->actingAs($viewOnlyUser, 'platform'); Livewire::test(ViewRun::class, [ 'run' => $run, ]) ->assertActionVisible('show_all_operations') ->assertActionExists('show_all_operations', fn (Action $action): bool => $action->getLabel() === 'Show all operations' && $action->getUrl() === SystemOperationRunLinks::index()) ->assertActionVisible('go_to_runbooks') ->assertActionExists('go_to_runbooks', fn (Action $action): bool => $action->getLabel() === 'Go to runbooks' && $action->getUrl() === Runbooks::getUrl(panel: 'system')) ->assertActionHidden('retry') ->assertActionHidden('cancel') ->assertActionHidden('mark_investigated'); $this->get(SystemOperationRunLinks::view($run)) ->assertSuccessful() ->assertSee('Operation #'.(int) $run->getKey()) ->assertSee('Show all operations') ->assertSee('Go to runbooks'); });