Deep-link Dozzle logs button to specific container

The discover API now fetches container names from Docker via the Python
API on port 9876 and matches them to services by UUID. The Dozzle logs
button builds a proper deep link using the Dozzle host ID and container
name, opening directly to that container's log stream.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-02-04 01:17:46 +01:00
parent 5aa7559d43
commit e4e5cc97d3
4 changed files with 32 additions and 6 deletions

View File

@@ -56,9 +56,28 @@ function buildUrl(fqdn: string | null, port: number): string {
return `http://${nucHost}`; return `http://${nucHost}`;
} }
async function fetchContainerNames(): Promise<string[]> {
try {
const res = await fetch(`http://${nucHost}:9876/containers`, {
signal: AbortSignal.timeout(5000),
});
if (!res.ok) return [];
return await res.json() as string[];
} catch {
return [];
}
}
function findContainerName(uuid: string, containers: string[]): string | undefined {
return containers.find(c => c.includes(uuid));
}
export async function GET() { export async function GET() {
try { try {
const resources = await fetchResources(); const [resources, containerNames] = await Promise.all([
fetchResources(),
fetchContainerNames(),
]);
if (!resources) { if (!resources) {
return NextResponse.json( return NextResponse.json(
@@ -88,6 +107,7 @@ export async function GET() {
resourceType: 'application', resourceType: 'application',
uuid: resource.uuid, uuid: resource.uuid,
coolifyStatus: resource.status, coolifyStatus: resource.status,
container: findContainerName(resource.uuid, containerNames),
}; };
} }
@@ -121,6 +141,7 @@ export async function GET() {
resourceType: 'service', resourceType: 'service',
uuid: resource.uuid, uuid: resource.uuid,
coolifyStatus: resource.status, coolifyStatus: resource.status,
container: findContainerName(resource.uuid, containerNames),
}; };
} }
@@ -137,6 +158,7 @@ export async function GET() {
resourceType: 'database', resourceType: 'database',
uuid: resource.uuid, uuid: resource.uuid,
coolifyStatus: resource.status, coolifyStatus: resource.status,
container: findContainerName(resource.uuid, containerNames),
}; };
} }

View File

@@ -2,8 +2,6 @@
import { useState, useCallback } from 'react'; import { useState, useCallback } from 'react';
import { Service, DiscoveredService, getCoolifyUrl, getDozzleUrl } from '@/lib/services'; import { Service, DiscoveredService, getCoolifyUrl, getDozzleUrl } from '@/lib/services';
const dozzleUrl = getDozzleUrl();
import { HealthStatus } from '@/lib/PortalContext'; import { HealthStatus } from '@/lib/PortalContext';
import { Icon } from './Icons'; import { Icon } from './Icons';
@@ -175,7 +173,7 @@ export function ServiceCard({ service, status }: ServiceCardProps) {
{/* View logs in Dozzle */} {/* View logs in Dozzle */}
{discovered && ( {discovered && (
<a <a
href={dozzleUrl} href={getDozzleUrl(service as DiscoveredService)}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
title="View logs" title="View logs"

View File

@@ -18,4 +18,5 @@ export const clientConfig = {
coolifyEnvUuid: process.env.NEXT_PUBLIC_COOLIFY_ENV_UUID || 'dckc0w4ko8s888c4gk84skoo', coolifyEnvUuid: process.env.NEXT_PUBLIC_COOLIFY_ENV_UUID || 'dckc0w4ko8s888c4gk84skoo',
grafanaUrl: process.env.NEXT_PUBLIC_GRAFANA_URL || 'http://192.168.1.3:3333', grafanaUrl: process.env.NEXT_PUBLIC_GRAFANA_URL || 'http://192.168.1.3:3333',
dozzleUrl: process.env.NEXT_PUBLIC_DOZZLE_URL || 'http://192.168.1.3:9999', dozzleUrl: process.env.NEXT_PUBLIC_DOZZLE_URL || 'http://192.168.1.3:9999',
dozzleHostId: process.env.NEXT_PUBLIC_DOZZLE_HOST_ID || '6c1738d9-6f12-4ed7-9293-70a91f407347',
}; };

View File

@@ -26,8 +26,13 @@ export function getCoolifyUrl(service: DiscoveredService): string {
return `${base}/project/${project}/environment/${env}/${service.resourceType}/${service.uuid}`; return `${base}/project/${project}/environment/${env}/${service.resourceType}/${service.uuid}`;
} }
export function getDozzleUrl(): string { export function getDozzleUrl(service?: DiscoveredService): string {
return process.env.NEXT_PUBLIC_DOZZLE_URL || 'http://192.168.1.3:9999'; const base = process.env.NEXT_PUBLIC_DOZZLE_URL || 'http://192.168.1.3:9999';
const hostId = process.env.NEXT_PUBLIC_DOZZLE_HOST_ID || '6c1738d9-6f12-4ed7-9293-70a91f407347';
if (service?.container) {
return `${base}/container/${hostId}~${service.container}`;
}
return base;
} }
export interface Bookmark { export interface Bookmark {