diff --git a/frontend/src/components/WebhookPanel.tsx b/frontend/src/components/WebhookPanel.tsx index dfe7c3b..375a307 100644 --- a/frontend/src/components/WebhookPanel.tsx +++ b/frontend/src/components/WebhookPanel.tsx @@ -65,10 +65,7 @@ export default function WebhookPanel({ events, status, error, onClear }: Props) {error &&

{error}

} {events.length === 0 ? ( -

- Noch keine Nachricht eingegangen. Ein fremdes System schickt Adressdaten an{' '} - POST /api/webhook; sie erscheinen hier ohne Zutun. -

+

Noch keine Nachricht eingegangen.

) : ( )} - -

- Der Webhook nimmt beliebiges JSON an – Objekt wie Liste – und zeigt es hier unverändert. - Der Verlauf liegt im Speicher des Backends und ist nach dessen Neustart leer; „Leeren" - verwirft ihn auch dort. -

) } diff --git a/frontend/src/config.ts b/frontend/src/config.ts index d460ec6..7ff0fea 100644 --- a/frontend/src/config.ts +++ b/frontend/src/config.ts @@ -6,6 +6,36 @@ export const DEFAULT_WS_PATH = '/ws' export const DEFAULT_WS_URL = import.meta.env.VITE_WS_URL ?? `ws://${DEFAULT_WS_HOST}:${DEFAULT_WS_PORT}${DEFAULT_WS_PATH}` +const SAVED_WS_URL_KEY = 'swyxweb.wsUrl' + +/** + * Zuletzt erfolgreich verbundene Adresse. localStorage kann fehlen oder gesperrt + * sein (Privatmodus, Browser-Einstellung) – dann wird schlicht nichts gemerkt. + */ +export function loadSavedWsUrl(): string | null { + try { + return localStorage.getItem(SAVED_WS_URL_KEY) + } catch { + return null + } +} + +export function saveWsUrl(url: string): void { + try { + localStorage.setItem(SAVED_WS_URL_KEY, url) + } catch { + // Ohne Speicher kein Wiederverbinden nach Neustart – mehr geht nicht verloren. + } +} + +export function clearSavedWsUrl(): void { + try { + localStorage.removeItem(SAVED_WS_URL_KEY) + } catch { + // Siehe saveWsUrl. + } +} + export interface ClientConfig { websocketUrl: string host: string diff --git a/frontend/src/index.css b/frontend/src/index.css index 71d3992..4ad9b7f 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -131,11 +131,6 @@ code { gap: 16px; } -.page__footer { - color: var(--text-muted); - font-size: 13px; -} - .card { background: var(--surface); border: 1px solid var(--border); diff --git a/frontend/src/pages/HomePage.tsx b/frontend/src/pages/HomePage.tsx index 9579331..2417e14 100644 --- a/frontend/src/pages/HomePage.tsx +++ b/frontend/src/pages/HomePage.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef, useState, type FormEvent, type ReactNode } from 'react' -import { DEFAULT_WS_URL, fetchClientConfig } from '../config' +import { DEFAULT_WS_URL, fetchClientConfig, clearSavedWsUrl, loadSavedWsUrl, saveWsUrl } from '../config' import { useSwyxTray } from '../hooks/useSwyxTray' import { useCallNotifications } from '../hooks/useCallNotifications' import { useWebhook } from '../hooks/useWebhook' @@ -68,13 +68,25 @@ export default function HomePage() { // Der Benutzer soll seine eingetippte Adresse nicht durch die Backend-Antwort verlieren. const urlTouched = useRef(false) + // Adresse des laufenden Verbindungsversuchs; gemerkt wird sie erst, wenn die + // Verbindung tatsächlich zustande kommt. + const pendingUrl = useRef(null) useEffect(() => { + // Mit der zuletzt erfolgreich verbundenen Adresse direkt wieder verbinden – + // die Backend-Konfiguration muss dann nicht gefragt werden. + const saved = loadSavedWsUrl() + if (saved) { + urlTouched.current = true + setUrl(saved) + pendingUrl.current = saved + tray.connect(saved) + return + } const controller = new AbortController() fetchClientConfig(controller.signal) .then((backendUrl) => { if (controller.signal.aborted) return - setConfigNote(`Adresse vom Backend übernommen: ${backendUrl}`) if (!urlTouched.current) setUrl(backendUrl) }) .catch((e: unknown) => { @@ -83,12 +95,28 @@ export default function HomePage() { setConfigNote(`Backend-Konfiguration nicht abrufbar (${message}) – Standardadresse wird verwendet.`) }) return () => controller.abort() + // eslint-disable-next-line react-hooks/exhaustive-deps -- nur beim Laden der Seite }, []) + // Erst die zustande gekommene Verbindung zählt: dann die Adresse merken, damit + // sie nach Verbindungsverlust oder Neustart automatisch wieder aufgebaut wird. + useEffect(() => { + if (status === 'open' && pendingUrl.current) saveWsUrl(pendingUrl.current) + }, [status]) + function handleConnect(event: FormEvent) { event.preventDefault() const target = url.trim() - if (target) tray.connect(target) + if (!target) return + pendingUrl.current = target + tray.connect(target) + } + + // Manuelles Trennen heißt auch: nach einem Neustart nicht wieder verbinden. + function handleDisconnect() { + clearSavedWsUrl() + pendingUrl.current = null + tray.disconnect() } function handleSendRaw(event: FormEvent) { @@ -104,7 +132,7 @@ export default function HomePage() {

Stadtbote

-

SwyxWeb · Telefonie über die SwyxTray-App

+

SwyxWeb

@@ -228,7 +256,7 @@ export default function HomePage() {