// file: kb_app/frontend/ts/main.ts import * as bootstrap from "bootstrap"; import "simplebar"; import ResizeObserver from "resize-observer-polyfill"; import { invoke } from "@tauri-apps/api/core"; import { listen, type UnlistenFn } from "@tauri-apps/api/event"; //import { error } from "@fltsci/tauri-plugin-tracing"; //import { info } from "@fltsci/tauri-plugin-tracing"; import { trace, takeoverConsole } from "@fltsci/tauri-plugin-tracing"; (window as Window & typeof globalThis & { bootstrap?: typeof bootstrap }).bootstrap = bootstrap; (window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver; function appendLogLine(textarea: HTMLTextAreaElement, line: string): void { const now = new Date(); const timestamp = now.toLocaleTimeString("fr-CH", { hour12: false }); textarea.value += `[${timestamp}] ${line}\n`; textarea.scrollTop = textarea.scrollHeight; } function setRunningState( isRunning: boolean, statusBadge: HTMLSpanElement, connectButton: HTMLButtonElement, disconnectButton: HTMLButtonElement, ): void { if (isRunning) { statusBadge.textContent = "Connected"; statusBadge.className = "badge text-bg-success"; connectButton.disabled = true; disconnectButton.disabled = false; return; } statusBadge.textContent = "Disconnected"; statusBadge.className = "badge text-bg-secondary"; connectButton.disabled = false; disconnectButton.disabled = true; } function setBusyState( label: string, statusBadge: HTMLSpanElement, connectButton: HTMLButtonElement, disconnectButton: HTMLButtonElement, ): void { statusBadge.textContent = label; statusBadge.className = "badge text-bg-warning"; connectButton.disabled = true; disconnectButton.disabled = true; } document.addEventListener("DOMContentLoaded", async () => { void takeoverConsole(); const sidebarToggle = document.querySelector('#sidebarToggle'); if (sidebarToggle) { // restaurer l’état depuis localStorage if (localStorage.getItem('sidebar-toggle') === 'true') { document.body.classList.add('sidenav-toggled'); } sidebarToggle.addEventListener('click', (event) => { event.preventDefault(); document.body.classList.toggle('sidenav-toggled'); localStorage.setItem('sidebar-toggle', document.body.classList.contains('sidenav-toggled') ? 'true' : 'false'); }); } const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]'); Array.from(tooltipTriggerList).map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl)); const toastElList = document.querySelectorAll('.toast'); Array.from(toastElList).map(toastEl => new bootstrap.Toast(toastEl)); const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]'); Array.from(popoverTriggerList).map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl)); const gobackto = location.pathname + location.search; document.querySelectorAll('a[data-setlang]').forEach((a) => { const href = a.getAttribute("href"); if (!href) return; // pas de href => on ignore const url = new URL(href, location.origin); url.searchParams.set("gobackto", gobackto); // conserve une URL relative (path + query) a.setAttribute("href", url.pathname + "?" + url.searchParams.toString()); }); const connectButton = document.querySelector("#wsConnectButton"); const disconnectButton = document.querySelector("#wsDisconnectButton"); const statusBadge = document.querySelector("#wsStatusBadge"); const logTextarea = document.querySelector("#wsLogTextarea"); if (!connectButton || !disconnectButton || !statusBadge || !logTextarea) { trace("main UI controls not found"); return; } let unlistenLogEvent: UnlistenFn | null = null; try { unlistenLogEvent = await listen("kb-log", (event) => { appendLogLine(logTextarea, event.payload); }); } catch (error) { appendLogLine(logTextarea, `[ui] event listen error: ${String(error)}`); } setRunningState(false, statusBadge, connectButton, disconnectButton); appendLogLine(logTextarea, "[ui] main window loaded"); connectButton.addEventListener("click", async () => { setBusyState("Starting", statusBadge, connectButton, disconnectButton); try { const startedCount = await invoke("start_ws_clients"); appendLogLine(logTextarea, `[ui] started ${startedCount} websocket client(s)`); setRunningState(true, statusBadge, connectButton, disconnectButton); } catch (error) { appendLogLine(logTextarea, `[ui] start error: ${String(error)}`); setRunningState(false, statusBadge, connectButton, disconnectButton); } }); disconnectButton.addEventListener("click", async () => { setBusyState("Stopping", statusBadge, connectButton, disconnectButton); try { const stoppedCount = await invoke("stop_ws_clients"); appendLogLine(logTextarea, `[ui] stopped ${stoppedCount} websocket client(s)`); setRunningState(false, statusBadge, connectButton, disconnectButton); } catch (error) { appendLogLine(logTextarea, `[ui] stop error: ${String(error)}`); setRunningState(true, statusBadge, connectButton, disconnectButton); } }); window.addEventListener("beforeunload", () => { if (unlistenLogEvent) { unlistenLogEvent(); } }); trace("window loaded"); });