Files
atc-agents/ui/src/App.tsx
T

182 lines
7.1 KiB
TypeScript
Raw Normal View History

import { useRef, useState } from 'react'
import { useClock } from './hooks/useClock'
import { useCommandCenter } from './hooks/useCommandCenter'
import { useLiveMetrics } from './hooks/useLiveMetrics'
import { SideNav } from './components/layout/SideNav'
import { TopBar } from './components/layout/TopBar'
import { AgentFleet } from './components/features/AgentFleet'
import { ApprovalInbox } from './components/features/ApprovalInbox'
import { ChatDrawer } from './components/features/ChatDrawer'
import { GpuMonitor } from './components/features/GpuMonitor'
import { InfraQuickAccess } from './components/features/InfraQuickAccess'
import { InspectorPanel } from './components/features/InspectorPanel'
import { PlatformTopology } from './components/features/PlatformTopology'
import { PresentationView } from './components/features/PresentationView'
import { DataQualityView } from './components/features/DataQualityView'
import { KnowledgeChatView } from './components/features/KnowledgeChatView'
import { StorageView } from './components/features/StorageView'
import { SearchView } from './components/features/SearchView'
import { TerminalDock } from './components/features/TerminalDock'
import { resolveInfraNode } from './lib/infraCatalog'
import { cn } from './lib/utils'
export default function App() {
const clock = useClock()
const cc = useCommandCenter()
const [gpuChatActive, setGpuChatActive] = useState(false)
const gpuBoost = gpuChatActive || cc.mainView === 'knowledge'
const { agentLoads, gpuLive } = useLiveMetrics(cc.agents, cc.gpu, cc.anims, gpuBoost)
const mainScrollRef = useRef<HTMLDivElement>(null)
const isPlatform = cc.mainView === 'platform'
const openApprovals = () => {
cc.setMainView('approvals')
mainScrollRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
}
const terminalSubject = cc.terminalSubjectId
const terminalLabel = (() => {
if (cc.selectedAgent) return cc.selectedAgent.name.split(' ·')[0]
const infra = resolveInfraNode(terminalSubject)
if (infra) return infra.label
if (cc.selectedNode) return cc.selectedNode.label
return 'Lab'
})()
return (
<div className="flex h-full flex-col overflow-hidden bg-surface">
<TopBar
clock={clock}
status={cc.status}
workload={cc.workload}
agents={cc.agents}
approvals={cc.approvals}
onApprovalsClick={openApprovals}
/>
<div className="flex min-h-0 flex-1 overflow-hidden">
<SideNav
agents={cc.agents}
animations={cc.anims}
gpu={cc.gpu}
gpuLive={gpuLive}
gpuBoost={gpuBoost}
selectedAgentId={cc.selectedAgentId}
selectedNodeId={cc.selectedNodeId}
mainView={cc.mainView}
approvalCount={cc.approvals.length}
agentsLoading={cc.agentsLoading}
onSetMainView={cc.setMainView}
onOpenApprovals={openApprovals}
onSelectAgent={cc.selectAgent}
onSelectZone={cc.selectNode}
/>
<div ref={mainScrollRef} className="scrollbar-thin flex min-h-0 min-w-0 flex-1 flex-col overflow-y-auto bg-surface">
<div className={cn('flex min-h-0 flex-1', isPlatform ? '' : 'flex-col')}>
<div className={cn('flex min-w-0 flex-1 flex-col gap-2', isPlatform ? 'p-2' : 'min-h-0 p-3')}>
{isPlatform && (
<>
<div className="grid shrink-0 grid-cols-1 gap-2 xl:grid-cols-[1fr_auto]">
<AgentFleet
agents={cc.agents}
animations={cc.anims}
selectedId={cc.selectedAgentId}
loads={agentLoads}
approvalCount={cc.approvals.length}
onSelect={cc.selectAgent}
onOpenApprovals={openApprovals}
/>
<GpuMonitor gpu={cc.gpu} live={gpuLive} />
</div>
<InfraQuickAccess
workload={cc.workload}
agents={cc.agents}
selectedNodeId={cc.selectedNodeId}
busy={cc.nodeBusy}
onSelectNode={cc.selectNode}
onSelectAgent={cc.selectAgent}
onProbe={cc.probeNodeId}
onOpenTerminal={cc.openTerminal}
/>
</>
)}
<div className={isPlatform ? 'min-h-[420px]' : 'min-h-0 flex-1'}>
{cc.mainView === 'platform' ? (
<PlatformTopology
workload={cc.workload}
animations={cc.anims}
selectedNodeId={cc.selectedNodeId}
onNodeClick={cc.selectNode}
/>
) : cc.mainView === 'presentation' ? (
<PresentationView />
) : cc.mainView === 'dataquality' ? (
<DataQualityView />
) : cc.mainView === 'knowledge' ? (
<KnowledgeChatView onGpuActivity={setGpuChatActive} />
) : cc.mainView === 'storage' ? (
<StorageView />
) : cc.mainView === 'search' ? (
<SearchView />
) : (
<ApprovalInbox agents={cc.agents} livePending={cc.approvals} onDecide={cc.decide} />
)}
</div>
</div>
{isPlatform && (
<div className="flex w-[340px] shrink-0 flex-col border-l border-border">
<InspectorPanel
node={cc.selectedNode}
nodeDetail={cc.nodeDetail}
agent={cc.selectedAgent}
agents={cc.agents}
workload={cc.workload}
gpu={cc.gpu}
feed={cc.feed}
lines={cc.inspectorLines}
busy={cc.nodeBusy}
onProbe={cc.probeNode}
onAsk={cc.askNode}
onSelectAgent={cc.selectAgent}
onSendPrompt={cc.sendPrompt}
onClear={cc.clearSelection}
onOpenTerminal={cc.openTerminal}
onProbeNodeId={cc.probeNodeId}
/>
<TerminalDock
subjectId={terminalSubject}
subjectLabel={terminalLabel}
lines={cc.inspectorLines}
busy={cc.nodeBusy || cc.promptBusy}
expanded={cc.terminalExpanded}
onToggle={() => cc.setTerminalExpanded(!cc.terminalExpanded)}
/>
</div>
)}
</div>
</div>
</div>
<ChatDrawer
expanded={cc.chatExpanded}
onToggle={() => cc.setChatExpanded(!cc.chatExpanded)}
chat={cc.chat}
feed={cc.feed}
agents={cc.agents}
approvals={cc.approvals}
selectedAgent={cc.selectedAgent}
promptBusy={cc.promptBusy}
approvalHighlight={cc.approvalHighlight}
filterAgentId={cc.selectedAgentId}
onSendPrompt={cc.sendPrompt}
onDecide={cc.decide}
onDismissHighlight={() => cc.setApprovalHighlight(false)}
/>
</div>
)
}