KAOS/code/web/templates/console.html
djuka b3645beea0 T22: Prijava — dva moda (klijent forma + operater chat sa Claude API)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 13:38:05 +00:00

180 lines
5.6 KiB
HTML

{{define "console"}}
<!DOCTYPE html>
<html lang="sr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>KAOS — Konzola</title>
<link rel="stylesheet" href="/static/style.css">
<script src="/static/htmx.min.js"></script>
</head>
<body>
<div class="header">
<h1>🔧 KAOS Dashboard</h1>
<div class="header-right">
<nav class="nav">
<a href="/" class="btn">Kanban</a>
<a href="/docs" class="btn">Dokumenti</a>
<a href="/console" class="btn btn-active">Konzola</a>
<a href="/submit" class="btn">Prijava</a>
</nav>
</div>
</div>
<div class="console-container">
<div class="console-toolbar">
<button class="btn" id="toggle-panel" onclick="togglePanel2()">+ Sesija 2</button>
</div>
<div class="console-panels">
<div class="console-panel" id="panel-1">
<div class="console-panel-header">
<span>🔧 Sesija 1</span>
<span class="session-status" id="status-1">idle</span>
<button class="btn btn-kill" id="kill-1" onclick="killSession(1)" style="display:none">Prekini</button>
</div>
<div class="console-output" id="output-1"></div>
<div class="console-input-row">
<input type="text" id="input-1" class="console-input" placeholder="Komanda..." onkeydown="handleKey(event, 1)" autocomplete="off">
<button class="btn btn-move" onclick="sendCommand(1)"></button>
</div>
</div>
<div class="console-panel" id="panel-2" style="display:none">
<div class="console-panel-header">
<span>🔧 Sesija 2</span>
<span class="session-status" id="status-2">idle</span>
<button class="btn btn-kill" id="kill-2" onclick="killSession(2)" style="display:none">Prekini</button>
</div>
<div class="console-output" id="output-2"></div>
<div class="console-input-row">
<input type="text" id="input-2" class="console-input" placeholder="Komanda..." onkeydown="handleKey(event, 2)" autocomplete="off">
<button class="btn btn-move" onclick="sendCommand(2)"></button>
</div>
</div>
</div>
</div>
<script>
var historyIdx = [0, 0];
var cmdHistory = [[], []];
function handleKey(e, session) {
if (e.key === 'Enter') {
sendCommand(session);
} else if (e.key === 'ArrowUp') {
e.preventDefault();
var idx = session - 1;
if (historyIdx[idx] > 0) {
historyIdx[idx]--;
document.getElementById('input-' + session).value = cmdHistory[idx][historyIdx[idx]] || '';
}
} else if (e.key === 'ArrowDown') {
e.preventDefault();
var idx = session - 1;
if (historyIdx[idx] < cmdHistory[idx].length) {
historyIdx[idx]++;
document.getElementById('input-' + session).value = cmdHistory[idx][historyIdx[idx]] || '';
}
}
}
function sendCommand(session) {
var input = document.getElementById('input-' + session);
var cmd = input.value.trim();
if (!cmd) return;
var idx = session - 1;
cmdHistory[idx].push(cmd);
historyIdx[idx] = cmdHistory[idx].length;
var output = document.getElementById('output-' + session);
output.innerHTML += '<div class="console-cmd">&gt; ' + escapeHtml(cmd) + '</div>';
input.value = '';
setSessionUI(session, 'running');
fetch('/console/exec', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({cmd: cmd, session: session})
})
.then(function(resp) {
if (!resp.ok) {
return resp.json().then(function(data) {
output.innerHTML += '<div class="console-error">' + escapeHtml(data.error) + '</div>';
setSessionUI(session, 'idle');
throw new Error(data.error);
});
}
return resp.json();
})
.then(function(data) {
if (!data) return;
streamOutput(session, data.exec_id);
})
.catch(function(err) {
setSessionUI(session, 'idle');
});
}
function streamOutput(session, execId) {
var output = document.getElementById('output-' + session);
var source = new EventSource('/console/stream/' + execId);
source.onmessage = function(e) {
output.innerHTML += '<div class="console-line">' + escapeHtml(e.data) + '</div>';
output.scrollTop = output.scrollHeight;
};
source.addEventListener('done', function(e) {
source.close();
output.innerHTML += '<div class="console-done">--- gotovo ---</div>';
output.scrollTop = output.scrollHeight;
setSessionUI(session, 'idle');
});
source.onerror = function() {
source.close();
setSessionUI(session, 'idle');
};
}
function killSession(session) {
fetch('/console/kill/' + session, {method: 'POST'})
.then(function() {
var output = document.getElementById('output-' + session);
output.innerHTML += '<div class="console-error">--- prekinuto ---</div>';
setSessionUI(session, 'idle');
});
}
function setSessionUI(session, status) {
document.getElementById('status-' + session).textContent = status;
document.getElementById('status-' + session).className = 'session-status session-' + status;
document.getElementById('kill-' + session).style.display = status === 'running' ? 'inline-block' : 'none';
document.getElementById('input-' + session).disabled = status === 'running';
}
function togglePanel2() {
var panel = document.getElementById('panel-2');
var btn = document.getElementById('toggle-panel');
if (panel.style.display === 'none') {
panel.style.display = 'flex';
btn.textContent = '- Sesija 2';
} else {
panel.style.display = 'none';
btn.textContent = '+ Sesija 2';
}
}
function escapeHtml(text) {
var div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
</script>
</body>
</html>
{{end}}