Add HDFS browser, SSH terminal, presentation editor, lab health panel

- HDFS WebHDFS file browser (api/hdfs_api.py + HdfsView)
- In-browser SSH terminal via paramiko WebSocket bridge (api/ssh_terminal.py + SshTerminal, xterm.js)
- Presentation deck editor (text + image upload) and CRUD endpoints
- Collapsible GPU matrix + new LabHealthPanel in SideNav
- Topology fixes (edge alignment, Hadoop node, compact nodes)
- nginx ws timeout bump for long-lived SSH sessions
This commit is contained in:
mo
2026-06-26 00:47:49 +00:00
parent fefe3016ad
commit 46b51a891c
21 changed files with 1957 additions and 328 deletions
+9 -5
View File
@@ -16,7 +16,9 @@ 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 { HdfsView } from './components/features/HdfsView'
import { SearchView } from './components/features/SearchView'
import { SshTerminal } from './components/features/SshTerminal'
import { TerminalDock } from './components/features/TerminalDock'
import { WorkbenchPanel } from './components/features/WorkbenchPanel'
import { resolveInfraNode } from './lib/infraCatalog'
@@ -27,6 +29,7 @@ export default function App() {
const cc = useCommandCenter()
const [gpuChatActive, setGpuChatActive] = useState(false)
const [infraOpen, setInfraOpen] = useState(false)
const [sshOpen, setSshOpen] = useState(false)
const gpuBoost = gpuChatActive || cc.mainView === 'knowledge'
const { agentLoads, gpuLive } = useLiveMetrics(cc.agents, cc.gpu, cc.anims, gpuBoost)
const mainScrollRef = useRef<HTMLDivElement>(null)
@@ -60,20 +63,17 @@ export default function App() {
<div className="flex min-h-0 flex-1 overflow-hidden">
<SideNav
agents={cc.agents}
animations={cc.anims}
workload={cc.workload}
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}
onOpenSsh={() => setSshOpen(true)}
/>
<div ref={mainScrollRef} className={cn('flex min-h-0 min-w-0 flex-1 flex-col bg-surface', isPlatform ? 'overflow-hidden' : 'scrollbar-thin overflow-y-auto')}>
@@ -132,6 +132,8 @@ export default function App() {
<KnowledgeChatView onGpuActivity={setGpuChatActive} />
) : cc.mainView === 'storage' ? (
<StorageView />
) : cc.mainView === 'hdfs' ? (
<HdfsView />
) : cc.mainView === 'search' ? (
<SearchView />
) : (
@@ -201,6 +203,8 @@ export default function App() {
onDecide={cc.decide}
onDismissHighlight={() => cc.setApprovalHighlight(false)}
/>
<SshTerminal open={sshOpen} onClose={() => setSshOpen(false)} />
</div>
)
}