connectiopn fix round 2 4

This commit is contained in:
2026-08-21 23:14:19 +02:00
parent 763be3e7bf
commit 8ddb3ae589
3 changed files with 58 additions and 3 deletions

View File

@ -1414,6 +1414,11 @@
}
document.getElementById("watch-close-btn").addEventListener("click", closeWatchOverlay);
// Klick auf den abgedunkelten Hintergrund (nicht auf das Panel selbst)
// schliesst die Live-Ansicht ebenfalls.
document.getElementById("watch-overlay").addEventListener("click", (ev) => {
if (ev.target === ev.currentTarget) closeWatchOverlay();
});
function watchSession(session) {
closeWatchOverlay();
@ -1517,6 +1522,11 @@
}
document.getElementById("rec-close-btn").addEventListener("click", closeRecordingOverlay);
// Klick auf den abgedunkelten Hintergrund (nicht auf das Panel selbst)
// schliesst die Wiedergabe ebenfalls.
document.getElementById("rec-overlay").addEventListener("click", (ev) => {
if (ev.target === ev.currentTarget) closeRecordingOverlay();
});
function createSshPlayer(entries) {
const outputEntries = entries.filter((e) => e.dir === "output");

View File

@ -109,6 +109,8 @@
});
document.getElementById("exit-btn").addEventListener("click", () => {
statusEl.textContent = "Sitzung wird beendet ...";
statusEl.classList.remove("error");
try { client.disconnect(); } catch (_) { /* bereits getrennt */ }
window.close();
// Siehe terminal.js fuer die ausfuehrliche Begruendung: window.close()

View File

@ -33,8 +33,24 @@
function b64encode(str) {
return btoa(unescape(encodeURIComponent(str)));
}
function b64decode(b64) {
return decodeURIComponent(escape(atob(b64)));
// Bugfix: NICHT ueber decodeURIComponent(escape(atob(...))) als JS-String
// dekodieren. Jedes "output"-Frame entspricht genau einem Chunk aus
// process.stdout.read() auf dem Server (app/ssh_proxy/terminal_ws.py) --
// ein Mehrbyte-UTF-8-Zeichen (Umlaute, Box-Drawing-Zeichen, Emoji in
// Banner/Prompt/htop etc.) kann dabei GENAU AN DER CHUNK-GRENZE
// auseinandergerissen werden. decodeURIComponent() wirft dann einen
// "URI malformed"-Fehler fuer diesen einen Chunk (siehe
// static/js/admin.js::createSshPlayer fuer die noch schwerwiegendere
// Auswirkung bei der Wiedergabe -- dort blieb die gesamte Wiedergabe an
// genau dieser Stelle haengen). xterm.js' term.write() nimmt daher direkt
// die rohen Bytes als Uint8Array entgegen -- xterm.js ist ein echter
// Terminal-Emulator mit eigenem, chunk-uebergreifend korrektem
// UTF-8-Parser, genau fuer diesen Fall gebaut.
function b64decodeBytes(b64) {
const bin = atob(b64);
const bytes = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
return bytes;
}
// Troubleshooting: der Server liefert bei einem Fehlschlag entweder eine
@ -76,7 +92,7 @@
ws.addEventListener("message", (ev) => {
const msg = JSON.parse(ev.data);
if (msg.type === "output") {
term.write(b64decode(msg.data));
term.write(b64decodeBytes(msg.data));
} else if (msg.type === "error") {
lastErrorMessage = msg.message;
statusEl.textContent = "Fehler: " + msg.message;
@ -107,6 +123,28 @@
});
document.addEventListener("fullscreenchange", sendResize);
document.getElementById("exit-btn").addEventListener("click", () => {
// Sofortiges sichtbares Feedback, damit erkennbar ist, dass der Klick
// ueberhaupt ankam -- unabhaengig davon, ob window.close() gleich
// klappt oder der Fallback (siehe unten) erst nach der Wartezeit greift.
statusEl.textContent = "Sitzung wird beendet ...";
statusEl.classList.remove("error");
try {
if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
ws.close(1000, "Sitzung durch Benutzer beendet");
}
} catch (_) { /* bereits getrennt */ }
window.close();
// window.close() schliesst den Tab nur, wenn er per Skript/Link mit
// target="_blank" geoeffnet wurde (siehe dashboard.js) UND noch keine
// weitere Navigation darin stattfand -- sonst verweigern Browser das
// lautlos, ohne Fehler oder Rueckgabewert. Deshalb IMMER zusaetzlich
// nach kurzer Wartezeit zum Dashboard weiterleiten: war das Schliessen
// erfolgreich, existiert die Seite dann laengst nicht mehr und der
// Timeout laeuft ins Leere; sonst bleibt so ein Weg zurueck.
window.setTimeout(() => { window.location.href = "/dashboard"; }, 300);
});
// --- Dateitransfer-Panel ------------------------------------------------
const ftOverlay = document.getElementById("ft-overlay");
@ -123,6 +161,11 @@
}
document.getElementById("filetransfer-btn").addEventListener("click", openFt);
document.getElementById("ft-close-btn").addEventListener("click", closeFt);
// Klick auf den abgedunkelten Hintergrund (nicht auf das Panel selbst)
// schliesst das Overlay ebenfalls -- Standardverhalten fuer solche Panels.
ftOverlay.addEventListener("click", (ev) => {
if (ev.target === ftOverlay) closeFt();
});
function formatSize(bytes) {
if (bytes < 1024) return `${bytes} B`;