Files
coolify/app/Livewire/Dashboard.php
T
Andras Bacsai fa1895c99a feat(dashboard): add canvas view with active deployment overlay
Add a /dashboard/canvas page that renders every team server with its
resources and their running or queued deployments, backed by a new
ServerCanvasController::dashboard endpoint and a per-server usage
endpoint for zone headers. The dashboard remembers the list/canvas
choice and each section (projects, servers) its own table/grid view.

- Show Deploying/Queued pills on canvas cards and a foldable recent
  deployments panel; add shared CanvasControls component
- Allow backup downloads from the server host via the S3 download
  storage (PrepareFileDownloadJob accepts a null container)
- Extract backup toggle/run actions into ManagesDatabaseBackup and
  surface them in backup execution headers; merge S3 and retention
  sections into the general backup settings
- Move deployments indicator to the top bar and add a main nav
  resource menu with submenus; simplify breadcrumbs and settings
  layouts
- Add shared variables overview canvas and scheduled task modals
- Add feature tests for dashboard canvas, view modes, navbar
  submenus, backup S3 downloads and scheduled task modals
2026-10-14 23:55:28 +02:00

84 lines
2.2 KiB
PHP

<?php
namespace App\Livewire;
use App\Livewire\Concerns\RemembersCanvasView;
use App\Models\PrivateKey;
use App\Models\Project;
use App\Models\Server;
use App\Models\TeamInvitation;
use Illuminate\Support\Collection;
use Livewire\Component;
class Dashboard extends Component
{
use RemembersCanvasView;
public Collection $projects;
public Collection $servers;
public Collection $privateKeys;
public function mount()
{
if ($this->prefersCanvasView('dashboard')) {
$this->redirectRoute('dashboard.canvas', navigate: true);
return;
}
$this->privateKeys = PrivateKey::ownedByCurrentTeamCached();
$this->servers = Server::ownedByCurrentTeamCached();
$this->projects = Project::ownedByCurrentTeam()
->with(['environments:id,uuid,name,project_id'])
->withCount([
'applications',
'services',
'postgresqls',
'redis',
'keydbs',
'dragonflies',
'clickhouses',
'mongodbs',
'mysqls',
'mariadbs',
'sqlites',
])
->get();
}
public function render()
{
return view('livewire.dashboard', [
'pendingInvitations' => $this->pendingInvitations(),
]);
}
/**
* Unexpired invitations for the user's email to teams the user has not joined yet.
*
* Uses hasExpired() instead of isValid() so rendering never deletes invitations or users.
*
* @return Collection<int, TeamInvitation>
*/
private function pendingInvitations(): Collection
{
$user = auth()->user();
if (! $user) {
return collect();
}
return TeamInvitation::query()
->where('email', strtolower($user->email))
->whereHas('team')
->whereNotIn('team_id', $user->teams()->select('teams.id'))
->with('team:id,name')
->oldest()
->get()
->reject(fn (TeamInvitation $invitation) => $invitation->hasExpired())
->values();
}
}