This commit is contained in:
RGJorge
2026-05-11 00:56:11 +00:00
parent 17e805d0fc
commit 3d544673ff
8 changed files with 200 additions and 25 deletions
+1
View File
@@ -24,6 +24,7 @@ function makeSvc(overrides: Partial<Service> = {}): Service {
exit_code: 0,
restart_count: 0,
oom_killed: false,
mounts: [],
...overrides,
};
}
+2
View File
@@ -141,6 +141,7 @@ const en = {
"detail.memory": "Memory",
"detail.noStats": "No stats available",
"detail.cpuHistory": "Usage History",
"detail.mounts": "Volumes & Mounts",
"detail.memoryHistory": "Memory History",
"detail.noHistory": "No historical data available",
"detail.loadingHistory": "Loading history...",
@@ -399,6 +400,7 @@ const es: Record<TranslationKey, string> = {
"detail.memory": "Memoria",
"detail.noStats": "No hay estad\u00edsticas disponibles",
"detail.cpuHistory": "Historial de Consumo",
"detail.mounts": "Volúmenes y Mounts",
"detail.memoryHistory": "Historial de Memoria",
"detail.noHistory": "No hay datos hist\u00f3ricos disponibles",
"detail.loadingHistory": "Cargando historial...",
+33
View File
@@ -723,6 +723,39 @@ export function DetailPanel({ service, stats, logLines, token, closing, locked,
</div>
)}
{/* Volumes / Mounts */}
{service.mounts && service.mounts.length > 0 && (
<div>
<span className="text-[11px] uppercase tracking-wider text-slate-500 block mb-1">{t("detail.mounts")}</span>
<div className="space-y-1.5">
{service.mounts.map((m, i) => {
const typeColor = m.type === "volume" ? "text-emerald-400 bg-emerald-500/10"
: m.type === "bind" ? "text-cyan-400 bg-cyan-500/10"
: "text-amber-400 bg-amber-500/10";
return (
<div key={i} className="bg-slate-800/60 border border-slate-700/40 rounded px-2.5 py-1.5">
<div className="flex items-center gap-1.5 mb-0.5">
<span className={`text-[10px] uppercase font-mono px-1.5 py-0.5 rounded ${typeColor}`}>{m.type}</span>
<span className="text-xs font-mono text-slate-200 truncate flex-1" title={m.destination}>{m.destination}</span>
<span className={`text-[10px] font-mono px-1.5 py-0.5 rounded ${m.rw ? "text-slate-400 bg-slate-700/60" : "text-amber-300 bg-amber-500/15"}`}>
{m.rw ? "rw" : "ro"}
</span>
</div>
{m.name && (
<div className="text-[10px] text-slate-400 font-mono pl-1 truncate" title={m.name}>
<span className="text-slate-600">name:</span> {m.name}
</div>
)}
<div className="text-[10px] text-slate-500 font-mono pl-1 truncate" title={m.source}>
<span className="text-slate-600"></span> {m.source}
</div>
</div>
);
})}
</div>
</div>
)}
{/* Connected services */}
{connectedSvcs.length > 0 && (
<div>
+1
View File
@@ -24,6 +24,7 @@ function makeSvc(overrides: Partial<Service> = {}): Service {
exit_code: 0,
restart_count: 0,
oom_killed: false,
mounts: [],
...overrides,
};
}
+9
View File
@@ -82,6 +82,15 @@ export async function discoverServices(all: boolean, projects: string[]): Promis
exit_code: exitCode,
restart_count: restartCount,
oom_killed: oomKilled,
mounts: (info?.Mounts || []).map((m: any) => ({
type: m.Type || "bind",
source: m.Source || "",
destination: m.Destination || "",
name: m.Name || undefined,
driver: m.Driver || undefined,
mode: m.Mode || "",
rw: m.RW !== false,
})),
};
});
+18
View File
@@ -1,3 +1,20 @@
export interface ContainerMount {
/** "bind" = host directory · "volume" = named docker volume · "tmpfs" = in-memory */
type: "bind" | "volume" | "tmpfs" | string;
/** Path on the host (or volume backend path) */
source: string;
/** Path inside the container */
destination: string;
/** Volume name (only for type=volume) */
name?: string;
/** Volume driver (only for type=volume) */
driver?: string;
/** Mode string, e.g. "rw", "ro", "rprivate" */
mode: string;
/** true = read-write, false = read-only */
rw: boolean;
}
export interface Service {
id: string;
uid: string;
@@ -19,6 +36,7 @@ export interface Service {
exit_code: number;
restart_count: number;
oom_killed: boolean;
mounts: ContainerMount[];
}
export interface Connection {