From 6093acc8130a5e20f3b41ee86406ff6033492024 Mon Sep 17 00:00:00 2001 From: Aarushi <50577581+aarushik93@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:03:10 +0100 Subject: [PATCH] Add more functionality to Nodes (#7278) updating node behaviour --- .../src/components/CustomNode.tsx | 183 ++++++++++++++---- .../src/components/ModalComponent.tsx | 40 ++++ .../src/components/customnode.css | 143 ++++++++++++++ rnd/autogpt_builder/src/components/modal.css | 34 ++++ 4 files changed, 363 insertions(+), 37 deletions(-) create mode 100644 rnd/autogpt_builder/src/components/ModalComponent.tsx create mode 100644 rnd/autogpt_builder/src/components/customnode.css create mode 100644 rnd/autogpt_builder/src/components/modal.css diff --git a/rnd/autogpt_builder/src/components/CustomNode.tsx b/rnd/autogpt_builder/src/components/CustomNode.tsx index 522cd7863..f401efbf5 100644 --- a/rnd/autogpt_builder/src/components/CustomNode.tsx +++ b/rnd/autogpt_builder/src/components/CustomNode.tsx @@ -1,15 +1,21 @@ import React, { useState, useEffect, FC, memo } from 'react'; import { Handle, Position, NodeProps } from 'reactflow'; import 'reactflow/dist/style.css'; +import './customnode.css'; +import ModalComponent from './ModalComponent'; type Schema = { + type: string; properties: { [key: string]: any }; + required?: string[]; }; -const CustomNode: FC = ({ data }) => { +const CustomNode: FC = ({ data, id }) => { const [isPropertiesOpen, setIsPropertiesOpen] = useState(data.isPropertiesOpen || false); + const [isModalOpen, setIsModalOpen] = useState(false); + const [activeKey, setActiveKey] = useState(null); + const [modalValue, setModalValue] = useState(''); - // Automatically open properties when output_data or status is updated useEffect(() => { if (data.output_data || data.status) { setIsPropertiesOpen(true); @@ -24,7 +30,7 @@ const CustomNode: FC = ({ data }) => { if (!schema?.properties) return null; const keys = Object.keys(schema.properties); return keys.map((key) => ( -
+
{type === 'target' && ( <> = ({ data }) => { id={key} style={{ background: '#555', borderRadius: '50%' }} /> - {key} + {key} )} {type === 'source' && ( <> - {key} + {key} = ({ data }) => { }; const isHandleConnected = (key: string) => { - return data.connections.some((conn: string) => { - const [, target] = conn.split(' -> '); + return data.connections && data.connections.some((conn: string) => { + const [source, target] = conn.split(' -> '); return target.includes(key) && target.includes(data.title); }); }; - const hasDisconnectedHandle = (key: string) => { - return !isHandleConnected(key); + const handleInputClick = (key: string) => { + setActiveKey(key); + setModalValue(data.hardcodedValues[key] || ''); + setIsModalOpen(true); + }; + + const handleModalSave = (value: string) => { + if (activeKey) { + handleInputChange(activeKey, value); + } + setIsModalOpen(false); + setActiveKey(null); + }; + + const renderInputField = (key: string, schema: any) => { + switch (schema.type) { + case 'string': + return schema.enum ? ( +
+ +
+ ) : ( +
+
handleInputClick(key)}> + {data.hardcodedValues[key] || `Enter ${key}`} +
+
+ ); + case 'boolean': + return ( +
+ + +
+ ); + case 'integer': + case 'number': + return ( +
+ handleInputChange(key, parseFloat(e.target.value))} + className="number-input" + /> +
+ ); + case 'array': + if (schema.items && schema.items.type === 'string' && schema.items.enum) { + return ( +
+ +
+ ); + } + return null; + default: + return null; + } }; return ( -
-
-
- {data?.title.replace(/\d+/g, '')} -
-
-
-
- {data.inputSchema && generateHandles(data.inputSchema, 'target')} - {data.inputSchema && Object.keys(data.inputSchema.properties).map(key => ( - hasDisconnectedHandle(key) && ( -
- handleInputChange(key, e.target.value)} - style={{ width: '100%', padding: '5px', borderRadius: '4px', border: '1px solid #555', background: '#444', color: '#e0e0e0' }} - /> +
+
+ {data.inputSchema && + Object.keys(data.inputSchema.properties).map((key) => ( +
+
+ + {key} +
+ {!isHandleConnected(key) && renderInputField(key, data.inputSchema.properties[key])}
- ) - ))} + ))}
-
+
{data.outputSchema && generateHandles(data.outputSchema, 'source')}
{isPropertiesOpen && ( -
+

Node Output

-

Status: {typeof data.status === 'object' ? JSON.stringify(data.status) : data.status || 'N/A'}

-

Output Data: {typeof data.output_data === 'object' ? JSON.stringify(data.output_data) : data.output_data || 'N/A'}

+

+ Status:{' '} + {typeof data.status === 'object' ? JSON.stringify(data.status) : data.status || 'N/A'} +

+

+ Output Data:{' '} + {typeof data.output_data === 'object' + ? JSON.stringify(data.output_data) + : data.output_data || 'N/A'} +

)} + setIsModalOpen(false)} + onSave={handleModalSave} + value={modalValue} + />
); }; diff --git a/rnd/autogpt_builder/src/components/ModalComponent.tsx b/rnd/autogpt_builder/src/components/ModalComponent.tsx new file mode 100644 index 000000000..3c2ac13f2 --- /dev/null +++ b/rnd/autogpt_builder/src/components/ModalComponent.tsx @@ -0,0 +1,40 @@ +import React, { FC } from 'react'; +import './modal.css'; + +interface ModalProps { + isOpen: boolean; + onClose: () => void; + onSave: (value: string) => void; + value: string; +} + +const ModalComponent: FC = ({ isOpen, onClose, onSave, value }) => { + const [tempValue, setTempValue] = React.useState(value); + + const handleSave = () => { + onSave(tempValue); + onClose(); + }; + + if (!isOpen) { + return null; + } + + return ( +
+
+