diff --git a/packages/tesm-core/pyproject.toml b/packages/tesm-core/pyproject.toml index d78849c..3d38d4c 100644 --- a/packages/tesm-core/pyproject.toml +++ b/packages/tesm-core/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "tesm-core" -version = "2.8.13" +version = "2.8.14" description = "Gemeinsames Anwendungsgeruest (Auth, RBAC, Navigation, Design-System, Migrationen) fuer TESM und TESM-Lizenzserver" requires-python = ">=3.11" dependencies = [ diff --git a/packages/tesm-core/src/tesm_core/static/tesm_core/css/components.css b/packages/tesm-core/src/tesm_core/static/tesm_core/css/components.css index 54933e8..e147079 100644 --- a/packages/tesm-core/src/tesm_core/static/tesm_core/css/components.css +++ b/packages/tesm-core/src/tesm_core/static/tesm_core/css/components.css @@ -1275,6 +1275,24 @@ color: var(--text-faint); } + /* Mitlesen auf der Wartungsseite: die Ausgabe eines laufenden Auftrags, + direkt unter seinem Geraet. Dunkler Grund wie in jeder Konsole -- was + dort steht, kommt von einer fremden Maschine und nicht aus dieser + Oberflaeche. */ + .job-output { + margin: 0; + max-height: 220px; + overflow: auto; + padding: var(--sp-3) var(--sp-4); + background: #101216; + color: #d7dbe0; + font-family: var(--font-mono); + font-size: var(--fs-xs); + line-height: 1.5; + white-space: pre-wrap; + word-break: break-word; + } + /* ---------------------------------------------------------------------- # Bildschirmsitzung (VNC) diff --git a/packages/tesm-core/src/tesm_core/static/tesm_core/js/screen.js b/packages/tesm-core/src/tesm_core/static/tesm_core/js/screen.js index 235bcff..c7ad9c3 100644 --- a/packages/tesm-core/src/tesm_core/static/tesm_core/js/screen.js +++ b/packages/tesm-core/src/tesm_core/static/tesm_core/js/screen.js @@ -88,6 +88,7 @@ const RA2NE = 6; //: einen Knopf brauchen. X11-Keysyms. const ALT_LINKS = 0xffe9; const F4 = 0xffc1; +const F5 = 0xffc2; const schema = window.location.protocol === "https:" ? "wss:" : "ws:"; @@ -97,7 +98,7 @@ const schema = window.location.protocol === "https:" ? "wss:" : "ws:"; * ``quelle`` ist die Adresse der JSON-Auskunft; alles Weitere steht dort. * Rueckgabe: eine Funktion, die die Sitzung wieder abbaut. */ -export function starteSitzung(wurzel, quelle) { +export function starteSitzung(wurzel, quelle, { beiEnde = null } = {}) { const teil = (rolle) => wurzel.querySelector(`[data-rolle="${rolle}"]`); const leinwand = teil("leinwand"); const zeile = teil("status"); @@ -295,6 +296,10 @@ export function starteSitzung(wurzel, quelle) { // Beim sauberen Schluss steht der Grund im Schliessrahmen -- etwa, // dass TESM wegen Untätigkeit getrennt hat. melden(letzterGrund ? `Sitzung beendet – ${letzterGrund}` : "Sitzung beendet."); + // Im Fenster gibt es nach dem Trennen nichts mehr zu sehen: ein leerer + // Rahmen, den man wegklicken muss. Bei einem **Abbruch** bleibt es + // stehen -- dort steht der Grund, und der ist der ganze Zweck. + beiEnde?.(); } else if (!stand && naechsterVersuch()) { return; } else { @@ -374,6 +379,13 @@ export function starteSitzung(wurzel, quelle) { rfb.sendKey(F4, "F4", false); rfb.sendKey(ALT_LINKS, "AltLeft", false); }); + // F5 faengt der Browser des Arbeitsplatzes ab -- er wuerde diese Seite neu + // laden statt das Bild auf dem Geraet. + teil("taste-f5")?.addEventListener("click", () => { + if (!rfb) return; + rfb.sendKey(F5, "F5", true); + rfb.sendKey(F5, "F5", false); + }); sitzungsknoepfe(false); melden("Wird vorbereitet …"); @@ -442,7 +454,9 @@ if (fenster) { titel.textContent = knopf.dataset.vncName || "Bildschirm"; if (typeof fenster.showModal === "function") fenster.showModal(); else fenster.setAttribute("open", ""); - beenden = starteSitzung(behaelter, knopf.dataset.vncOeffnen); + beenden = starteSitzung(behaelter, knopf.dataset.vncOeffnen, { + beiEnde: () => fenster.close(), + }); }); // Zu heisst zu: eine Sitzung, die im Hintergrund weiterlaeuft, haelt die