Add Portainer-style container bulk actions and network manager.
Release rolling / release (push) Successful in 8m41s

Always show a containers action bar (start/stop/restart/pause/resume/kill/
recreate/remove/prune) driven by row selection via typed bulk RPC. Rebuild
the container Networking tab into a join/leave network manager with aliases
and optional static IPs, plus a clearer ports table.
This commit is contained in:
Raven Scott
2026-07-13 18:22:19 -04:00
parent 4879b7ca18
commit 5c16254ff4
5 changed files with 827 additions and 485 deletions
+50 -5
View File
@@ -87,15 +87,60 @@ export function registerNetworkHandlers(session) {
})
session.respond('connectNetwork', async (args) => {
await docker.getNetwork(args.networkId).connect({ Container: args.containerId })
return { success: true, message: 'Container connected to network' }
const networkId = args.networkId || args.id || args.network
const containerId = args.containerId || args.container
if (!networkId || !containerId) {
throw Object.assign(new Error('networkId and containerId required'), {
code: 'INVALID_ARGS',
})
}
/** @type {Record<string, unknown>} */
const endpointConfig = {}
if (Array.isArray(args.aliases) && args.aliases.length) {
endpointConfig.Aliases = args.aliases
.map((a) => String(a || '').trim())
.filter(Boolean)
}
const ipv4 = args.ipv4Address || args.IPv4Address
const ipv6 = args.ipv6Address || args.IPv6Address
if (ipv4 || ipv6) {
endpointConfig.IPAMConfig = {}
if (ipv4) endpointConfig.IPAMConfig.IPv4Address = String(ipv4).trim()
if (ipv6) endpointConfig.IPAMConfig.IPv6Address = String(ipv6).trim()
}
const connectOpts = { Container: containerId }
if (Object.keys(endpointConfig).length) {
connectOpts.EndpointConfig = endpointConfig
}
await docker.getNetwork(networkId).connect(connectOpts)
return {
success: true,
message: 'Container connected to network',
networkId,
containerId,
}
})
session.respond('disconnectNetwork', async (args) => {
const networkId = args.networkId || args.id || args.network
const containerId = args.containerId || args.container
if (!networkId || !containerId) {
throw Object.assign(new Error('networkId and containerId required'), {
code: 'INVALID_ARGS',
})
}
await docker
.getNetwork(args.networkId)
.disconnect({ Container: args.containerId, Force: args.force || false })
return { success: true, message: 'Container disconnected from network' }
.getNetwork(networkId)
.disconnect({ Container: containerId, Force: args.force || false })
return {
success: true,
message: 'Container disconnected from network',
networkId,
containerId,
}
})
session.respond('pruneNetworks', async (args) => {