Docker tab: full inspect detail — icon, IP, ports, paths per container
- Replace pill view with per-container rows showing full detail - docker inspect batch call: networks+IPs, port mappings, bind mounts - Container icon from template XML, name links to WebUI if configured - Network IP badges (blue), port mapping badges (yellow) - Bind mount paths shown src→dst, collapsible expand for >3 paths - Large folders (>7 containers) auto-span full width - Status badge: RUNNING/STOPPED/PAUSED/EXITED with colour - Stopped containers dimmed, icons load from template XMLs
This commit is contained in:
@@ -88,23 +88,90 @@ function vv_dk_write_conf_map(string $raw, string $id, array $map): string {
|
||||
return $raw . "\n# ── Docker Folder Map ────────────────────────────────────────────────────────\n" . $block . "\n";
|
||||
}
|
||||
|
||||
// ── Container inventory ───────────────────────────────────────────────────────
|
||||
// ── Container inventory (full inspect) ───────────────────────────────────────
|
||||
|
||||
function vv_dk_webui(string $name, array $portMap): string {
|
||||
$template = '/boot/config/plugins/dockerMan/templates-user/my-' . $name . '.xml';
|
||||
if (!file_exists($template)) return '';
|
||||
$xml = @file_get_contents($template) ?: '';
|
||||
if (!preg_match('/<WebUI>(.*?)<\/WebUI>/s', $xml, $m)) return '';
|
||||
$url = trim($m[1]);
|
||||
if (!$url) return '';
|
||||
static $localIp = null;
|
||||
if ($localIp === null) {
|
||||
$localIp = trim(shell_exec("ip route get 8.8.8.8 2>/dev/null | awk '/src/{for(i=1;i<=NF;i++)if(\$i==\"src\")print \$(i+1)}'") ?: '');
|
||||
if (!$localIp) $localIp = gethostbyname(gethostname());
|
||||
}
|
||||
$url = str_replace('[IP]', $localIp, $url);
|
||||
$url = preg_replace_callback('/\[PORT:(\d+)\]/', fn($pm) => $portMap[$pm[1]] ?? $pm[1], $url);
|
||||
return $url;
|
||||
}
|
||||
|
||||
function vv_dk_icon(string $name): string {
|
||||
$template = '/boot/config/plugins/dockerMan/templates-user/my-' . $name . '.xml';
|
||||
if (!file_exists($template)) return '';
|
||||
$xml = @file_get_contents($template) ?: '';
|
||||
return preg_match('/<Icon>(.*?)<\/Icon>/s', $xml, $m) ? trim($m[1]) : '';
|
||||
}
|
||||
|
||||
function vv_dk_inspect_all(): array {
|
||||
$ids = trim(shell_exec("docker ps -aq 2>/dev/null") ?: '');
|
||||
if (!$ids) return [];
|
||||
|
||||
$idList = implode(' ', array_map('escapeshellarg', explode("\n", $ids)));
|
||||
$raw = shell_exec("docker inspect $idList 2>/dev/null") ?: '[]';
|
||||
$data = json_decode($raw, true) ?: [];
|
||||
|
||||
function vv_dk_containers(): array {
|
||||
$raw = shell_exec("docker ps -a --format '{{.Names}}\t{{.Status}}\t{{.Image}}\t{{.RunningFor}}' 2>/dev/null") ?: '';
|
||||
$out = [];
|
||||
foreach (explode("\n", trim($raw)) as $line) {
|
||||
if (!$line) continue;
|
||||
[$name, $status, $image, $age] = array_pad(explode("\t", $line, 4), 4, '');
|
||||
$name = trim($name);
|
||||
foreach ($data as $c) {
|
||||
$name = ltrim($c['Name'] ?? '', '/');
|
||||
if (!$name) continue;
|
||||
$running = str_starts_with(trim($status), 'Up');
|
||||
$status = $c['State']['Status'] ?? 'unknown';
|
||||
$running = $status === 'running';
|
||||
$image = $c['Config']['Image'] ?? '';
|
||||
|
||||
// Networks: name → IP
|
||||
$networks = [];
|
||||
foreach ($c['NetworkSettings']['Networks'] ?? [] as $netName => $net) {
|
||||
$ip = $net['IPAddress'] ?? '';
|
||||
if ($ip) $networks[$netName] = $ip;
|
||||
}
|
||||
|
||||
// Port mappings: hostPort → containerPort/proto
|
||||
$ports = [];
|
||||
$portMap = []; // containerPort → hostPort (for WebUI resolution)
|
||||
foreach ($c['HostConfig']['PortBindings'] ?? [] as $containerPort => $bindings) {
|
||||
foreach ($bindings ?? [] as $b) {
|
||||
$hp = $b['HostPort'] ?? '';
|
||||
if ($hp) {
|
||||
$ports[] = $hp . '→' . $containerPort;
|
||||
[$cp] = explode('/', $containerPort);
|
||||
$portMap[$cp] = $hp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bind mounts only
|
||||
$mounts = [];
|
||||
foreach ($c['Mounts'] ?? [] as $m) {
|
||||
if (($m['Type'] ?? '') === 'bind') {
|
||||
$mounts[] = ['src' => $m['Source'] ?? '', 'dst' => $m['Destination'] ?? ''];
|
||||
}
|
||||
}
|
||||
|
||||
$webui = vv_dk_webui($name, $portMap);
|
||||
$icon = vv_dk_icon($name);
|
||||
|
||||
$out[$name] = [
|
||||
'name' => $name,
|
||||
'running' => $running,
|
||||
'status' => trim($status),
|
||||
'image' => trim($image),
|
||||
'age' => trim($age),
|
||||
'name' => $name,
|
||||
'running' => $running,
|
||||
'status' => $status,
|
||||
'image' => $image,
|
||||
'networks' => $networks,
|
||||
'ports' => $ports,
|
||||
'mounts' => $mounts,
|
||||
'webui' => $webui,
|
||||
'icon' => $icon,
|
||||
];
|
||||
}
|
||||
return $out;
|
||||
@@ -114,12 +181,14 @@ function vv_dk_containers(): array {
|
||||
|
||||
function vv_dk_all(): array {
|
||||
$jsonData = vv_dk_read_json();
|
||||
$containers = vv_dk_containers();
|
||||
$containers = vv_dk_inspect_all();
|
||||
$currentHost= vv_detect_host();
|
||||
$myId = strtoupper($currentHost);
|
||||
$myRaw = vv_read_conf_raw($currentHost . '.conf');
|
||||
$confMap = vv_dk_read_conf_map($myRaw, $myId);
|
||||
|
||||
$empty = ['name'=>'','running'=>false,'status'=>'','image'=>'','networks'=>[],'ports'=>[],'mounts'=>[],'webui'=>'','icon'=>''];
|
||||
|
||||
// Build folder list enriched with live container data
|
||||
$assigned = [];
|
||||
$folders = [];
|
||||
@@ -127,23 +196,21 @@ function vv_dk_all(): array {
|
||||
$ctrs = [];
|
||||
foreach ($f['containers'] ?? [] as $cname) {
|
||||
$assigned[$cname] = true;
|
||||
$ctrs[] = array_merge(['name' => $cname, 'running' => false, 'status' => '', 'image' => '', 'age' => ''],
|
||||
$containers[$cname] ?? []);
|
||||
$ctrs[] = array_merge($empty, ['name' => $cname], $containers[$cname] ?? []);
|
||||
}
|
||||
usort($ctrs, fn($a, $b) => $b['running'] <=> $a['running'] ?: strcmp($a['name'], $b['name']));
|
||||
$running = count(array_filter($ctrs, fn($c) => $c['running']));
|
||||
$folders[] = [
|
||||
'id' => $fid,
|
||||
'name' => $f['name'] ?? 'Unnamed',
|
||||
'icon' => $f['icon'] ?? '',
|
||||
'total' => count($ctrs),
|
||||
'running' => $running,
|
||||
'containers'=> $ctrs,
|
||||
'id' => $fid,
|
||||
'name' => $f['name'] ?? 'Unnamed',
|
||||
'total' => count($ctrs),
|
||||
'running' => $running,
|
||||
'containers' => $ctrs,
|
||||
];
|
||||
}
|
||||
usort($folders, fn($a, $b) => strcmp($a['name'], $b['name']));
|
||||
|
||||
// Ungrouped: in docker ps but not in any folder
|
||||
// Ungrouped: running but not in any folder
|
||||
$ungrouped = [];
|
||||
foreach ($containers as $name => $c) {
|
||||
if (isset($assigned[$name])) continue;
|
||||
|
||||
Reference in New Issue
Block a user