mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-01 01:55:13 +08:00
🏅 Sync 2026-03-20 23:05:15
This commit is contained in:
1 parent
2a09fa2e10
commit
dc4644df51
2 files changed
+75
-26
No files matched your search
@@ -73,7 +73,8 @@ return dm2.dv.extend({
|
|||||||
const hostConfig = c.HostConfig || {};
|
const hostConfig = c.HostConfig || {};
|
||||||
const resolvedImage = resolveImageId(c.Image) || resolveImageId(c.Config?.Image) || c.Image || c.Config?.Image || '';
|
const resolvedImage = resolveImageId(c.Image) || resolveImageId(c.Config?.Image) || c.Image || c.Config?.Image || '';
|
||||||
const builtInNetworks = new Set(['none', 'bridge', 'host']);
|
const builtInNetworks = new Set(['none', 'bridge', 'host']);
|
||||||
const [netnames, nets] = Object.entries(c.NetworkSettings?.Networks || {});
|
// Object.entries returns [[name, obj], ...] — pick the first network
|
||||||
|
const [[firstName, firstNet] = []] = Object.entries(c.NetworkSettings?.Networks || {});
|
||||||
|
|
||||||
containerData.container = {
|
containerData.container = {
|
||||||
name: c.Name?.substring(1) || '',
|
name: c.Name?.substring(1) || '',
|
||||||
@@ -82,20 +83,18 @@ return dm2.dv.extend({
|
|||||||
image: resolvedImage,
|
image: resolvedImage,
|
||||||
privileged: hostConfig.Privileged ? 1 : 0,
|
privileged: hostConfig.Privileged ? 1 : 0,
|
||||||
restart_policy: hostConfig.RestartPolicy?.Name || 'unless-stopped',
|
restart_policy: hostConfig.RestartPolicy?.Name || 'unless-stopped',
|
||||||
network: (() => {
|
network: firstName || '',
|
||||||
return (netnames && (netnames.length > 0)) ? netnames[0] : '';
|
|
||||||
})(),
|
|
||||||
ipv4: (() => {
|
ipv4: (() => {
|
||||||
if (builtInNetworks.has(netnames[0])) return '';
|
if (!firstName || builtInNetworks.has(firstName)) return '';
|
||||||
return (nets && (nets.length > 0)) ? nets[0]?.IPAddress || '' : '';
|
return firstNet?.IPAddress || '';
|
||||||
})(),
|
})(),
|
||||||
ipv6: (() => {
|
ipv6: (() => {
|
||||||
if (builtInNetworks.has(netnames[0])) return '';
|
if (!firstName || builtInNetworks.has(firstName)) return '';
|
||||||
return (nets && (nets.length > 0)) ? nets[0]?.GlobalIPv6Address || '' : '';
|
return firstNet?.GlobalIPv6Address || '';
|
||||||
})(),
|
})(),
|
||||||
ipv6_lla: (() => {
|
ipv6_lla: (() => {
|
||||||
if (builtInNetworks.has(netnames[0])) return '';
|
if (!firstName || builtInNetworks.has(firstName)) return '';
|
||||||
return (nets && (nets.length > 0)) ? nets[0]?.LinkLocalIPv6Address || '' : '';
|
return firstNet?.LinkLocalIPv6Address || '';
|
||||||
})(),
|
})(),
|
||||||
link: hostConfig.Links || [],
|
link: hostConfig.Links || [],
|
||||||
dns: hostConfig.Dns || [],
|
dns: hostConfig.Dns || [],
|
||||||
@@ -135,9 +134,12 @@ return dm2.dv.extend({
|
|||||||
publish: (() => {
|
publish: (() => {
|
||||||
const ports = [];
|
const ports = [];
|
||||||
for (const [containerPort, bindings] of Object.entries(hostConfig.PortBindings || {})) {
|
for (const [containerPort, bindings] of Object.entries(hostConfig.PortBindings || {})) {
|
||||||
if (Array.isArray(bindings) && bindings.length > 0 && bindings[0]?.HostPort) {
|
if (Array.isArray(bindings) && bindings.length > 0) {
|
||||||
const hostPort = bindings[0].HostPort;
|
for (const b of bindings) {
|
||||||
ports.push(hostPort + ':' + containerPort);
|
if (!b?.HostPort) continue;
|
||||||
|
const ip = b.HostIp || '';
|
||||||
|
ports.push((ip ? ip + ':' : '') + b.HostPort + ':' + containerPort);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ports;
|
return ports;
|
||||||
@@ -801,9 +803,15 @@ return dm2.dv.extend({
|
|||||||
(Array.isArray(publish) ? publish : [publish])
|
(Array.isArray(publish) ? publish : [publish])
|
||||||
.filter(p => p && typeof p === 'string' && p.trim().length > 0)
|
.filter(p => p && typeof p === 'string' && p.trim().length > 0)
|
||||||
.map(p => {
|
.map(p => {
|
||||||
const m = p.match(/^(\d+):(\d+)\/(tcp|udp)$/);
|
// formats: hostPort:cPort/proto or hostIp:hostPort:cPort/proto
|
||||||
if (m) return [`${m[2]}/${m[3]}`, [{ HostPort: m[1] }]];
|
const m = p.match(/^(?:([^:]+):(\d+)|(\d+)):(\d+)\/(tcp|udp)$/);
|
||||||
return null;
|
if (!m) return null;
|
||||||
|
const hostIp = m[1] || '';
|
||||||
|
const hostPort = m[2] || m[3];
|
||||||
|
const cPort = m[4];
|
||||||
|
const proto = m[5];
|
||||||
|
const binding = hostIp ? { HostIp: hostIp, HostPort: hostPort } : { HostPort: hostPort };
|
||||||
|
return [`${cPort}/${proto}`, [binding]];
|
||||||
}).filter(Boolean)
|
}).filter(Boolean)
|
||||||
) : undefined,
|
) : undefined,
|
||||||
Mounts: undefined,
|
Mounts: undefined,
|
||||||
|
|||||||
@@ -308,6 +308,56 @@ return dm2.dv.extend({
|
|||||||
}, E('div', btns));
|
}, E('div', btns));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
buildPortLinks(ports) {
|
||||||
|
// cont.Ports[] from GET /containers/json — flat array.
|
||||||
|
// Published ports have {IP, PrivatePort, PublicPort, Type}.
|
||||||
|
// Exposed-only ports omit IP and PublicPort: {PrivatePort, Type}.
|
||||||
|
if (!Array.isArray(ports) || ports.length === 0) return '';
|
||||||
|
|
||||||
|
const LOCAL_IPS = new Set(['0.0.0.0', '::']);
|
||||||
|
|
||||||
|
// Sort: published (has PublicPort) before exposed-only, then by PrivatePort
|
||||||
|
const sorted = [...ports].sort((a, b) => {
|
||||||
|
const aHasPub = a.PublicPort ? 1 : 0;
|
||||||
|
const bHasPub = b.PublicPort ? 1 : 0;
|
||||||
|
if (aHasPub !== bHasPub) return bHasPub - aHasPub;
|
||||||
|
return (a.PrivatePort || 0) - (b.PrivatePort || 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const lines = sorted.map(p => {
|
||||||
|
const ip = p.IP || '';
|
||||||
|
const pub = p.PublicPort || '';
|
||||||
|
const priv = p.PrivatePort || '';
|
||||||
|
const type = p.Type || '';
|
||||||
|
|
||||||
|
const isIPv6 = ip.includes(':');
|
||||||
|
const isLocal = LOCAL_IPS.has(ip);
|
||||||
|
const displayIp = isIPv6 ? `[${ip}]` : ip;
|
||||||
|
|
||||||
|
let label;
|
||||||
|
if (pub && ip) label = `${displayIp}:${pub}->${priv}/${type}`;
|
||||||
|
else if (pub) label = `${pub}->${priv}/${type}`;
|
||||||
|
else label = `${priv}/${type}`;
|
||||||
|
|
||||||
|
// Clickable link for published TCP ports only
|
||||||
|
if (type === 'tcp' && pub) {
|
||||||
|
const host = isLocal ? window.location.hostname : displayIp;
|
||||||
|
return E('div', {}, [
|
||||||
|
E('a', {
|
||||||
|
href: `http://${host}:${pub}`,
|
||||||
|
target: '_blank',
|
||||||
|
rel: 'noopener noreferrer',
|
||||||
|
title: _('Open in browser'),
|
||||||
|
}, [label]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return E('div', {}, [label]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return E('div', {}, lines);
|
||||||
|
},
|
||||||
|
|
||||||
handleSave: null,
|
handleSave: null,
|
||||||
handleSaveApply: null,
|
handleSaveApply: null,
|
||||||
handleReset: null,
|
handleReset: null,
|
||||||
@@ -342,16 +392,7 @@ return dm2.dv.extend({
|
|||||||
_shortId: (cont?.Id || '').substring(0, 12),
|
_shortId: (cont?.Id || '').substring(0, 12),
|
||||||
Networks: this.parseNetworkLinksForContainer(network_list, cont?.NetworkSettings?.Networks || {}, true),
|
Networks: this.parseNetworkLinksForContainer(network_list, cont?.NetworkSettings?.Networks || {}, true),
|
||||||
Created: this.buildTimeString(cont?.Created) || '',
|
Created: this.buildTimeString(cont?.Created) || '',
|
||||||
Ports: (Array.isArray(cont.Ports) && cont.Ports.length > 0)
|
Ports: this.buildPortLinks(cont.Ports),
|
||||||
? cont.Ports.map(p => {
|
|
||||||
// const ip = p.IP || '';
|
|
||||||
const pub = p.PublicPort || '';
|
|
||||||
const priv = p.PrivatePort || '';
|
|
||||||
const type = p.Type || '';
|
|
||||||
return `${pub ? pub + ':' : ''}${priv}/${type}`;
|
|
||||||
// return `${ip ? ip + ':' : ''}${pub} -> ${priv} (${type})`;
|
|
||||||
}).join('<br/>')
|
|
||||||
: '',
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user