fix(canvas): show servers without resources on the servers canvas

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-10-21 18:02:02 +02:00
co-authored by Claude Opus 5.5
parent b1f2abf868
commit c4bc9ae8bf
2 changed files with 36 additions and 1 deletions
+18 -1
View File
@@ -65,6 +65,23 @@ class ServerCanvas
->reject(fn (Environment $environment) => $used->has($environment->id))
->map(fn (Environment $environment) => $this->canvas->emptyNode($environment->project, $environment, $zoneOf($environment->project), $environment->project->name.' / '.$environment->name, $canEdit))
->values();
// The canvas draws a zone around its cards, so a server without cards gets a placeholder card.
$filled = $nodes->concat($empty)->pluck('zone')->flip();
$bare = $servers->reject(fn (Server $server) => $filled->has($server->uuid))->map(fn (Server $server) => [
'id' => 'empty-server:'.$server->uuid,
'type' => 'empty',
'name' => 'No resources yet',
'subtitle' => 'Open to see this server',
'status' => null,
'zone' => $server->uuid,
'extra_zones' => [],
'urls' => [],
'children' => [],
'link' => route('server.show', ['server_uuid' => $server->uuid]),
'context' => null,
'project' => null,
'environment' => null,
])->values();
return [
'title' => $single ? $single->name : 'Servers',
@@ -80,7 +97,7 @@ class ServerCanvas
'zones' => $servers->map(fn (Server $server) => [...$this->canvas->zone($server, $canReadSensitive), 'details' => $this->details($server)])
->when($empty->contains('zone', EnvironmentCanvas::EMPTY_ZONE), fn (Collection $zones) => $zones->push($this->canvas->emptyZone()))
->values()->all(),
'nodes' => $nodes->concat($empty)->all(),
'nodes' => $nodes->concat($empty)->concat($bare)->all(),
'links' => collect($graph['links'])->filter(fn (array $link) => $shown->has($link['source']) && $shown->has($link['target']))->values()->all(),
'positions' => [],
];
+18
View File
@@ -105,6 +105,24 @@ test('the servers canvas puts empty environments of a project without resources
->and(collect($response->json('nodes'))->where('project.uuid', $bare->uuid)->pluck('zone')->all())->toBe([$this->db->uuid]);
});
test('the servers canvas shows a server without resources as a placeholder card in its zone', function () {
serverCanvasApp($this->environment, $this->web, 'storefront');
Environment::query()->where('project_id', $this->project->id)->where('name', '!=', 'staging')->delete();
$response = serverCanvasSession($this, $this->admin, $this->team)
->getJson('/canvas/api/servers/canvas')
->assertOk();
$placeholder = collect($response->json('nodes'))->firstWhere('zone', $this->db->uuid);
expect($placeholder)->toMatchArray([
'id' => 'empty-server:'.$this->db->uuid,
'type' => 'empty',
'name' => 'No resources yet',
'link' => route('server.show', ['server_uuid' => $this->db->uuid]),
])->and(collect($response->json('nodes'))->where('zone', $this->web->uuid)->pluck('name')->all())->toBe(['storefront']);
});
test('one server canvas shows only that server, and links that leave it are hidden', function () {
$app = serverCanvasApp($this->environment, $this->web, 'storefront');
$api = serverCanvasApp($this->environment, $this->db, 'orders-api');