@php $runs = $runs ?? collect(); $overflowCount = (int) ($overflowCount ?? 0); $tenant = $tenant ?? null; $visibleRunCount = $runs->count(); $activeRunCount = (int) ($activeRunCount ?? ($runs->filter(fn ($run): bool => $run instanceof \App\Models\OperationRun && $run->isCurrentlyActive())->count() + $overflowCount)); $primaryRun = $runs->first(); $hasActiveVisibleRuns = $runs->contains(fn ($run): bool => $run instanceof \App\Models\OperationRun && $run->isCurrentlyActive()); $hasTerminalFollowUpVisibleRuns = $runs->contains(fn ($run): bool => $run instanceof \App\Models\OperationRun && ! $run->isCurrentlyActive() && $run->requiresOperatorReview()); $hasTerminalVisibleRuns = $runs->contains(fn ($run): bool => $run instanceof \App\Models\OperationRun && ! $run->isCurrentlyActive()); $usesCollectivePrimaryAction = $visibleRunCount > 1; $operationsCollectionLabel = \App\Support\OperationRunLinks::collectionLabel(); $operationsIndexUrl = $tenant ? \App\Support\OpsUx\OperationRunUrl::index($tenant) : null; $primaryActionLabel = $usesCollectivePrimaryAction ? 'Review operations' : 'View operation'; $bannerTitle = $hasTerminalVisibleRuns ? 'Operation updates' : 'Active operations'; $bannerHelper = match (true) { $hasTerminalFollowUpVisibleRuns => 'Review needed operation updates stay visible until you open Operations or acknowledge them in this browser session.', $hasTerminalVisibleRuns => 'Successful operation updates stay briefly visible so you can confirm completion and keep working.', default => 'Queued and running work stays inside the tenant shell until you need the diagnostics view.', }; $primaryActionUrl = null; if ($usesCollectivePrimaryAction) { $primaryActionUrl = $operationsIndexUrl; } elseif ($tenant && $primaryRun) { $primaryActionUrl = \App\Support\OpsUx\OperationRunUrl::view($primaryRun, $tenant); } $tertiaryActionLabel = $hasTerminalFollowUpVisibleRuns ? 'Acknowledge' : ($hasActiveVisibleRuns ? 'Hide activity' : 'Dismiss'); @endphp {{-- Cleanup is delegated to the shared poller helper, which uses teardownObserver and new MutationObserver. --}} {{-- Widget must always be mounted, even when empty, so it can receive Livewire events --}}
@if($runs->isNotEmpty())

{{ $bannerTitle }}

{{ $bannerHelper }}

@if ($primaryActionUrl) {{ $primaryActionLabel }} @endif @if ($operationsIndexUrl) Show all operations @endif
@foreach ($runs as $run) @php $uxStatus = \App\Support\OpsUx\OperationStatusNormalizer::toUxStatus($run->status, $run->outcome); $isTerminalRun = ! $run->isCurrentlyActive(); $summaryCounts = is_array($run->summary_counts) ? $run->summary_counts : []; $hasDeterminateProgress = ! $isTerminalRun && $run->status !== 'queued' && is_numeric($summaryCounts['total'] ?? null) && is_numeric($summaryCounts['processed'] ?? null) && (int) $summaryCounts['total'] > 0; $lifecycleAttention = \App\Support\OpsUx\OperationUxPresenter::lifecycleAttentionSummary($run); $showsLifecycleAttention = $lifecycleAttention !== null && ($lifecycleAttention !== 'Likely stale' || $run->status === 'queued' || ! $hasDeterminateProgress); $progressTotal = $hasDeterminateProgress ? max(1, (int) $summaryCounts['total']) : null; $progressProcessed = $hasDeterminateProgress ? min(max(0, (int) $summaryCounts['processed']), $progressTotal) : null; $progressPercent = $hasDeterminateProgress ? max(0, min(100, (int) round(($progressProcessed / $progressTotal) * 100))) : null; $progressLabel = $hasDeterminateProgress ? sprintf('%d / %d processed (%d%%)', $progressProcessed, $progressTotal, $progressPercent) : null; $showsIndeterminateProgress = ! $isTerminalRun && ! $hasDeterminateProgress; $statusLabel = match ($uxStatus) { 'queued' => 'Queued for execution', 'running' => 'In progress', 'succeeded' => 'Completed successfully', 'partial' => 'Completed with follow-up', 'blocked' => 'Blocked by prerequisite', default => 'Execution failed', }; $statusClasses = match ($uxStatus) { 'queued' => 'bg-primary-50 text-primary-700 ring-1 ring-inset ring-primary-100 dark:bg-primary-500/10 dark:text-primary-200 dark:ring-primary-400/20', 'running' => 'bg-primary-100 text-primary-800 ring-1 ring-inset ring-primary-200 dark:bg-primary-500/20 dark:text-primary-100 dark:ring-primary-400/25', 'succeeded' => 'bg-success-50 text-success-800 ring-1 ring-inset ring-success-200 dark:bg-success-500/15 dark:text-success-100 dark:ring-success-400/25', 'partial', 'blocked' => 'bg-warning-50 text-warning-800 ring-1 ring-inset ring-warning-200 dark:bg-warning-500/10 dark:text-warning-100 dark:ring-warning-400/25', default => 'bg-danger-50 text-danger-800 ring-1 ring-inset ring-danger-200 dark:bg-danger-500/10 dark:text-danger-100 dark:ring-danger-400/25', }; $activityLabel = $run->status === 'queued' ? 'Waiting for worker.' : 'Progress details pending.'; $elapsedLabel = \App\Support\OpsUx\RunDurationInsights::elapsedCompact($run); $surfaceGuidance = \App\Support\OpsUx\OperationUxPresenter::surfaceGuidance($run); $activitySummaryLine = $isTerminalRun ? sprintf('Completed · %s', \App\Support\OpsUx\RunDurationInsights::completedRecency($run)) : sprintf( '%s · %s · %s', $run->status === 'queued' ? 'Queued' : 'Running', $elapsedLabel, $progressLabel ?? $activityLabel, ); @endphp

{{ \App\Support\OperationCatalog::label((string) $run->type) }}

{{ $statusLabel }} @if ($showsLifecycleAttention) {{ $lifecycleAttention }} @endif

{{ $activitySummaryLine }}

@if ($isTerminalRun && $surfaceGuidance)

{{ $surfaceGuidance }}

@endif @if ($progressPercent !== null && $progressLabel !== null)
@elseif ($showsIndeterminateProgress)
@endif
@endforeach
@if ($overflowCount > 0)

{{ $overflowCount }} more operation update{{ $overflowCount === 1 ? '' : 's' }} available in @if ($operationsIndexUrl) {{ $operationsCollectionLabel }}. @else {{ $operationsCollectionLabel }}. @endif

@endif
{{ $activeRunCount }} active operation{{ $activeRunCount === 1 ? '' : 's' }}
@if($tenant) Show all operations @endif
@endif