mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-30 03:00:41 -04:00
rebuild graphs on api call + pos and metadata
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Handle, Position, NodeProps } from 'reactflow';
|
||||
import 'reactflow/dist/style.css';
|
||||
|
||||
@@ -7,7 +7,14 @@ type Schema = {
|
||||
};
|
||||
|
||||
const CustomNode: React.FC<NodeProps> = ({ data }) => {
|
||||
const [isPropertiesOpen, setIsPropertiesOpen] = useState(false);
|
||||
const [isPropertiesOpen, setIsPropertiesOpen] = useState(data.isPropertiesOpen || false);
|
||||
|
||||
// Automatically open properties when output_data or status is updated
|
||||
useEffect(() => {
|
||||
if (data.output_data || data.status) {
|
||||
setIsPropertiesOpen(true);
|
||||
}
|
||||
}, [data.output_data, data.status]);
|
||||
|
||||
const toggleProperties = () => {
|
||||
setIsPropertiesOpen(!isPropertiesOpen);
|
||||
@@ -56,6 +63,10 @@ const CustomNode: React.FC<NodeProps> = ({ data }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const hasDisconnectedHandle = (key: string) => {
|
||||
return !isHandleConnected(key) && !data.connections.some((conn: string) => conn.includes(key));
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px', border: '2px solid #fff', borderRadius: '20px', background: '#333', color: '#e0e0e0', width: '250px' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}>
|
||||
@@ -73,7 +84,7 @@ const CustomNode: React.FC<NodeProps> = ({ data }) => {
|
||||
<div>
|
||||
{data.inputSchema && generateHandles(data.inputSchema, 'target')}
|
||||
{data.inputSchema && Object.keys(data.inputSchema.properties).map(key => (
|
||||
(!isHandleConnected(key) || data.connections.length === 0) && (
|
||||
(hasDisconnectedHandle(key) || data.connections.length === 0) && (
|
||||
<div key={key} style={{ marginBottom: '5px' }}>
|
||||
<input
|
||||
type="text"
|
||||
@@ -92,10 +103,9 @@ const CustomNode: React.FC<NodeProps> = ({ data }) => {
|
||||
</div>
|
||||
{isPropertiesOpen && (
|
||||
<div style={{ marginTop: '10px', background: '#444', padding: '10px', borderRadius: '10px' }}>
|
||||
<h4>Node Properties</h4>
|
||||
<p><strong>Name:</strong> {data.title}</p>
|
||||
<p><strong>Description:</strong> {data.description}</p>
|
||||
{/* Add more properties here if needed */}
|
||||
<h4>Node Output</h4>
|
||||
<p><strong>Status:</strong> {data.status || 'N/A'}</p>
|
||||
<p><strong>Output Data:</strong> {data.output_data || 'N/A'}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@ import ReactFlow, {
|
||||
OnEdgesChange,
|
||||
OnConnect,
|
||||
NodeTypes,
|
||||
EdgeRemoveChange,
|
||||
} from 'reactflow';
|
||||
import 'reactflow/dist/style.css';
|
||||
import Modal from 'react-modal';
|
||||
@@ -68,8 +69,24 @@ const Flow: React.FC = () => {
|
||||
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
|
||||
[]
|
||||
);
|
||||
|
||||
const onEdgesChange: OnEdgesChange = useCallback(
|
||||
(changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
|
||||
(changes) => {
|
||||
const removedEdges = changes.filter((change): change is EdgeRemoveChange => change.type === 'remove');
|
||||
setEdges((eds) => applyEdgeChanges(changes, eds));
|
||||
|
||||
if (removedEdges.length > 0) {
|
||||
setNodes((nds) =>
|
||||
nds.map((node) => {
|
||||
const updatedConnections = node.data.connections.filter(
|
||||
(conn: string) =>
|
||||
!removedEdges.some((edge) => edge.id && conn.includes(edge.id))
|
||||
);
|
||||
return { ...node, data: { ...node.data, connections: updatedConnections } };
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
@@ -123,8 +140,11 @@ const Flow: React.FC = () => {
|
||||
));
|
||||
},
|
||||
block_id: nodeSchema?.id || '',
|
||||
metadata: {
|
||||
position: { x: Math.random() * 400, y: Math.random() * 400 }, // Move position to metadata
|
||||
}
|
||||
},
|
||||
position: { x: Math.random() * 400, y: Math.random() * 400 },
|
||||
position: { x: Math.random() * 400, y: Math.random() * 400 }, // Provide default value for React Flow
|
||||
};
|
||||
setNodes((nds) => [...nds, newNode]);
|
||||
setNodeId((id) => id + 1);
|
||||
@@ -180,6 +200,58 @@ const Flow: React.FC = () => {
|
||||
return inputData;
|
||||
};
|
||||
|
||||
const updateNodeData = (execData: any) => {
|
||||
setNodes((nds) =>
|
||||
nds.map((node) => {
|
||||
if (node.id === execData.node_id) {
|
||||
return {
|
||||
...node,
|
||||
data: {
|
||||
...node.data,
|
||||
status: execData.status,
|
||||
output_data: execData.output_data,
|
||||
isPropertiesOpen: true, // Open the properties
|
||||
},
|
||||
};
|
||||
}
|
||||
return node;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const resetGraph = (newNodes: any[]) => {
|
||||
setNodes(newNodes.map((node) => ({
|
||||
id: node.id,
|
||||
type: 'custom',
|
||||
data: {
|
||||
...node.input_default,
|
||||
label: node.id,
|
||||
title: node.block_id,
|
||||
description: node.description || '',
|
||||
connections: [],
|
||||
variableName: node.variableName || '',
|
||||
variableValue: node.variableValue || '',
|
||||
printVariable: node.printVariable || '',
|
||||
block_id: node.block_id,
|
||||
metadata: node.metadata,
|
||||
setVariableName,
|
||||
setVariableValue,
|
||||
setPrintVariable,
|
||||
setHardcodedValues: (values: { [key: string]: any }) => {
|
||||
setNodes((nds) =>
|
||||
nds.map((n) =>
|
||||
n.id === node.id
|
||||
? { ...n, data: { ...n.data, hardcodedValues: values } }
|
||||
: n
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
position: node.metadata.position,
|
||||
})));
|
||||
setEdges([]);
|
||||
};
|
||||
|
||||
const runAgent = async () => {
|
||||
try {
|
||||
const formattedNodes = nodes.map(node => ({
|
||||
@@ -198,6 +270,10 @@ const Flow: React.FC = () => {
|
||||
}
|
||||
return acc;
|
||||
}, {} as { [key: string]: string }),
|
||||
metadata: {
|
||||
...node.data.metadata,
|
||||
position: node.position, // Include position in metadata
|
||||
}
|
||||
}));
|
||||
|
||||
const payload = {
|
||||
@@ -228,7 +304,6 @@ const Flow: React.FC = () => {
|
||||
return acc;
|
||||
}, {} as { [key: string]: any });
|
||||
|
||||
// Ensure the top-level structure of the input matches the expected schema
|
||||
const nodeInputForExecution = Object.keys(initialNodeInput).reduce((acc, key) => {
|
||||
const blockId = nodes.find(node => node.id === key)?.data.block_id;
|
||||
const nodeSchema = availableNodes.find(n => n.id === blockId);
|
||||
@@ -271,22 +346,7 @@ const Flow: React.FC = () => {
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const updatedNodes = nodes.map(node => {
|
||||
const nodeExecution = data.find((exec: any) => exec.node_id === node.id);
|
||||
if (nodeExecution) {
|
||||
return {
|
||||
...node,
|
||||
data: {
|
||||
...node.data,
|
||||
status: nodeExecution.status,
|
||||
output_data: nodeExecution.output_data,
|
||||
},
|
||||
};
|
||||
}
|
||||
return node;
|
||||
});
|
||||
|
||||
setNodes(updatedNodes);
|
||||
data.forEach(updateNodeData);
|
||||
|
||||
const allCompleted = data.every((exec: any) => exec.status === 'COMPLETED');
|
||||
if (allCompleted) {
|
||||
@@ -350,7 +410,7 @@ const Flow: React.FC = () => {
|
||||
</div>
|
||||
<div style={{ height: '100%', width: '100%' }}>
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
nodes={nodes.map(node => ({ ...node, position: node.data.metadata.position }))}
|
||||
edges={edges}
|
||||
nodeTypes={nodeTypes}
|
||||
onNodesChange={onNodesChange}
|
||||
|
||||
Reference in New Issue
Block a user