+ @if ($shouldShowProjectFilter)
+
+
+ {{ $selectedProjectId ? ($filterOptions['projects'][$selectedProjectId] ?? 'All Projects') : 'All Projects' }}
+
+
+
+ @foreach ($filterOptions['projects'] as $uuid => $name)
+
+ @endforeach
+
+
+ @endif
+
+ @if ($shouldShowServerFilter)
+
+
+ {{ $selectedServerId ? ($filterOptions['servers'][$selectedServerId] ?? 'All Servers') : 'All Servers' }}
+
+
+
+ @foreach ($filterOptions['servers'] as $id => $name)
+
+ @endforeach
+
+
+ @endif
+
+ @if ($shouldShowSourceFilter)
+
+
+ {{ $selectedSourceId ? (collect($filterOptions['sources'])->firstWhere('id', $selectedSourceId)['name'] ?? 'All Sources') : 'All Sources' }}
+
+
+
+ @foreach ($filterOptions['sources'] as $source)
+
+ @endforeach
+
+
+ @endif
+
+
+
+ {{ $selectedStatus ? ($filterOptions['statuses'][$selectedStatus] ?? 'All Statuses') : 'All Statuses' }}
+
+
+
+ @foreach ($filterOptions['statuses'] as $value => $label)
+
+ @endforeach
+
+
+
+ @if ($selectedProjectId || $selectedServerId || $selectedSourceId || $selectedStatus)
+
+ @endif
+
+
+ {{-- Deployments List --}}
+
+ {{-- Table Header --}}
+
+
ID
+
Environment
+
Status
+
Application
+
Commit
+
Created
+
+
+ @forelse ($deployments as $deployment)
+ @php
+ // Eager load relationships to avoid N+1 queries
+ $application = $deployment->application;
+ $environment = $application->environment ?? null;
+ $project = $environment->project ?? null;
+
+ // Format deployment ID for display (first 9 characters)
+ $shortId = substr($deployment->deployment_uuid, 0, 9);
+ $status = $deployment->status;
+ $statusUpdatedAt = $deployment->updated_at;
+ $statusTimeAgo = $statusUpdatedAt->diffForHumans(['short' => true]);
+
+ // Determine if deployment is actively running (needs polling/logs)
+ $isActive = in_array($status, ['in_progress', 'queued']);
+
+ // Status configuration for styling and display
+ // Maps status values to color schemes and display text
+ $statusConfig = match($status) {
+ 'finished' => ['color' => 'green', 'dot' => 'bg-green-500', 'text' => 'Ready', 'bg' => 'bg-green-100/80 dark:bg-green-900/30', 'textColor' => 'text-green-800 dark:text-green-200'],
+ 'failed' => ['color' => 'red', 'dot' => 'bg-red-500', 'text' => 'Error', 'bg' => 'bg-red-100 dark:bg-red-900/30', 'textColor' => 'text-red-800 dark:text-red-200'],
+ 'in_progress' => ['color' => 'yellow', 'dot' => 'bg-yellow-500', 'text' => 'In Progress', 'bg' => 'bg-yellow-100/80 dark:bg-yellow-900/30', 'textColor' => 'text-yellow-800 dark:text-yellow-200'],
+ 'queued' => ['color' => 'purple', 'dot' => 'bg-purple-500', 'text' => 'Queued', 'bg' => 'bg-purple-100/80 dark:bg-purple-900/30', 'textColor' => 'text-purple-800 dark:text-purple-200'],
+ 'cancelled-by-user' => ['color' => 'gray', 'dot' => 'bg-gray-500', 'text' => 'Cancelled', 'bg' => 'bg-gray-100 dark:bg-gray-900/30', 'textColor' => 'text-gray-800 dark:text-gray-200'],
+ default => ['color' => 'gray', 'dot' => 'bg-gray-500', 'text' => ucfirst($status), 'bg' => 'bg-gray-100 dark:bg-gray-900/30', 'textColor' => 'text-gray-800 dark:text-gray-200'],
+ };
+
+ // Format commit information for display
+ $commitHash = $deployment->commit ? substr($deployment->commit, 0, 7) : null;
+ $commitMessage = $deployment->commitMessage();
+ $branchName = $application->git_branch ?? 'main';
+ $isCurrent = false; // TODO: Determine if this is the current deployment
+
+ // Only load logs for active deployments to avoid unnecessary processing
+ $logLines = $isActive ? $this->getLogLines($deployment) : collect();
+ @endphp
+
+ {{-- Deployment Row with Expandable Logs --}}
+ {{-- Component-level polling handles updates, no need for per-row polling --}}
+
+
+ {{-- Deployment ID -- Clickable to deployment page --}}
+
+ @if ($project && $environment && $application)
+
+ {{ $shortId }}
+
+ @else
+
{{ $shortId }}
+ @endif
+
+
+ {{-- Environment Badge -- Clickable to environment page --}}
+
+
+ {{-- Status -- Not clickable --}}
+
+ @if ($isActive)
+
+ @else
+
+ @endif
+
+ {{ $statusConfig['text'] }}
+
+
+ {{ $statusTimeAgo }}
+
+
+
+ {{-- Application Info -- Clickable to application configuration page --}}
+
+
+ {{-- Commit Info -- Clickable to GitHub commit page --}}
+
+ @if ($commitHash)
+
+
{{ $branchName }}
+ @if ($application && $deployment->commit)
+
+ {{ $commitHash }}
+
+ @else
+
{{ $commitHash }}
+ @endif
+ @if ($commitMessage)
+
{{ Str::before($commitMessage, "\n") }}
+ @endif
+ @endif
+
+
+ {{-- Metadata -- Not clickable --}}
+
+ {{ $deployment->created_at->diffForHumans(['short' => true]) }}
+
+
+ {{-- Expand/Collapse Button for Logs --}}
+ {{-- Only show expand button if logs are available --}}
+ @if ($logLines->isNotEmpty())
+
+ @endif
+
+
+ {{-- Expandable Logs Section --}}
+ {{-- Shows real-time deployment logs when expanded --}}
+ @if ($logLines->isNotEmpty())
+
+
+
+ @foreach ($logLines as $line)
+
isset($line['command']) && $line['command'],
+ 'flex gap-2',
+ ])>
+ {{ $line['timestamp'] ?? '' }}
+ $line['hidden'] ?? false,
+ 'text-red-500' => $line['stderr'] ?? false,
+ 'font-bold' => isset($line['command']) && $line['command'],
+ 'whitespace-pre-wrap',
+ ])>{!! $line['line'] ?? '' !!}
+
+ @endforeach
+
+
+
+ @endif
+
+ @empty
+
+
No deployments found
+
Try adjusting your filters or check back later.
+
+ @endforelse
+
+
+ {{-- Pagination --}}
+ @if ($deployments->hasPages())
+
+
+ Showing {{ $deployments->firstItem() }} to {{ $deployments->lastItem() }} of {{ $deployments->total() }} deployments
+
+
+ @if ($deployments->onFirstPage())
+
+ @else
+
+ @endif
+
+
+ Page {{ $deployments->currentPage() }} of {{ $deployments->lastPage() }}
+
+
+ @if ($deployments->hasMorePages())
+
+ @else
+
+ @endif
+
+
+ @endif
+
+
diff --git a/routes/web.php b/routes/web.php
index 703f80ab5..f970df406 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -17,6 +17,7 @@ use App\Livewire\Notifications\Telegram as NotificationTelegram;
use App\Livewire\Notifications\Webhook as NotificationWebhook;
use App\Livewire\Profile\Index as ProfileIndex;
use App\Livewire\Project\Application\Configuration as ApplicationConfiguration;
+use App\Livewire\Deployment\Index as GlobalDeploymentIndex;
use App\Livewire\Project\Application\Deployment\Index as DeploymentIndex;
use App\Livewire\Project\Application\Deployment\Show as DeploymentShow;
use App\Livewire\Project\CloneMe as ProjectCloneMe;
@@ -246,7 +247,11 @@ Route::middleware(['auth', 'verified'])->group(function () {
});
Route::get('/servers', ServerIndex::class)->name('server.index');
- // Route::get('/server/new', ServerCreate::class)->name('server.create');
+
+ // Global deployments page - shows all deployments across all projects
+ Route::get('/deployments', GlobalDeploymentIndex::class)->name('deployment.index');
+
+ Route::get('/server/new', ServerCreate::class)->name('server.create');
Route::prefix('server/{server_uuid}')->group(function () {
Route::get('/', ServerShow::class)->name('server.show');