import { useState } from 'react'; import { useBindings, useRoutePreview, useRouteDecisions } from '@insignia/iios-community-web'; import type { RouteDecision } from '@insignia/iios-kernel-client'; export const SERVICE = 'http://localhost:3200'; const STATE_COLORS: Record = { ALLOW: '#16a34a', DENY: '#dc2626', REVIEW: '#d97706', SUPPRESS: '#6b7280', SIMULATED: '#2563eb', }; /** Inject a signed dev webhook and poll the raw-event log until it normalizes into an interaction. */ async function ingestTestMessage(token: string, text: string): Promise { const inject = await fetch(`${SERVICE}/v1/dev/webhook/WEBHOOK`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ text }), }); if (!inject.ok) throw new Error(`inject ${inject.status}`); const { rawEventId } = (await inject.json()) as { rawEventId: string }; for (let i = 0; i < 40; i++) { const r = await fetch(`${SERVICE}/v1/adapters/inbound`, { headers: { authorization: `Bearer ${token}` } }); const rows = (await r.json()) as Array<{ id: string; interactionId?: string | null }>; const hit = rows.find((x) => x.id === rawEventId); if (hit?.interactionId) return hit.interactionId; await new Promise((res) => setTimeout(res, 150)); } throw new Error('interaction never normalized'); } const cell: React.CSSProperties = { padding: '6px 10px', borderBottom: '1px solid #eee', verticalAlign: 'top' }; const box: React.CSSProperties = { border: '1px solid #e5e7eb', borderRadius: 8, padding: 16, marginBottom: 16 }; export function App({ token }: { token: string }) { const { bindings, createBinding } = useBindings(); const preview = useRoutePreview(); const { decisions, approve, deny } = useRouteDecisions({ pollMs: 2000 }); const [origin, setOrigin] = useState('WEBHOOK'); const [dest, setDest] = useState('PORTAL'); const [destRef, setDestRef] = useState('parents-group'); const [restriction, setRestriction] = useState(''); const [mode, setMode] = useState('MANUAL'); const [text, setText] = useState('There is a party at 9 PM tonight!'); const [simRows, setSimRows] = useState([]); const [busy, setBusy] = useState(''); const onCreate = async () => { await createBinding({ originChannelType: origin, destinationChannelType: dest, destinationRef: destRef || undefined, restrictionProfile: restriction || undefined, mode, requiresReview: true, enabled: true, } as Parameters[0]); }; const onSimulate = async () => { setBusy('ingesting…'); try { const interactionId = await ingestTestMessage(token, text); setBusy('simulating…'); setSimRows(await preview(interactionId, origin)); } catch (e) { setBusy(`error: ${(e as Error).message}`); return; } setBusy(''); }; return (

IIOS P6 — Route Admin

Preview-first. Simulation never sends. Restricted destinations are deny-by-default.

1 · Create binding

{bindings.map((b) => ( ))}
origindestinationrestrictionmodeenabled
{b.originChannelType}{b.originRef ? `:${b.originRef}` : ''} {b.destinationChannelType}{b.destinationRef ? `:${b.destinationRef}` : ''} {b.restrictionProfile ?? '—'} {b.mode} {b.enabled ? '✓' : '—'}

2 · Simulate a message (no send)

setText(e.target.value)} style={{ flex: 1 }} />
{busy &&

{busy}

} {simRows.length > 0 && ( {simRows.map((d) => )}
destinationdecisionreason codespreview
)}

3 · Pending decisions (approve / deny)

{decisions.length === 0 &&

No decisions yet — simulate above.

} {decisions.map((d) => ( ))}
{d.decisionState === 'REVIEW' ? ( <> ) : d.executed ? '↪ forwarded (sandbox)' : '—'}
); } function payloadOf(d: RouteDecision): { text?: string; destinationRef?: string | null } { return (d.previewPayload ?? {}) as { text?: string; destinationRef?: string | null }; } function DecisionRow({ d }: { d: RouteDecision }) { const p = payloadOf(d); return ( {d.routeBinding ? `${d.routeBinding.destinationChannelType}${d.routeBinding.destinationRef ? `:${d.routeBinding.destinationRef}` : ''}` : (p.destinationRef ?? '—')} {d.decisionState} {d.reasonCodes.join(', ') || '—'} {p.text ?? '—'} ); } function DecisionCells({ d }: { d: RouteDecision }) { const p = payloadOf(d); return ( <> {d.routeBinding ? `${d.routeBinding.destinationChannelType}${d.routeBinding.destinationRef ? `:${d.routeBinding.destinationRef}` : ''}` : '—'} {d.decisionState} {d.reasonCodes.join(', ') || '—'} {p.text ?? '—'} ); }