This commit is contained in:
2026-08-27 08:57:14 +02:00
commit dca69c04ad
9 changed files with 1392 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
const form = document.getElementById("command-form");
const nameInput = document.getElementById("name");
const commandInput = document.getElementById("command");
const list = document.getElementById("command-list");
const emptyNote = document.getElementById("empty-note");
const statusEl = document.getElementById("status");
const outputEl = document.getElementById("output");
function setStatus(message, kind) {
statusEl.textContent = message;
statusEl.className = "status" + (kind ? ` ${kind}` : "");
}
function showOutput(text) {
outputEl.hidden = !text;
outputEl.textContent = text || "";
}
function formatTerminal(command, output) {
const lines = [];
if (command) lines.push(`$ ${command}`);
if (output) lines.push(output);
return lines.join("\n");
}
async function api(url, options) {
const res = await fetch(url, options);
const data = await res.json().catch(() => ({}));
if (!res.ok) {
const err = new Error(data.error || `Fehler ${res.status}`);
err.data = data;
throw err;
}
return data;
}
function renderCommands(commands) {
list.replaceChildren();
emptyNote.hidden = commands.length > 0;
for (const cmd of commands) {
const li = document.createElement("li");
const info = document.createElement("div");
info.className = "info";
const name = document.createElement("span");
name.className = "name";
name.textContent = cmd.name;
const code = document.createElement("code");
code.textContent = cmd.command;
info.append(name, code);
const actions = document.createElement("div");
actions.className = "actions";
const runBtn = document.createElement("button");
runBtn.type = "button";
runBtn.textContent = "Ausführen";
runBtn.addEventListener("click", () => runCommand(cmd, runBtn));
const delBtn = document.createElement("button");
delBtn.type = "button";
delBtn.className = "delete";
delBtn.textContent = "Löschen";
delBtn.addEventListener("click", () => deleteCommand(cmd, delBtn));
actions.append(runBtn, delBtn);
li.append(info, actions);
list.append(li);
}
}
async function loadCommands() {
try {
renderCommands(await api("/api/commands"));
} catch (err) {
setStatus(`Befehle konnten nicht geladen werden: ${err.message}`, "error");
}
}
async function runCommand(cmd, button) {
button.disabled = true;
setStatus(`${cmd.name}" wird gesendet …`);
showOutput("");
try {
const result = await api(`/api/commands/${cmd.id}/run`, { method: "POST" });
setStatus(
result.ok
? `${cmd.name}" wurde gesendet.`
: `cec-client hat sich mit Exit-Code ${result.exitCode} beendet.`,
result.ok ? "ok" : "error"
);
showOutput(formatTerminal(result.command, result.output));
} catch (err) {
setStatus(`Ausführen fehlgeschlagen: ${err.message}`, "error");
showOutput(formatTerminal(err.data?.command, err.data?.output));
} finally {
button.disabled = false;
}
}
async function deleteCommand(cmd, button) {
button.disabled = true;
try {
await api(`/api/commands/${cmd.id}`, { method: "DELETE" });
setStatus(`${cmd.name}" wurde gelöscht.`, "ok");
await loadCommands();
} catch (err) {
setStatus(`Löschen fehlgeschlagen: ${err.message}`, "error");
button.disabled = false;
}
}
form.addEventListener("submit", async (event) => {
event.preventDefault();
const submitBtn = form.querySelector("button[type=submit]");
submitBtn.disabled = true;
try {
await api("/api/commands", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: nameInput.value.trim(),
command: commandInput.value.trim(),
}),
});
setStatus(`${nameInput.value.trim()}" wurde gespeichert.`, "ok");
form.reset();
nameInput.focus();
await loadCommands();
} catch (err) {
setStatus(`Speichern fehlgeschlagen: ${err.message}`, "error");
} finally {
submitBtn.disabled = false;
}
});
loadCommands();