Merge Workstream H: device pairing UI + live dashboard

Resolved conflicts in App.tsx/SeancePage.tsx (both F and H added new
routes/nav links, kept both) and i18n files (both added sibling top-level
keys — inventory + devices, fixed nesting after conflict markers removed).

Also fixed a real integration gap: DevicesPage.test.tsx's mock User object
predated Workstream F's unlocks/essence additions to the User type (the
two workstreams built in parallel isolation and couldn't see each other's
changes). 269/269 frontend tests pass, tsc clean.
This commit is contained in:
Indiana
2026-07-24 20:47:57 +00:00
10 changed files with 1492 additions and 0 deletions

View File

@@ -30,6 +30,7 @@ for (const f of files) {
const RARITY = ['common', 'uncommon', 'rare', 'mythic']
const RULES = [
['seance.connection.', ['connecting', 'open', 'unstable', 'closed']],
['devices.dashboard.connection.', ['connecting', 'open', 'unstable', 'closed']],
['seance.status.', ['attuning', 'summoning', 'gathering']],
['seance.toast.', ['rate_limited', 'veil_crowded']], // other codes fall back to toast.message
['seance.modes.', ['wire', 'evp', 'radio', 'ouija', 'emf']],

View File

@@ -14,6 +14,7 @@
"codex": "codex",
"shop": "shop",
"inventory": "inventory",
"devices": "devices",
"seance": "séance",
"enter": "enter",
"logout": "depart"
@@ -443,6 +444,39 @@
"error": "the sigil would not hold"
}
},
"devices": {
"back": "← the threshold",
"title": "DEVICE BAY",
"subtitle": "pair hardware to your account and watch its telemetry live",
"pair": {
"title": "PAIR A NEW DEVICE",
"nameLabel": "device name",
"namePlaceholder": "e.g. attic-node-01",
"submit": "pair device",
"pending": "pairing…",
"nameRequired": "name the device before pairing",
"error": "the pairing handshake failed — try again"
},
"token": {
"warning": "copy this now — it cannot be shown again. losing it means re-pairing the device.",
"copy": "copy",
"copied": "copied",
"confirm": "I've saved it — hide token"
},
"dashboard": {
"title": "LIVE FEED",
"empty": "no devices paired yet — pair one above to see it here",
"lastSeen": "last seen",
"lastSeenNever": "never",
"noReadings": "awaiting first reading…",
"connection": {
"connecting": "reaching the feed…",
"open": "feed live",
"unstable": "feed unstable…",
"closed": "feed offline"
}
}
},
"haunting": {
"whisper": {
"behindYou": "behind you",

View File

@@ -14,6 +14,7 @@
"codex": "códice",
"shop": "relicario",
"inventory": "inventario",
"devices": "dispositivos",
"seance": "sesión",
"enter": "entrar",
"logout": "partir"
@@ -443,6 +444,39 @@
"error": "el sigilo no se sostuvo"
}
},
"devices": {
"back": "← el umbral",
"title": "BAHÍA DE DISPOSITIVOS",
"subtitle": "empareja hardware con tu cuenta y observa su telemetría en vivo",
"pair": {
"title": "EMPAREJAR UN NUEVO DISPOSITIVO",
"nameLabel": "nombre del dispositivo",
"namePlaceholder": "p. ej. nodo-ático-01",
"submit": "emparejar dispositivo",
"pending": "emparejando…",
"nameRequired": "nombra el dispositivo antes de emparejarlo",
"error": "el emparejamiento falló — inténtalo de nuevo"
},
"token": {
"warning": "cópialo ahora — no volverá a mostrarse. perderlo significa volver a emparejar el dispositivo.",
"copy": "copiar",
"copied": "copiado",
"confirm": "ya lo guardé — ocultar token"
},
"dashboard": {
"title": "TRANSMISIÓN EN VIVO",
"empty": "aún no hay dispositivos emparejados — empareja uno arriba para verlo aquí",
"lastSeen": "visto por última vez",
"lastSeenNever": "nunca",
"noReadings": "esperando la primera lectura…",
"connection": {
"connecting": "alcanzando la transmisión…",
"open": "transmisión en vivo",
"unstable": "transmisión inestable…",
"closed": "transmisión desconectada"
}
}
},
"haunting": {
"whisper": {
"behindYou": "detrás de ti",