|
1 | | -import { useCallback, useState } from "react"; |
| 1 | +import { useCallback, useReducer, useState } from "react"; |
2 | 2 | import { ReactFlowProvider, type Edge, type Node } from "@xyflow/react"; |
| 3 | + |
3 | 4 | import { FlowCanvas } from "@/components/FlowCanvas"; |
4 | 5 | import { Palette } from "@/components/Palette"; |
| 6 | +import { Sidebar } from "@/components/Sidebar"; |
| 7 | +import { TopBar, type RunMode } from "@/components/TopBar"; |
| 8 | +import { BottomStrip } from "@/components/BottomStrip"; |
| 9 | + |
| 10 | +import { |
| 11 | + INITIAL_SPEC, specReducer, type TopologyFactory, |
| 12 | +} from "@/state/spec"; |
| 13 | +import type { ShardingProposalView } from "@/components/sidebar/ShardingTab"; |
| 14 | + |
| 15 | +const PRESETS: readonly string[] = [ |
| 16 | + "qwen3_next", "kimi_linear", "kimi_k2", "deepseek_v3", |
| 17 | + "deepseek_v4_flash", "gemma4", "mistral4", "ling26", |
| 18 | + "longcat", "nemotron3", "zaya1", "arcee_trinity", |
| 19 | +]; |
| 20 | + |
| 21 | +const TOPOLOGIES: readonly TopologyFactory[] = [ |
| 22 | + "h100_8x", "h200_8x", "a100_8x", "b100_8x", |
| 23 | + "gb10_quarter", "tpu_v6e_8", "tpu_v5p_4", "m3_ultra_solo", |
| 24 | +]; |
5 | 25 |
|
6 | 26 | export function App(): JSX.Element { |
7 | 27 | const [nodes, setNodes] = useState<Node[]>([]); |
8 | 28 | const [edges, setEdges] = useState<Edge[]>([]); |
| 29 | + const [projectName, setProjectName] = useState("untitled"); |
| 30 | + const [proposals] = useState<ShardingProposalView[]>([]); |
| 31 | + const [spec, dispatch] = useReducer(specReducer, INITIAL_SPEC); |
9 | 32 |
|
10 | 33 | const handleDropBrick = useCallback( |
11 | 34 | (kind: string, position: { x: number; y: number }) => { |
12 | 35 | setNodes((prev) => [ |
13 | 36 | ...prev, |
14 | | - { |
15 | | - id: `${kind}_${prev.length + 1}`, |
16 | | - type: "brick", |
17 | | - position, |
18 | | - data: { kind }, |
19 | | - }, |
| 37 | + { id: `${kind}_${prev.length + 1}`, |
| 38 | + type: "brick", position, data: { kind } }, |
20 | 39 | ]); |
21 | 40 | }, []); |
22 | 41 |
|
23 | 42 | const handleConnect = useCallback( |
24 | 43 | (p: { source: string; target: string }) => { |
25 | 44 | setEdges((prev) => [ |
26 | 45 | ...prev, |
27 | | - { id: `${p.source}->${p.target}`, |
28 | | - source: p.source, target: p.target, |
| 46 | + { id: `${p.source}->${p.target}`, source: p.source, target: p.target, |
29 | 47 | data: { severity: "info" } }, |
30 | 48 | ]); |
31 | 49 | }, []); |
32 | 50 |
|
| 51 | + const handlePresetDrop = useCallback((_name: string) => { |
| 52 | + // F-A.2/F-D will resolve preset → specs via build_preset_specs RPC and |
| 53 | + // fan out into Node[] additions. Stub for now. |
| 54 | + }, []); |
| 55 | + |
| 56 | + const handleRunPipeline = useCallback((_mode: RunMode) => { |
| 57 | + // F-D wires this to JSON-RPC pipeline.run; for now we only flag intent. |
| 58 | + }, []); |
| 59 | + |
33 | 60 | return ( |
34 | 61 | <ReactFlowProvider> |
35 | | - <div style={{ display: "flex", height: "100vh", margin: 0 }}> |
36 | | - <Palette /> |
37 | | - <FlowCanvas |
38 | | - nodes={nodes} |
39 | | - edges={edges} |
40 | | - onConnect={handleConnect} |
41 | | - onDropBrick={handleDropBrick} |
| 62 | + <div style={{ display: "flex", flexDirection: "column", |
| 63 | + height: "100vh", margin: 0 }}> |
| 64 | + <TopBar |
| 65 | + state={spec} |
| 66 | + projectName={projectName} |
| 67 | + presets={PRESETS} |
| 68 | + topologies={TOPOLOGIES} |
| 69 | + onProjectNameChange={setProjectName} |
| 70 | + onPresetDrop={handlePresetDrop} |
| 71 | + onTopologyChange={(t) => dispatch({ type: "sharding.set", |
| 72 | + sharding: { ...spec.sharding, topology: t } })} |
| 73 | + onCompileModeChange={(m) => dispatch({ type: "sharding.set", |
| 74 | + sharding: { ...spec.sharding, compile_mode: m } })} |
| 75 | + onRunPipeline={handleRunPipeline} |
42 | 76 | /> |
| 77 | + <div style={{ flex: 1, display: "flex", minHeight: 0 }}> |
| 78 | + <Palette /> |
| 79 | + <FlowCanvas |
| 80 | + nodes={nodes} edges={edges} |
| 81 | + onConnect={handleConnect} |
| 82 | + onDropBrick={handleDropBrick} |
| 83 | + /> |
| 84 | + <Sidebar |
| 85 | + loss={spec.loss} |
| 86 | + optim={spec.optim} |
| 87 | + rewriters={spec.rewriters} |
| 88 | + sharding={spec.sharding} |
| 89 | + gotchas={spec.gotchas} |
| 90 | + proposals={proposals} |
| 91 | + onLossApply={(l) => dispatch({ type: "loss.set", loss: l })} |
| 92 | + onOptimApply={(o) => dispatch({ type: "optim.set", optim: o })} |
| 93 | + onRewriterAdd={(r) => dispatch({ type: "rewriters.add", rewriter: r })} |
| 94 | + onRewriterRemove={(i) => dispatch({ type: "rewriters.remove", index: i })} |
| 95 | + onRewriterReorder={(f, t) => |
| 96 | + dispatch({ type: "rewriters.reorder", from: f, to: t })} |
| 97 | + onShardingChange={(s) => |
| 98 | + dispatch({ type: "sharding.set", sharding: s })} |
| 99 | + onShardingAccept={(_idx) => { /* F-D wires accept → topology update */ }} |
| 100 | + /> |
| 101 | + </div> |
| 102 | + <BottomStrip state={spec} fusedRegionCount={0} /> |
43 | 103 | </div> |
44 | 104 | </ReactFlowProvider> |
45 | 105 | ); |
|
0 commit comments