Handle Dokploy project composes in widget
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-01-29 10:45:21 +01:00
parent 78af7838bf
commit dba0cd5882
3 changed files with 136 additions and 2 deletions

View File

@@ -52,6 +52,7 @@ class DokployPlatformHealth extends Widget
$applicationsPayload = Arr::get($project, 'applications', []);
$applications = $this->formatApplications(is_array($applicationsPayload) ? $applicationsPayload : [], $client);
$composes = $this->formatProjectComposes($project, $client);
$services = $this->formatProjectServices($project);
$results[] = [
@@ -59,11 +60,13 @@ class DokployPlatformHealth extends Widget
'project_id' => Arr::get($project, 'projectId', $projectId),
'name' => Arr::get($project, 'name') ?? Arr::get($project, 'projectName') ?? (string) $projectId,
'description' => Arr::get($project, 'description'),
'status' => $this->deriveProjectStatus($applications, $services),
'status' => $this->deriveProjectStatus($applications, $services, $composes),
'applications' => $applications,
'composes' => $composes,
'services' => $services,
'updated_at' => Arr::get($project, 'updatedAt') ?? Arr::get($project, 'createdAt'),
'applications_count' => count($applications),
'composes_count' => count($composes),
'services_count' => count($services),
];
}
@@ -204,6 +207,52 @@ class DokployPlatformHealth extends Widget
->all();
}
protected function formatProjectComposes(array $project, DokployClient $client): array
{
$composes = (array) Arr::get($project, 'compose', []);
return collect($composes)
->map(function (array $compose) use ($client) {
$composeId = Arr::get($compose, 'composeId') ?? Arr::get($compose, 'id');
$statusPayload = [];
$deployments = [];
if ($composeId) {
try {
$statusPayload = $client->composeStatus($composeId);
$deployments = $client->composeDeployments($composeId, 1);
} catch (\Throwable $exception) {
$statusPayload = [];
$deployments = [];
}
}
$composeDetails = Arr::get($statusPayload, 'compose', []);
return [
'id' => $composeId,
'name' => Arr::get($compose, 'name')
?? Arr::get($compose, 'appName')
?? Arr::get($composeDetails, 'name')
?? Arr::get($composeDetails, 'appName')
?? $composeId,
'status' => Arr::get($compose, 'composeStatus')
?? Arr::get($compose, 'status')
?? Arr::get($composeDetails, 'composeStatus')
?? Arr::get($composeDetails, 'status')
?? 'unknown',
'last_deploy' => Arr::get($deployments, '0.createdAt')
?? Arr::get($deployments, '0.created_at')
?? Arr::get($compose, 'updatedAt')
?? Arr::get($composeDetails, 'updatedAt'),
'services' => $this->formatServices(Arr::get($statusPayload, 'services', [])),
];
})
->filter(fn (array $compose) => filled($compose['name']))
->values()
->all();
}
protected function normalizeServiceList(array $services, string $type, string $idKey, string $statusKey): array
{
return collect($services)
@@ -246,11 +295,12 @@ class DokployPlatformHealth extends Widget
return $metrics;
}
protected function deriveProjectStatus(array $applications, array $services): string
protected function deriveProjectStatus(array $applications, array $services, array $composes): string
{
$statuses = collect($applications)
->pluck('status')
->merge(collect($services)->pluck('status'))
->merge(collect($composes)->pluck('status'))
->filter()
->map(fn ($status) => strtolower((string) $status))
->values();

View File

@@ -83,6 +83,9 @@
<x-filament::badge color="gray" :icon="Heroicon::RectangleStack">
Apps: {{ $project['applications_count'] ?? 0 }}
</x-filament::badge>
<x-filament::badge color="gray" :icon="Heroicon::ServerStack">
Composes: {{ $project['composes_count'] ?? 0 }}
</x-filament::badge>
<x-filament::badge color="gray" :icon="Heroicon::ServerStack">
Services: {{ $project['services_count'] ?? 0 }}
</x-filament::badge>
@@ -158,6 +161,55 @@
@endforelse
</div>
<div {{ $stacked }}>
<x-filament::badge color="gray" :icon="Heroicon::ServerStack">
Composes
</x-filament::badge>
@forelse($project['composes'] as $compose)
<div {{ $stacked }}>
<x-filament::badge
:color="$statusColors[$compose['status']] ?? 'gray'"
:icon="$statusIcons[$compose['status']] ?? Heroicon::QuestionMarkCircle"
>
{{ $compose['name'] ?? 'Compose' }}
@if(!empty($compose['status']))
({{ strtoupper($compose['status']) }})
@endif
</x-filament::badge>
<div {{ $detailsGrid }}>
@if(!empty($compose['id']))
<x-filament::badge color="gray" :icon="Heroicon::Identification">
{{ $compose['id'] }}
</x-filament::badge>
@endif
<x-filament::badge color="gray" :icon="Heroicon::Clock">
Last deploy:
{{ $compose['last_deploy'] ? \Illuminate\Support\Carbon::parse($compose['last_deploy'])->diffForHumans() : '—' }}
</x-filament::badge>
</div>
@if(!empty($compose['services']))
<div {{ $serviceGrid }}>
@foreach($compose['services'] as $service)
<x-filament::badge
:color="$serviceColors[$service['status']] ?? 'gray'"
:icon="array_key_exists($service['status'] ?? '', $serviceColors) ? Heroicon::Server : Heroicon::QuestionMarkCircle"
>
{{ $service['name'] }}: {{ strtoupper($service['status'] ?? 'N/A') }}
</x-filament::badge>
@endforeach
</div>
@endif
</div>
@empty
<x-filament::badge color="gray" :icon="Heroicon::QuestionMarkCircle">
No composes reported.
</x-filament::badge>
@endforelse
</div>
<div {{ $stacked }}>
<x-filament::badge color="gray" :icon="Heroicon::ServerStack">
Services

View File

@@ -40,6 +40,13 @@ class DokployPlatformHealthWidgetTest extends TestCase
'branch' => 'main',
],
],
'compose' => [
[
'composeId' => 'cmp_1',
'name' => 'Main Compose',
'composeStatus' => 'done',
],
],
'redis' => [
[
'redisId' => 'redis_1',
@@ -63,12 +70,37 @@ class DokployPlatformHealthWidgetTest extends TestCase
],
]);
$fakeClient->shouldReceive('composeStatus')
->with('cmp_1')
->andReturn([
'compose' => [
'name' => 'Main Compose',
'composeStatus' => 'done',
'updatedAt' => now()->toIso8601String(),
],
'services' => [
[
'serviceName' => 'web',
'status' => 'running',
],
],
]);
$fakeClient->shouldReceive('composeDeployments')
->with('cmp_1', 1)
->andReturn([
[
'createdAt' => now()->toIso8601String(),
],
]);
$this->app->instance(DokployClient::class, $fakeClient);
Livewire::test(DokployPlatformHealth::class)
->assertStatus(200)
->assertSee('Core')
->assertSee('API')
->assertSee('Main Compose')
->assertSee('Redis');
}