This commit is contained in:
Raven Scott
2025-11-24 22:55:02 -05:00
parent aa45d86efe
commit e6032533e9
2 changed files with 120 additions and 15 deletions
+41 -7
View File
@@ -527,6 +527,10 @@ function updateSystemInfo(systemInfo) {
// Update volumes store if volumes are present in systemInfo
if (systemInfo.volumes && Array.isArray(systemInfo.volumes)) {
volumesStore.set(systemInfo.volumes);
// If we're on the volumes view, refresh the display
if (currentView === 'volumes') {
renderVolumes(systemInfo.volumes);
}
}
const dockerInfoEl = document.getElementById('docker-info-content');
@@ -1047,11 +1051,24 @@ function setupDeployStackHandler() {
}
}
// Subscription for volumes store to auto-update UI
let volumesStoreSubscription = null;
function loadVolumes() {
if (!window.activePeer) {
return;
}
// Set up subscription to auto-update UI when volumes change
if (!volumesStoreSubscription) {
volumesStoreSubscription = volumesStore.subscribe((volumes) => {
// Only auto-update if we're on the volumes view
if (currentView === 'volumes') {
renderVolumes(volumes);
}
});
}
// Check cache first - if fresh, use it; otherwise load from server
if (!volumesStore.isStale() && volumesStore.get().length > 0) {
renderVolumes(volumesStore.get());
@@ -1103,7 +1120,8 @@ function renderVolumes(volumes) {
const volumeName = btn.dataset.volumeName;
showConfirmModal('Are you sure you want to remove this volume? This cannot be undone.', () => {
sendCommand('removeVolume', { name: volumeName });
setTimeout(() => loadVolumes(), 1000);
// The server will broadcast the updated volumes list, which will trigger the subscription
// But we can also proactively refresh if needed
});
});
});
@@ -3805,11 +3823,21 @@ function handlePeerData(data, topicId, peer) {
case 'volumes':
console.log('[INFO] Handling volumes list...');
// Store in cache and render
let volumesToRender = null;
if (response.data && Array.isArray(response.data)) {
renderVolumes(response.data);
volumesToRender = response.data;
} else if (response.volumes && Array.isArray(response.volumes)) {
// Fallback for old format
renderVolumes(response.volumes);
volumesToRender = response.volumes;
}
if (volumesToRender !== null) {
// Update store (this will trigger subscriptions)
volumesStore.set(volumesToRender);
// Render if on volumes view
if (currentView === 'volumes') {
renderVolumes(volumesToRender);
}
}
break;
@@ -3902,17 +3930,23 @@ function handlePeerData(data, topicId, peer) {
// Handle volumes responses - update cache and route to handlers if needed
// Check for volumes in response (both new format with type and old format)
// Note: This is a fallback for responses that weren't handled in the switch statement above
// The 'volumes' case in the switch should have already handled type: 'volumes' responses
let volumesArray = null;
if (response && response.type === 'volumes' && Array.isArray(response.data)) {
volumesArray = response.data;
} else if (response && response.success === true && Array.isArray(response.volumes)) {
if (response && response.type !== 'volumes' && response.success === true && Array.isArray(response.volumes)) {
// Old format volumes response that wasn't caught by switch
volumesArray = response.volumes;
}
if (volumesArray !== null) {
// Always update the cache first
// Always update the cache first (this will trigger subscriptions)
volumesStore.set(volumesArray);
// Render if on volumes view
if (currentView === 'volumes') {
renderVolumes(volumesArray);
}
// Route to active volume selectors if they exist (for deploy modal)
if (window.activeVolumeHandlers && window.activeVolumeHandlers.size > 0) {
for (const [volumeId, handlerInfo] of window.activeVolumeHandlers.entries()) {
+79 -8
View File
@@ -1170,6 +1170,28 @@ swarm.on('connection', (peer) => {
const volume = await docker.createVolume(volumeConfig);
response = { success: true, message: `Volume "${args.name}" created successfully`, data: volume.name };
// Broadcast updated volumes list to all peers
try {
const volumesResult = await docker.listVolumes();
const volumesList = volumesResult.Volumes || [];
const update = {
type: 'volumes',
data: volumesList,
success: true,
volumes: volumesList
};
for (const connectedPeer of connectedPeers) {
try {
connectedPeer.write(JSON.stringify(update));
} catch (peerErr) {
console.error(`[ERROR] Failed to send volume update to peer: ${peerErr.message}`);
}
}
} catch (volErr) {
console.warn(`[WARN] Failed to broadcast volume update: ${volErr.message}`);
}
} catch (error) {
console.error(`[ERROR] Failed to create volume: ${error.message}`);
response = { error: `Failed to create volume: ${error.message}` };
@@ -1182,6 +1204,28 @@ swarm.on('connection', (peer) => {
const volume = docker.getVolume(parsedData.args.name);
await volume.remove();
response = { success: true, message: `Volume ${parsedData.args.name} removed` };
// Broadcast updated volumes list to all peers
try {
const volumesResult = await docker.listVolumes();
const volumesList = volumesResult.Volumes || [];
const update = {
type: 'volumes',
data: volumesList,
success: true,
volumes: volumesList
};
for (const connectedPeer of connectedPeers) {
try {
connectedPeer.write(JSON.stringify(update));
} catch (peerErr) {
console.error(`[ERROR] Failed to send volume update to peer: ${peerErr.message}`);
}
}
} catch (volErr) {
console.warn(`[WARN] Failed to broadcast volume update: ${volErr.message}`);
}
} catch (error) {
console.error(`[ERROR] Failed to remove volume: ${error.message}`);
response = { error: `Failed to remove volume: ${error.message}` };
@@ -1527,17 +1571,44 @@ async function initializeDockerEventStream() {
try {
const event = JSON.parse(chunk.toString());
if (event.status === "undefined") return;
logger.info('Docker event received', { status: event.status, id: event.id });
logger.info('Docker event received', { status: event.status, id: event.id, type: event.Type });
// Get updated container list and broadcast it to all connected peers
const containers = await docker.listContainers({ all: true });
const update = { type: 'containers', data: containers };
// Handle container events
if (event.Type === 'container') {
// Get updated container list and broadcast it to all connected peers
const containers = await docker.listContainers({ all: true });
const update = { type: 'containers', data: containers };
for (const peer of connectedPeers) {
for (const peer of connectedPeers) {
try {
peer.write(JSON.stringify(update));
} catch (peerErr) {
logger.error('Failed to send update to peer', { error: peerErr.message });
}
}
}
// Handle volume events (create, destroy)
if (event.Type === 'volume' && (event.Action === 'create' || event.Action === 'destroy')) {
try {
peer.write(JSON.stringify(update));
} catch (peerErr) {
logger.error('Failed to send update to peer', { error: peerErr.message });
const volumesResult = await docker.listVolumes();
const volumesList = volumesResult.Volumes || [];
const update = {
type: 'volumes',
data: volumesList,
success: true,
volumes: volumesList
};
for (const peer of connectedPeers) {
try {
peer.write(JSON.stringify(update));
} catch (peerErr) {
logger.error('Failed to send volume update to peer', { error: peerErr.message });
}
}
} catch (volErr) {
logger.error('Failed to fetch volumes after event', { error: volErr.message });
}
}
} catch (err) {