web-app-demos/apps/reporter/templates/admin.html
2025-03-17 16:11:01 -06:00

158 lines
No EOL
4.4 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title}</title>
<link rel="stylesheet" type="text/css" href="/static/bootstrap/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/static/bootstrap/bootstrap-icons.min.css">
<link rel="stylesheet" type="text/css" href="./static/css/style.css">
<link rel="shortcut icon" type="image/png" href="./static/favicon.png">
<link rel="shortcut icon" sizes="192x192" href="./static/favicon.png">
<link rel="apple-touch-icon" href="./static/favicon.png">
<style type="text/css">
#output {
height: 20em;
resize: vertical;
font-family: monospace;
}
#command {
font-family: monospace;
}
.status-ok {
color: var(--bs-success-text-emphasis);
}
.status-error {
color: var(--bs-danger-text-emphasis);
}
</style>
</head>
<body>
<div id="wrapper" class="d-flex flex-column vh-100">
${menu}
<div class="container flex-grow-1 min-height-0 z-0">
<div class="row h-100">
<div class="p-3 mx-auto">
<select class="form-select mb-3" id="commandlist">
<option value="" disabled selected>Commands</option>
<option value="status">Status</option>
<option value="shutdown">Shut down</option>
</select>
<div id="output" class="w-100 border overflow-y-auto p-2 mb-3"></div>
<form method="post" action="/reporter/admin/api" id="commandform" class="mb-3" autocomplete="off">
<div class="input-group">
<input type="text" class="form-control" id="command" name="command">
<button type="submit" class="btn btn-primary"><i class="bi bi-send"></i></button>
</div>
</form>
</div>
</div>
</div>
</div>
<script src="/static/bootstrap/bootstrap.bundle.min.js"></script>
<script type="text/javascript">
const el = (id) => document.getElementById(id);
let theme = "light";
const form = el('commandform');
const output = el('output');
const commandEl = el('command');
const commandList = el('commandlist');
const html = document.documentElement;
let history = [];
let cursor = null;
let buffer = "";
const sendCommand = async () => {
const command = commandEl.value;
if (command == '') { return; }
if (command != history[0]) {
history.unshift(command);
}
output.innerHTML += `<pre class='mb-0'>&gt; ${command}</pre>`;
const formData = new FormData(form);
commandEl.value = '';
cursor = null;
buffer = "";
const words = command.split(' ');
if (words[0] == "history") {
output.innerHTML += `<pre class="status-ok">${history.toReversed().join('\n')}</pre>`;
}
else if (words[0] == "theme") {
const themes = ["dark", "light"];
if (words.length == 1) {
output.innerHTML += `<pre class="status-ok">Using ${theme} theme.</pre>`;
}
else if (themes.includes(words[1])) {
html.setAttribute("data-bs-theme", words[1]);
theme = words[1];
output.innerHTML += `<pre class="status-ok">Theme set to ${words[1]}</pre>`;
}
else {
output.innerHTML += `<pre class="status-error">Theme ${words[1]} unsupported. Available: ${themes.join(", ")}</pre>`;
}
}
else {
try {
const response = await fetch(form.action, {
method: "POST",
body: formData
});
result = await response.json();
output.innerHTML += `<pre class="status-${result.status}">${result.data}\n[${result.timestamp}]</pre>`;
} catch (e) {
console.error(e);
}
}
output.scrollTop = output.scrollHeight;
}
commandList.addEventListener("change", (event) => {
commandEl.value = commandList.value;
sendCommand();
commandList.options[0].selected = true;
});
form.addEventListener("submit", (event) => {
event.preventDefault();
sendCommand();
});
commandEl.addEventListener("keydown", (event) => {
if (event.keyCode == 38) { //up
event.preventDefault();
if (cursor == null && history.length > 0) {
cursor = 0;
buffer = commandEl.value;
commandEl.value = history[0];
}
else if (history.length > cursor+1) {
cursor++;
commandEl.value = history[cursor];
}
}
else if (event.keyCode == 40) { //down
event.preventDefault();
if (cursor == 0) {
cursor = null;
commandEl.value = buffer;
buffer = "";
}
else if (cursor > 0) {
cursor--;
commandEl.value = history[cursor];
}
}
});
commandEl.focus();
</script>
</body>
</html>