feat(web): management console — TanStack Start + orval + shadcn + Paraglide
ci / rust (push) Has been cancelled
ci / rust (push) Has been cancelled
Browser UI for the host's management REST API (mgmt.rs / docs/api/openapi.json). Stack, exactly as specified: - TanStack Start (Vite, SPA mode) — file-based routes, SSR shell + client hydration. - React Query via orval codegen from the checked-in OpenAPI spec: a custom fetch mutator (src/api/fetcher.ts) centralizes the base URL, the bearer token (Settings → localStorage), JSON, and a throwing ApiError; the query client skips retries on 4xx. orval returns the response body directly (includeHttpResponseReturnType:false) so a query's `.data` is the typed payload; GET→useQuery, POST/DELETE→useMutation by method. - shadcn/ui on Tailwind v4 (CSS-first tokens, dark-first) — button/card/badge/input/label/ table/skeleton primitives hand-authored from the canonical source. - Paraglide i18n (en + de) with a reactive useLocale() hook and a language switcher. Pages: dashboard (live status — video/audio/session/stream, stop-session + request-IDR, 2s polling), host (identity/codecs/ports), clients (paired list + unpair), pairing (PIN submit, polls pin_pending), settings (API token + language). Dev server proxies /api → 127.0.0.1:47990 (same-origin, no CORS; PUNKTFUNK_MGMT_URL to override). Generated code (orval client, paraglide runtime, routeTree) is gitignored and reproduced by `pnpm codegen` (prepare/pre* scripts). Validated live against `serve`: API shapes match, dev proxy works, SSR shell renders the localized nav, build + tsc green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/inlang-message-format",
|
||||
"app_name": "punktfunk",
|
||||
"app_tagline": "Verwaltungskonsole",
|
||||
"nav_dashboard": "Übersicht",
|
||||
"nav_host": "Host",
|
||||
"nav_clients": "Gekoppelte Geräte",
|
||||
"nav_pairing": "Kopplung",
|
||||
"nav_settings": "Einstellungen",
|
||||
"status_title": "Live-Status",
|
||||
"status_video": "Video",
|
||||
"status_audio": "Audio",
|
||||
"status_streaming": "Aktiv",
|
||||
"status_idle": "Inaktiv",
|
||||
"status_session": "Sitzung",
|
||||
"status_no_session": "Keine aktive Sitzung",
|
||||
"status_paired_count": "Gekoppelte Geräte",
|
||||
"status_pin_pending": "Kopplungs-PIN ausstehend",
|
||||
"stream_codec": "Codec",
|
||||
"stream_resolution": "Auflösung",
|
||||
"stream_fps": "Bildrate",
|
||||
"stream_bitrate": "Bitrate",
|
||||
"action_stop_session": "Sitzung beenden",
|
||||
"action_request_idr": "Keyframe anfordern",
|
||||
"action_unpair": "Entkoppeln",
|
||||
"host_identity": "Identität",
|
||||
"host_hostname": "Hostname",
|
||||
"host_local_ip": "Lokale IP",
|
||||
"host_version": "Version",
|
||||
"host_abi": "ABI-Version",
|
||||
"host_codecs": "Codecs",
|
||||
"host_ports": "Ports",
|
||||
"host_uniqueid": "Eindeutige ID",
|
||||
"clients_title": "Gekoppelte Geräte",
|
||||
"clients_empty": "Noch keine gekoppelten Geräte.",
|
||||
"clients_name": "Name",
|
||||
"clients_fingerprint": "Fingerabdruck",
|
||||
"clients_unpair_confirm": "Dieses Gerät entkoppeln? Es muss sich erneut koppeln, um zu verbinden.",
|
||||
"pairing_title": "Kopplung",
|
||||
"pairing_idle": "Keine Kopplung aktiv. Starte die Kopplung in einem Moonlight-Client und gib hier die PIN ein.",
|
||||
"pairing_waiting": "Ein Gerät wartet auf Kopplung. Gib die angezeigte PIN ein:",
|
||||
"pairing_pin_label": "PIN",
|
||||
"pairing_submit": "PIN bestätigen",
|
||||
"pairing_success": "Erfolgreich gekoppelt.",
|
||||
"pairing_failed": "Kopplung fehlgeschlagen — PIN prüfen und erneut versuchen.",
|
||||
"settings_title": "Einstellungen",
|
||||
"settings_token_label": "API-Token",
|
||||
"settings_token_help": "Bearer-Token für die Verwaltungs-API. Bei einem Loopback-Host ohne Token leer lassen.",
|
||||
"settings_language": "Sprache",
|
||||
"settings_save": "Speichern",
|
||||
"settings_saved": "Gespeichert.",
|
||||
"common_loading": "Wird geladen…",
|
||||
"common_error": "Etwas ist schiefgelaufen.",
|
||||
"common_retry": "Erneut versuchen",
|
||||
"common_yes": "Ja",
|
||||
"common_cancel": "Abbrechen",
|
||||
"common_unauthorized": "Nicht autorisiert — gültiges API-Token in den Einstellungen setzen."
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/inlang-message-format",
|
||||
"app_name": "punktfunk",
|
||||
"app_tagline": "management console",
|
||||
"nav_dashboard": "Dashboard",
|
||||
"nav_host": "Host",
|
||||
"nav_clients": "Paired clients",
|
||||
"nav_pairing": "Pairing",
|
||||
"nav_settings": "Settings",
|
||||
"status_title": "Live status",
|
||||
"status_video": "Video",
|
||||
"status_audio": "Audio",
|
||||
"status_streaming": "Streaming",
|
||||
"status_idle": "Idle",
|
||||
"status_session": "Session",
|
||||
"status_no_session": "No active session",
|
||||
"status_paired_count": "Paired clients",
|
||||
"status_pin_pending": "Pairing PIN pending",
|
||||
"stream_codec": "Codec",
|
||||
"stream_resolution": "Resolution",
|
||||
"stream_fps": "Frame rate",
|
||||
"stream_bitrate": "Bitrate",
|
||||
"action_stop_session": "Stop session",
|
||||
"action_request_idr": "Request keyframe",
|
||||
"action_unpair": "Unpair",
|
||||
"host_identity": "Identity",
|
||||
"host_hostname": "Hostname",
|
||||
"host_local_ip": "Local IP",
|
||||
"host_version": "Version",
|
||||
"host_abi": "ABI version",
|
||||
"host_codecs": "Codecs",
|
||||
"host_ports": "Ports",
|
||||
"host_uniqueid": "Unique ID",
|
||||
"clients_title": "Paired clients",
|
||||
"clients_empty": "No paired clients yet.",
|
||||
"clients_name": "Name",
|
||||
"clients_fingerprint": "Fingerprint",
|
||||
"clients_unpair_confirm": "Unpair this client? It will need to pair again to connect.",
|
||||
"pairing_title": "Pairing",
|
||||
"pairing_idle": "No pairing in progress. Start pairing from a Moonlight client, then enter its PIN here.",
|
||||
"pairing_waiting": "A client is waiting to pair. Enter the PIN it shows:",
|
||||
"pairing_pin_label": "PIN",
|
||||
"pairing_submit": "Submit PIN",
|
||||
"pairing_success": "Paired successfully.",
|
||||
"pairing_failed": "Pairing failed — check the PIN and try again.",
|
||||
"settings_title": "Settings",
|
||||
"settings_token_label": "API token",
|
||||
"settings_token_help": "Bearer token for the management API. Leave empty for a loopback host with no token.",
|
||||
"settings_language": "Language",
|
||||
"settings_save": "Save",
|
||||
"settings_saved": "Saved.",
|
||||
"common_loading": "Loading…",
|
||||
"common_error": "Something went wrong.",
|
||||
"common_retry": "Retry",
|
||||
"common_yes": "Yes",
|
||||
"common_cancel": "Cancel",
|
||||
"common_unauthorized": "Unauthorized — set a valid API token in Settings."
|
||||
}
|
||||
Reference in New Issue
Block a user