Files
appServerPortalUI/public/app.js
2026-06-12 19:12:46 +02:00

221 lines
6.8 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ==== FRONTEND app.js ====
// Service-Liste
const services = [
{ id: "abc", name: "Control GamePad", url: "https://tccontrol.server.schooltech.ch/" },
{ id: "xyz", name: "Guacamole", url: "https://rp5guac.server.schooltech.ch/" },
{ id: "sim", name: "Simulation", url: "https://tcSimulation.server.schooltech.ch/" },
{ id: "video", name: "Video", url: "https://robotVideo.server.schooltech.ch/" },
{ id: "homing", name: "Homing", url:"https://robotHoming.server.schooltech.ch/"},
{ id: "base", name:"RobotBase", url:"https://robotBase.server.schooltech.ch/"},
{ id: "ellbow", name:"RobotEllbow", url:"https://robotEllbow.server.schooltech.ch/"},
{ id: "hand", name:"RobotHand", url:"https://robotHand.server.schooltech.ch/"},
{ id: "driver", name:"RobotDriver", url:"https://robotdriver.server.schooltech.ch/"},
{ id: "code", name:"VSCode", url:"https://robotVSCode.server.schooltech.ch/"}
];
// DOM-Elemente
const iframe = document.getElementById("service-frame");
const loginModal = document.getElementById("login-modal");
const loginBtn = document.getElementById("login-btn");
const loginSubmit = document.getElementById("login-submit");
const loginMsg = document.getElementById("login-msg");
const nav = document.getElementById("services");
const estopBtn = document.getElementById("emergency-stop");
const usernameInput = document.getElementById("username");
const passwordInput = document.getElementById("password");
let loggedIn = false;
let armedPollInterval = null;
// ===========================
// Login anzeigen
// ===========================
function switchToLogin() {
loginBtn.textContent = "Login";
loginBtn.onclick = () => {
loginModal.style.display = "block";
};
}
// ===========================
// Logout anzeigen
// ===========================
function switchToLogout() {
loginBtn.textContent = "Logout";
loginBtn.onclick = async () => {
try {
await fetch("/api/logout", { method: "POST" });
} catch (e) {
console.warn("Logout request failed:", e);
}
performLocalLogout();
};
}
// ===========================
// Lokales Logout
// ===========================
function performLocalLogout() {
loggedIn = false;
stopArmedPolling();
estopBtn.style.display = "none";
iframe.src = "";
iframe.style.display = "none";
nav.innerHTML = "";
loginModal.style.display = "block";
switchToLogin();
}
// ===========================
// Armed-Status prüfen
// ===========================
const POWER_STATUS_URL = '/api/power-status';
const ESTOP_URL = '/api/emergency-stop';
async function updateArmedStatus() {
console.log('[armed-check] GET', POWER_STATUS_URL);
try {
const r = await fetch(POWER_STATUS_URL);
if (r.ok) {
const data = await r.json();
console.log('[armed-check] response:', data);
estopBtn.style.display = data.armed ? "block" : "none";
} else {
console.warn('[armed-check] HTTP', r.status, ' Button versteckt');
estopBtn.style.display = "none";
}
} catch (e) {
console.error('[armed-check] Fehler bei', POWER_STATUS_URL, '', e.message);
estopBtn.style.display = "none";
}
}
function startArmedPolling() {
updateArmedStatus();
armedPollInterval = setInterval(updateArmedStatus, 5000);
}
function stopArmedPolling() {
if (armedPollInterval) {
clearInterval(armedPollInterval);
armedPollInterval = null;
}
}
// ===========================
// Emergency Stop
// ===========================
estopBtn.addEventListener("click", async () => {
console.log('[estop] POST', ESTOP_URL);
try {
const r = await fetch(ESTOP_URL, { method: 'POST' });
console.log('[estop] response HTTP', r.status);
} catch (e) {
console.error('[estop] Fehler bei', ESTOP_URL, '', e.message);
}
});
// ===========================
// Login-Logik
// ===========================
async function doLogin() {
const user = usernameInput.value;
const pass = passwordInput.value;
try {
const res = await fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ user, pass })
});
if (res.ok) {
loggedIn = true;
loginModal.style.display = "none";
loginMsg.textContent = "";
setupServiceButtons();
switchToLogout();
startArmedPolling();
} else {
loginMsg.textContent = "Login fehlgeschlagen";
}
} catch (e) {
loginMsg.textContent = "Fehler: " + e.message;
}
}
loginSubmit.onclick = doLogin;
// Enter-Taste Login
[usernameInput, passwordInput].forEach(input => {
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
doLogin();
}
});
});
// ===========================
// Buttons erzeugen
// ===========================
function setupServiceButtons() {
nav.innerHTML = "";
services.forEach(svc => {
console.log("Service " + svc.name + " wird als Button angefuegt");
const btn = document.createElement("button");
btn.textContent = svc.name;
btn.onclick = async () => {
try {
await fetch('/api/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event: 'open',
service: svc.id,
url: svc.url
})
});
} catch(e) {
console.error('Event log failed', e);
}
document.querySelectorAll("nav button").forEach(b => b.classList.remove("active"));
btn.classList.add("active");
openService(svc);
};
nav.appendChild(btn);
});
}
// ===========================
// Service öffnen
// ===========================
function openService(svc) {
iframe.src = svc.url;
iframe.style.display = "block";
window.scrollTo(0,0);
}
// ===========================
// Session Status beim Laden prüfen
// ===========================
(async function checkStatus() {
try {
const r = await fetch('/api/status');
if (r.ok) {
loggedIn = true;
setupServiceButtons();
switchToLogout();
startArmedPolling();
} else {
switchToLogin();
}
} catch (e) {
switchToLogin();
}
})();