polish(admin): Übersicht-Kacheln klickbar + Notfall-Signal, Notfall-Text umbricht

- Übersicht: Kacheln (Nutzer/Anfragen/Notfälle/LLM) springen per Klick in den Bereich;
  Notfall-Kachel wird rot mit "ansehen", wenn Ereignisse vorliegen, sonst "keine".
- Notfall-Tabelle: Textausschnitt umbricht statt abzuschneiden -> auf Mobil lesbar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-21 00:32:52 +02:00
commit 7bac2952c5
2 changed files with 17 additions and 11 deletions

View file

@ -776,22 +776,28 @@ async function loadOverview() {
const gpu = (llm && llm.gpus && llm.gpus.length) const gpu = (llm && llm.gpus && llm.gpus.length)
? llm.gpus.map((g) => `GPU ${g.index}: ${g.percent}%`).join(" · ") : "—"; ? llm.gpus.map((g) => `GPU ${g.index}: ${g.percent}%`).join(" · ") : "—";
const stat = (label, value, sub) => ` const hasEmergencies = typeof emCount === "number" && emCount > 0;
<div class="bg-white dark:bg-slate-800 rounded-xl border border-slate-200 dark:border-slate-700 p-4"> // Kachel; mit data-jump wird sie anklickbar (springt in den Bereich).
const stat = (label, value, sub, opts = {}) => `
<${opts.jump ? `button data-jump="${opts.jump}"` : "div"}
class="ov-stat text-left bg-white dark:bg-slate-800 rounded-xl border ${opts.border || "border-slate-200 dark:border-slate-700"} p-4 ${opts.jump ? "hover:bg-slate-50 dark:hover:bg-slate-700/50 transition-colors" : ""}">
<p class="text-xs text-slate-500 dark:text-slate-400">${escHtml(label)}</p> <p class="text-xs text-slate-500 dark:text-slate-400">${escHtml(label)}</p>
<p class="text-2xl font-semibold mt-1">${escHtml(value)}</p> <p class="text-2xl font-semibold mt-1 ${opts.accent || ""}">${escHtml(value)}</p>
${sub ? `<p class="text-xs text-slate-400 mt-0.5 truncate">${escHtml(sub)}</p>` : ""} ${sub ? `<p class="text-xs text-slate-400 mt-0.5 truncate">${escHtml(sub)}</p>` : ""}
</div>`; </${opts.jump ? "button" : "div"}>`;
const jump = (to, label) => const jump = (to, label) =>
`<button class="ov-jump text-sm rounded-lg border border-slate-300 dark:border-slate-600 px-3 py-1.5 hover:bg-slate-100 dark:hover:bg-slate-700 transition-colors" data-jump="${to}">${escHtml(label)}</button>`; `<button class="ov-jump text-sm rounded-lg border border-slate-300 dark:border-slate-600 px-3 py-1.5 hover:bg-slate-100 dark:hover:bg-slate-700 transition-colors" data-jump="${to}">${escHtml(label)}</button>`;
c.innerHTML = ` c.innerHTML = `
<div class="grid grid-cols-2 gap-3"> <div class="grid grid-cols-2 gap-3">
${stat("Nutzer", userCount)} ${stat("Nutzer", userCount, "", { jump: "users" })}
${stat("Anfragen gesamt", reqTotal)} ${stat("Anfragen gesamt", reqTotal, "", { jump: "system" })}
${stat("Notfälle", emCount, (typeof emCount === "number" && emCount > 0) ? "protokolliert" : "")} ${stat("Notfälle", emCount, hasEmergencies ? "ansehen" : "keine",
${stat("LLM-Backend", backend, llm ? llm.model : "")} { jump: "emergency",
accent: hasEmergencies ? "text-red-600 dark:text-red-400" : "",
border: hasEmergencies ? "border-red-300 dark:border-red-800" : "" })}
${stat("LLM-Backend", backend, llm ? llm.model : "", { jump: "system" })}
</div> </div>
<div class="bg-white dark:bg-slate-800 rounded-xl border border-slate-200 dark:border-slate-700 p-4"> <div class="bg-white dark:bg-slate-800 rounded-xl border border-slate-200 dark:border-slate-700 p-4">
<h4 class="font-semibold text-sm mb-2">GPU-Auslastung</h4> <h4 class="font-semibold text-sm mb-2">GPU-Auslastung</h4>
@ -800,7 +806,7 @@ async function loadOverview() {
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
${jump("users", "→ Nutzer")} ${jump("system", "→ System")} ${jump("emergency", "→ Notfälle")} ${jump("users", "→ Nutzer")} ${jump("system", "→ System")} ${jump("emergency", "→ Notfälle")}
</div>`; </div>`;
c.querySelectorAll(".ov-jump").forEach((b) => c.querySelectorAll(".ov-jump, .ov-stat[data-jump]").forEach((b) =>
b.addEventListener("click", () => switchAdminTab(b.dataset.jump))); b.addEventListener("click", () => switchAdminTab(b.dataset.jump)));
} }
@ -1086,7 +1092,7 @@ async function loadEmergencyEvents() {
<td class="px-4 py-2.5"> <td class="px-4 py-2.5">
<span class="rounded-full bg-red-100 dark:bg-red-900/40 text-red-700 dark:text-red-300 text-xs px-2.5 py-0.5 font-medium">${escHtml(ev.category)}</span> <span class="rounded-full bg-red-100 dark:bg-red-900/40 text-red-700 dark:text-red-300 text-xs px-2.5 py-0.5 font-medium">${escHtml(ev.category)}</span>
</td> </td>
<td class="px-4 py-2.5 text-xs text-slate-600 dark:text-slate-300 max-w-xs truncate">${escHtml(ev.snippet)}</td> <td class="px-4 py-2.5 text-xs text-slate-600 dark:text-slate-300 max-w-[16rem] break-words">${escHtml(ev.snippet)}</td>
</tr>`).join("")} </tr>`).join("")}
</tbody> </tbody>
</table> </table>

View file

@ -318,6 +318,6 @@
<div id="status" class="w-full max-w-3xl mx-auto mt-1 min-h-[1rem] text-xs text-slate-500 dark:text-slate-400"></div> <div id="status" class="w-full max-w-3xl mx-auto mt-1 min-h-[1rem] text-xs text-slate-500 dark:text-slate-400"></div>
</footer> </footer>
<script src="/app.js?v=37"></script> <script src="/app.js?v=38"></script>
</body> </body>
</html> </html>