diff --git a/app.js b/app.js index a613204..94b118f 100644 --- a/app.js +++ b/app.js @@ -17,6 +17,7 @@ const duplicateContainerForm = document.getElementById('duplicate-container-form // Global variables const connections = {}; +window.openTerminals = {}; let activePeer = null; window.activePeer = null; // Expose to other modules @@ -130,7 +131,6 @@ function addConnection(topicHex) { peer.on('close', () => { console.log(`[INFO] Disconnected from peer for topic: ${topicHex}`); updateConnectionStatus(topicId, false); - connections[topicId].peer = null; // Clear the peer reference if (window.activePeer === peer) { window.activePeer = null; @@ -154,6 +154,26 @@ function addConnection(topicHex) { return; } + // Close and kill any open terminals associated with this connection + if (window.openTerminals[topicId]) { + console.log(`[INFO] Closing terminals for topic: ${topicId}`); + window.openTerminals[topicId].forEach((containerId) => { + try { + cleanUpTerminal(containerId); // Use the terminal.js cleanup logic + } catch (err) { + console.error(`[ERROR] Failed to kill terminal for container ${containerId}: ${err.message}`); + } + }); + delete window.openTerminals[topicId]; + } + + // Hide the terminal modal if it is active + const terminalModal = document.getElementById('terminal-modal'); + if (terminalModal.style.display === 'flex') { + console.log(`[INFO] Hiding terminal modal for disconnected topic: ${topicId}`); + terminalModal.style.display = 'none'; + } + // Disconnect the peer and destroy the swarm if (connection.peer) { connection.peer.destroy(); @@ -173,11 +193,12 @@ function addConnection(topicHex) { console.log(`[INFO] Disconnected and removed connection: ${topicId}`); // Reset active peer if it was the disconnected connection + if (window.activePeer === connection.peer) { window.activePeer = null; connectionTitle.textContent = 'Choose a Connection'; // Reset title dashboard.classList.add('hidden'); containerList.innerHTML = ''; // Clear the container list - + } // Ensure the container list is cleared regardless of the active connection resetContainerList(); @@ -185,7 +206,6 @@ function addConnection(topicHex) { // Refresh the connections view resetConnectionsView(); } - // Function to reset the container list function resetContainerList() { containerList.innerHTML = ''; // Clear the existing list diff --git a/libs/terminal.js b/libs/terminal.js index cda4650..90cbc02 100644 --- a/libs/terminal.js +++ b/libs/terminal.js @@ -1,4 +1,3 @@ -// terminal.js import { Terminal } from 'xterm'; import { FitAddon } from 'xterm-addon-fit'; @@ -14,6 +13,11 @@ let activeContainerId = null; // Currently displayed containerId // Kill Terminal button functionality document.getElementById('kill-terminal-btn').onclick = () => { + killActiveTerminal(); +}; + +// Kill the active terminal session +function killActiveTerminal() { const containerId = activeContainerId; if (containerId && terminalSessions[containerId]) { @@ -23,19 +27,7 @@ document.getElementById('kill-terminal-btn').onclick = () => { window.sendCommand('killTerminal', { containerId }); // Clean up terminal session - const session = terminalSessions[containerId]; - session.xterm.dispose(); - session.onDataDisposable.dispose(); - if (session.resizeListener) { - window.removeEventListener('resize', session.resizeListener); - } - // Remove the terminal's container div from DOM - session.container.parentNode.removeChild(session.container); - - delete terminalSessions[containerId]; - - // Remove from tray if exists - removeFromTray(containerId); + cleanUpTerminal(containerId); // Hide the terminal modal if this was the active session if (activeContainerId === containerId) { @@ -45,7 +37,7 @@ document.getElementById('kill-terminal-btn').onclick = () => { } else { console.error('[ERROR] No terminal session found to kill.'); } -}; +} // Start terminal session function startTerminal(containerId, containerName) { @@ -55,10 +47,7 @@ function startTerminal(containerId, containerName) { } if (terminalSessions[containerId]) { - // Terminal session already exists console.log(`[INFO] Terminal session already exists for container: ${containerId}`); - - // If terminal is minimized or not active, switch to it if (activeContainerId !== containerId || terminalModal.style.display === 'none') { switchTerminal(containerId); } else { @@ -67,10 +56,8 @@ function startTerminal(containerId, containerName) { return; } - // Create new terminal session console.log(`[INFO] Creating new terminal session for container: ${containerId}`); - // Initialize new terminal session const xterm = new Terminal({ cursorBlink: true, theme: { background: '#000000', foreground: '#ffffff' }, @@ -78,21 +65,16 @@ function startTerminal(containerId, containerName) { const fitAddon = new FitAddon(); xterm.loadAddon(fitAddon); - // Create a container div for this terminal const terminalDiv = document.createElement('div'); terminalDiv.style.width = '100%'; terminalDiv.style.height = '100%'; terminalDiv.style.display = 'none'; // Initially hidden terminalContainer.appendChild(terminalDiv); - // Open the terminal in the container div xterm.open(terminalDiv); - // Set up event listener for terminal input using onData const onDataDisposable = xterm.onData((data) => { console.log(`[DEBUG] Sending terminal input for container ${containerId}: ${data}`); - - // Base64 encode the data window.activePeer.write( JSON.stringify({ type: 'terminalInput', @@ -103,7 +85,6 @@ function startTerminal(containerId, containerName) { ); }); - // Store the terminal session terminalSessions[containerId] = { xterm, fitAddon, @@ -114,13 +95,11 @@ function startTerminal(containerId, containerName) { container: terminalDiv, }; - // Send startTerminal command to server console.log(`[INFO] Starting terminal for container: ${containerId}`); window.activePeer.write( JSON.stringify({ command: 'startTerminal', args: { containerId } }) ); - // Switch to the requested terminal session switchTerminal(containerId); } @@ -132,39 +111,29 @@ function switchTerminal(containerId) { return; } - // Hide the current terminal if any if (activeContainerId && activeContainerId !== containerId) { const currentSession = terminalSessions[activeContainerId]; if (currentSession) { - // Remove resize listener for current session if (currentSession.resizeListener) { window.removeEventListener('resize', currentSession.resizeListener); currentSession.resizeListener = null; } - // Hide current terminal's container currentSession.container.style.display = 'none'; } } - // Show the terminal session.container.style.display = 'block'; + setTimeout(() => session.fitAddon.fit(), 10); - setTimeout(() => session.fitAddon.fit(), 10); // Ensure terminal fits properly after rendering - - // Update modal title terminalTitle.dataset.containerId = containerId; terminalTitle.textContent = `Container Terminal: ${session.name}`; - - // Show the terminal modal terminalModal.style.display = 'flex'; activeContainerId = containerId; - // Remove from tray if it exists removeFromTray(containerId); console.log(`[INFO] Switched to terminal for container: ${containerId}`); - // Adjust resize event listener if (session.resizeListener) { window.removeEventListener('resize', session.resizeListener); } @@ -187,7 +156,6 @@ function appendTerminalOutput(data, containerId, encoding) { outputData = data; } - // Write the decoded data to the terminal session.xterm.write(outputData); } @@ -199,5 +167,30 @@ function removeFromTray(containerId) { } } +// Clean up terminal session +function cleanUpTerminal(containerId) { + const session = terminalSessions[containerId]; + if (session) { + session.xterm.dispose(); + session.onDataDisposable.dispose(); + if (session.resizeListener) { + window.removeEventListener('resize', session.resizeListener); + } + session.container.parentNode.removeChild(session.container); + delete terminalSessions[containerId]; + console.log(`[INFO] Cleaned up terminal for container: ${containerId}`); + } else { + console.error(`[ERROR] No terminal session to clean up for container: ${containerId}`); + } +} + +// Clean up all terminals +function cleanUpAllTerminals() { + Object.keys(terminalSessions).forEach(cleanUpTerminal); + terminalModal.style.display = 'none'; + activeContainerId = null; + console.log('[INFO] All terminal sessions cleaned up.'); +} + // Expose functions to app.js -export { startTerminal, appendTerminalOutput }; \ No newline at end of file +export { startTerminal, appendTerminalOutput, cleanUpAllTerminals };