/** * Dev test page for Conversational Branching components. * Route: /dev/branching * * Renders all branching components with mock data — no API calls. * Use this to validate visual design before wiring into FlowPilotSessionPage. */ import { useState, useCallback, useEffect, useRef } from 'react' import { BranchMap } from '@/components/session/BranchMap' import { ForkCard } from '@/components/session/ForkCard' import { BranchTransitionBar } from '@/components/session/BranchTransitionBar' import { BranchRevivalCard } from '@/components/session/BranchRevivalCard' import { HandoffModal } from '@/components/session/HandoffModal' import type { BranchResponse, ForkPointResponse, ResolutionOutputResponse, ResolutionOutputType, } from '@/types/branching' import { cn } from '@/lib/utils' import { toast } from '@/lib/toast' import { FileText, BookOpen, MessageSquare, Pencil, Copy, Send, Check, } from 'lucide-react' // ── Mock Data ── const SESSION_ID = 'mock-session-001' const ROOT_ID = 'branch-root' const BRANCH_NET = 'branch-network' const BRANCH_DNS = 'branch-dns' const BRANCH_DHCP = 'branch-dhcp' const BRANCH_REVIVED = 'branch-revived-firewall' const MOCK_BRANCHES: BranchResponse[] = [ { id: ROOT_ID, session_id: SESSION_ID, parent_branch_id: null, fork_point_step_id: null, branch_order: 1, label: 'Root — Initial Investigation', status: 'active', status_reason: null, status_changed_at: null, context_summary: { tried: ['Checked event logs', 'Ran ipconfig'], concluded: 'Multiple possible causes identified', artifacts: [], }, evidence_from_branch_id: null, evidence_description: null, step_count: 4, created_at: '2026-03-24T10:00:00Z', updated_at: '2026-03-24T10:05:00Z', }, { id: BRANCH_NET, session_id: SESSION_ID, parent_branch_id: ROOT_ID, fork_point_step_id: null, branch_order: 1, label: 'Network Connectivity', status: 'dead_end', status_reason: 'Ping to gateway successful, NIC is healthy', status_changed_at: '2026-03-24T10:12:00Z', context_summary: { tried: ['Ping gateway', 'Check NIC status', 'Traceroute'], concluded: 'Network layer is not the issue', artifacts: ['traceroute.txt'], }, evidence_from_branch_id: null, evidence_description: null, step_count: 3, created_at: '2026-03-24T10:05:00Z', updated_at: '2026-03-24T10:12:00Z', }, { id: BRANCH_DNS, session_id: SESSION_ID, parent_branch_id: ROOT_ID, fork_point_step_id: null, branch_order: 2, label: 'DNS Resolution', status: 'solved', status_reason: 'DNS cache was poisoned — flushed and resolved', status_changed_at: '2026-03-24T10:20:00Z', context_summary: { tried: ['nslookup', 'ipconfig /flushdns', 'Checked DNS server config'], concluded: 'Root cause: stale DNS cache entry for internal domain', artifacts: ['nslookup-output.txt'], }, evidence_from_branch_id: null, evidence_description: null, step_count: 5, created_at: '2026-03-24T10:05:00Z', updated_at: '2026-03-24T10:20:00Z', }, { id: BRANCH_DHCP, session_id: SESSION_ID, parent_branch_id: ROOT_ID, fork_point_step_id: null, branch_order: 3, label: 'DHCP Lease Issue', status: 'untried', status_reason: null, status_changed_at: null, context_summary: null, evidence_from_branch_id: null, evidence_description: null, step_count: 0, created_at: '2026-03-24T10:05:00Z', updated_at: '2026-03-24T10:05:00Z', }, { id: BRANCH_REVIVED, session_id: SESSION_ID, parent_branch_id: BRANCH_NET, fork_point_step_id: null, branch_order: 1, label: 'Firewall Rules', status: 'revived', status_reason: null, status_changed_at: '2026-03-24T10:25:00Z', context_summary: { tried: ['Checked Windows Firewall'], concluded: 'Revisiting after DNS fix revealed blocked outbound on port 443', artifacts: [], }, evidence_from_branch_id: BRANCH_DNS, evidence_description: 'DNS fix revealed that port 443 is being blocked by a new firewall rule pushed via GPO', step_count: 2, created_at: '2026-03-24T10:15:00Z', updated_at: '2026-03-24T10:25:00Z', }, ] const MOCK_FORK: ForkPointResponse = { id: 'fork-001', session_id: SESSION_ID, parent_branch_id: ROOT_ID, trigger_step_id: null, fork_reason: "Based on the symptoms (intermittent connectivity loss affecting only this workstation), I see three possible causes. Let's investigate each:", options: [ { label: 'Network Connectivity', description: 'NIC driver issue, cable fault, or switch port problem', branch_id: BRANCH_NET, status: 'dead_end', }, { label: 'DNS Resolution', description: 'Stale cache, wrong DNS server, or poisoned entry', branch_id: BRANCH_DNS, status: 'solved', }, { label: 'DHCP Lease Issue', description: 'Lease expiry, scope exhaustion, or relay agent failure', branch_id: BRANCH_DHCP, status: 'untried', }, ], created_at: '2026-03-24T10:05:00Z', } const MOCK_OUTPUTS: ResolutionOutputResponse[] = [ { id: 'output-psa', session_id: SESSION_ID, output_type: 'psa_ticket_notes', generated_content: `## Problem User reported intermittent connectivity loss on workstation WS-1042 in the Accounting department. ## Diagnostic Steps 1. **Network Connectivity** [Dead End] — Ping to gateway successful (avg 2ms), NIC healthy, traceroute clean. Network layer ruled out. 2. **DNS Resolution** [Solved] — nslookup for internal domain \`erp.contoso.local\` returned stale IP (10.0.1.50 instead of 10.0.2.50). DNS cache poisoned by a cached entry from before the ERP server migration last Tuesday. 3. **Firewall Rules** [Revived] — DNS fix revealed that a new GPO-pushed firewall rule was blocking outbound port 443. Rule was added by the security team on 3/22 without change advisory. ## Resolution - Flushed DNS cache: \`ipconfig /flushdns\` - Cleared stale DNS record on domain controller - Firewall rule exception added for ERP traffic - Verified connectivity stable for 15 minutes post-fix ## Recommendations - Add DNS record validation to the ERP migration runbook - Request change advisory process for GPO firewall rule changes`, structured_data: null, edited_content: null, status: 'draft', pushed_to: null, pushed_at: null, pushed_reference: null, generated_by_model: 'claude-sonnet-4-6', created_at: '2026-03-24T10:22:00Z', updated_at: '2026-03-24T10:22:00Z', }, { id: 'output-kb', session_id: SESSION_ID, output_type: 'knowledge_base', generated_content: `# Intermittent Connectivity After Server Migration ## Symptoms - Workstation loses connectivity to internal applications intermittently - External sites work normally - Affects single workstation or small group ## Root Cause Stale DNS cache entries pointing to pre-migration IP addresses. Often occurs 1-7 days after internal server migrations when DNS TTLs haven't expired. ## Things to Rule Out First - **Network layer** — If ping to gateway succeeds and traceroute is clean, skip to DNS - **DHCP** — Only investigate if ipconfig shows APIPA address (169.254.x.x) ## Resolution Steps 1. Run \`nslookup \` — compare returned IP with current server IP 2. If mismatched: \`ipconfig /flushdns\` on the workstation 3. Check AD DNS for stale records: \`dnscmd /enumrecords contoso.local \` 4. Delete stale record if found 5. Verify: \`nslookup \` returns correct IP ## Tags DNS, migration, connectivity, cache, stale-record`, structured_data: { symptoms: ['Intermittent connectivity to internal apps', 'External sites work'], root_cause: 'Stale DNS cache from server migration', steps: ['nslookup', 'flushdns', 'Check AD DNS', 'Delete stale record'], tags: ['DNS', 'migration', 'connectivity'], }, edited_content: null, status: 'draft', pushed_to: null, pushed_at: null, pushed_reference: null, generated_by_model: 'claude-sonnet-4-6', created_at: '2026-03-24T10:22:00Z', updated_at: '2026-03-24T10:22:00Z', }, { id: 'output-client', session_id: SESSION_ID, output_type: 'client_summary', generated_content: `Hi, We've resolved the connectivity issue on your workstation. Here's what happened: After your company's ERP server was moved to a new address last week, your computer was still trying to reach it at the old address. This caused the intermittent connection drops you were experiencing when accessing internal applications. We've updated the address records and cleared the old cached information on your machine. We also found and fixed a secondary issue where a recently applied security policy was blocking some web traffic. Your connectivity should now be stable. If you experience any further issues, please don't hesitate to reach out.`, structured_data: null, edited_content: null, status: 'draft', pushed_to: null, pushed_at: null, pushed_reference: null, generated_by_model: 'claude-sonnet-4-6', created_at: '2026-03-24T10:22:00Z', updated_at: '2026-03-24T10:22:00Z', }, ] // ── Mock Resolution Panel (self-contained, no API calls) ── const TABS: Array<{ type: ResolutionOutputType; label: string; icon: React.ElementType }> = [ { type: 'psa_ticket_notes', label: 'PSA Notes', icon: FileText }, { type: 'knowledge_base', label: 'KB Article', icon: BookOpen }, { type: 'client_summary', label: 'Client Summary', icon: MessageSquare }, ] function MockResolutionPanel({ outputs }: { outputs: ResolutionOutputResponse[] }) { const [activeType, setActiveType] = useState('psa_ticket_notes') const [isEditing, setIsEditing] = useState(false) const [editValue, setEditValue] = useState('') const [copied, setCopied] = useState(false) const activeOutput = outputs.find(o => o.output_type === activeType) ?? null const displayContent = activeOutput?.edited_content ?? activeOutput?.generated_content ?? '' function handleEditToggle() { if (!isEditing) { setEditValue(displayContent) setIsEditing(true) } else { setIsEditing(false) setEditValue('') } } async function handleCopy() { try { await navigator.clipboard.writeText(displayContent) setCopied(true) setTimeout(() => setCopied(false), 2000) } catch { toast.error('Failed to copy') } } return (
{/* Tab bar */}
{TABS.map(tab => { const Icon = tab.icon const isActive = tab.type === activeType return ( ) })}
{/* Content */}
{!activeOutput ? (
No output generated yet.
) : isEditing ? (