function getCsrfToken() { return document.querySelector('meta[name="csrf-token"]')?.content || ''; } const terminalInput = document.getElementById('terminalInput'); const terminalOutput = document.getElementById('terminalOutput'); const connectionStatus = document.getElementById('connectionStatus'); terminalInput.addEventListener('keydown', function(e) { if (e.key === 'Enter') { executeCommand(); } }); function executeCommand() { const command = terminalInput.value.trim(); if (!command) return; appendTerminalLine(command, 'command'); terminalInput.value = ''; terminalInput.disabled = true; document.getElementById('executeBtn').disabled = true; updateStatus('executing', 'Executing...'); fetch('/terminal/' + serverId + '/execute', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRF-Token': getCsrfToken(), }, body: 'command=' + encodeURIComponent(command) + '&_csrf_token=' + encodeURIComponent(getCsrfToken()), }) .then(r => r.json()) .then(data => { terminalInput.disabled = false; document.getElementById('executeBtn').disabled = false; terminalInput.focus(); if (data.success) { if (data.output) { appendTerminalLine(data.output, 'output'); } if (data.stderr) { appendTerminalLine(data.stderr, 'error'); } updateStatus('connected', 'Connected'); } else { appendTerminalLine(data.message || 'Command failed', 'error'); updateStatus('error', 'Error'); } const terminalBody = document.getElementById('terminalOutput'); terminalBody.scrollTop = terminalBody.scrollHeight; }) .catch(err => { terminalInput.disabled = false; document.getElementById('executeBtn').disabled = false; appendTerminalLine('Connection error: ' + err.message, 'error'); updateStatus('error', 'Error'); }); } function appendTerminalLine(text, type) { const line = document.createElement('div'); line.className = 'terminal-line terminal-' + type; if (type === 'command') { line.innerHTML = '$ ' + escapeHtml(text); } else { line.innerHTML = '
' + escapeHtml(text) + '
'; } terminalOutput.appendChild(line); terminalOutput.scrollTop = terminalOutput.scrollHeight; } function runQuickCmd(cmd) { terminalInput.value = cmd; executeCommand(); } function clearTerminal() { terminalOutput.innerHTML = ''; } function clearHistory() { if (!confirm('Clear all command history for this server?')) return; fetch('/terminal/' + serverId + '/clear-history', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRF-Token': getCsrfToken(), }, body: '_csrf_token=' + encodeURIComponent(getCsrfToken()), }) .then(r => r.json()) .then(data => { showToast(data.success ? 'success' : 'error', data.message); if (data.success) location.reload(); }); } function updateStatus(status, text) { const dot = connectionStatus.querySelector('.status-dot'); dot.className = 'status-dot ' + status; connectionStatus.lastChild.textContent = ' ' + text; } terminalInput.focus();