summaryrefslogtreecommitdiff
path: root/frontend/src/App.tsx
diff options
context:
space:
mode:
authorblackhao <13851610112@163.com>2025-12-06 01:30:57 -0600
committerblackhao <13851610112@163.com>2025-12-06 01:30:57 -0600
commit93dbe11014cf967690727c25e89d9d1075008c24 (patch)
treee168becbfff0e699f49021c1b3de6918e7f0a124 /frontend/src/App.tsx
parentbcb44d5a7c4b17afd7ba64be5b497d74afc69fb6 (diff)
Diffstat (limited to 'frontend/src/App.tsx')
-rw-r--r--frontend/src/App.tsx115
1 files changed, 96 insertions, 19 deletions
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 8c52751..9ec1340 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -13,6 +13,7 @@ import 'reactflow/dist/style.css';
import useFlowStore from './store/flowStore';
import LLMNode from './components/nodes/LLMNode';
import Sidebar from './components/Sidebar';
+import LeftSidebar from './components/LeftSidebar';
import { ContextMenu } from './components/ContextMenu';
import { Plus } from 'lucide-react';
@@ -31,12 +32,19 @@ function Flow() {
deleteEdge,
deleteNode,
deleteBranch,
- setSelectedNode
+ setSelectedNode,
+ toggleNodeDisabled,
+ archiveNode,
+ createNodeFromArchive,
+ toggleTraceDisabled
} = useFlowStore();
const reactFlowWrapper = useRef<HTMLDivElement>(null);
const { project } = useReactFlow();
const [menu, setMenu] = useState<{ x: number; y: number; type: 'pane' | 'node' | 'edge'; id?: string } | null>(null);
+
+ const [isLeftOpen, setIsLeftOpen] = useState(true);
+ const [isRightOpen, setIsRightOpen] = useState(true);
const onPaneClick = () => {
setSelectedNode(null);
@@ -73,6 +81,7 @@ function Flow() {
systemPrompt: '',
userPrompt: '',
mergeStrategy: 'smart',
+ reasoningEffort: 'medium', // Default for reasoning models
messages: [],
traces: [],
outgoingTraces: [],
@@ -86,12 +95,44 @@ function Flow() {
};
const onNodeClick = (_: any, node: Node) => {
+ // Don't select disabled nodes
+ const nodeData = node.data as any;
+ if (nodeData?.disabled) return;
setSelectedNode(node.id);
};
+ const onDragOver = (event: React.DragEvent) => {
+ event.preventDefault();
+ event.dataTransfer.dropEffect = 'copy';
+ };
+
+ const onDrop = (event: React.DragEvent) => {
+ event.preventDefault();
+
+ const archiveId = event.dataTransfer.getData('archiveId');
+ if (!archiveId) return;
+
+ const bounds = reactFlowWrapper.current?.getBoundingClientRect();
+ if (!bounds) return;
+
+ const position = project({
+ x: event.clientX - bounds.left,
+ y: event.clientY - bounds.top
+ });
+
+ createNodeFromArchive(archiveId, position);
+ };
+
return (
<div style={{ width: '100vw', height: '100vh', display: 'flex' }}>
- <div style={{ flex: 1, height: '100%' }} ref={reactFlowWrapper}>
+ <LeftSidebar isOpen={isLeftOpen} onToggle={() => setIsLeftOpen(!isLeftOpen)} />
+
+ <div
+ style={{ flex: 1, height: '100%', position: 'relative' }}
+ ref={reactFlowWrapper}
+ onDragOver={onDragOver}
+ onDrop={onDrop}
+ >
<ReactFlow
nodes={nodes}
edges={edges}
@@ -139,28 +180,64 @@ function Flow() {
}
}
}
- ] : menu.type === 'node' ? [
- {
- label: 'Delete Node (Cascade)',
- danger: true,
- onClick: () => menu.id && deleteBranch(menu.id)
- }
- ] : [
- {
- label: 'Disconnect',
- onClick: () => menu.id && deleteEdge(menu.id)
- },
- {
- label: 'Delete Branch',
- danger: true,
- onClick: () => menu.id && deleteBranch(undefined, menu.id)
+ ] : menu.type === 'node' ? (() => {
+ const targetNode = nodes.find(n => n.id === menu.id);
+ const isDisabled = targetNode?.data?.disabled;
+
+ // If disabled, only show Enable option
+ if (isDisabled) {
+ return [
+ {
+ label: 'Enable Node',
+ onClick: () => menu.id && toggleNodeDisabled(menu.id)
+ }
+ ];
}
- ]
+
+ // Normal node menu
+ return [
+ {
+ label: 'Disable Node',
+ onClick: () => menu.id && toggleNodeDisabled(menu.id)
+ },
+ {
+ label: 'Add to Archive',
+ onClick: () => menu.id && archiveNode(menu.id)
+ },
+ {
+ label: 'Delete Node (Cascade)',
+ danger: true,
+ onClick: () => menu.id && deleteBranch(menu.id)
+ }
+ ];
+ })() : (() => {
+ // Check if any node connected to this edge is disabled
+ const targetEdge = edges.find(e => e.id === menu.id);
+ const sourceNode = nodes.find(n => n.id === targetEdge?.source);
+ const targetNode = nodes.find(n => n.id === targetEdge?.target);
+ const isTraceDisabled = sourceNode?.data?.disabled || targetNode?.data?.disabled;
+
+ return [
+ {
+ label: isTraceDisabled ? 'Enable Trace' : 'Disable Trace',
+ onClick: () => menu.id && toggleTraceDisabled(menu.id)
+ },
+ {
+ label: 'Disconnect',
+ onClick: () => menu.id && deleteEdge(menu.id)
+ },
+ {
+ label: 'Delete Branch',
+ danger: true,
+ onClick: () => menu.id && deleteBranch(undefined, menu.id)
+ }
+ ];
+ })()
}
/>
)}
</div>
- <Sidebar />
+ <Sidebar isOpen={isRightOpen} onToggle={() => setIsRightOpen(!isRightOpen)} />
</div>
);
}