removed chat and advanced components from side bar and flow declarations

This commit is contained in:
anovazzi1 2023-03-06 17:41:48 -03:00
commit edd987f9b2
9 changed files with 194 additions and 462 deletions

View file

@ -1,45 +0,0 @@
import { CheckCircleIcon, TrashIcon } from "@heroicons/react/24/outline";
import { Handle, Position } from "reactflow";
import { isValidConnection, nodeColors } from "../../utils";
import ToggleComponent from "../../components/toggleComponent";
import { useContext, useState } from "react";
import { typesContext } from "../../contexts/typesContext";
import { NodeDataType } from "../../types/flow";
export default function BooleanNode({ data }:{data:NodeDataType}) {
const [enabled, setEnabled] = useState(false);
const {types, deleteNode, reactFlowInstance} = useContext(typesContext);
return (
<div className="prompt-node relative bg-white dark:bg-gray-900 rounded-lg solid border dark:border-gray-700 flex flex-col justify-center">
<div className="w-full flex items-center justify-between gap-8 p-4 bg-gray-50 dark:bg-gray-800 dark:text-white dark:border-b-gray-700 border-b ">
<div className="flex items-center gap-4 text-lg">
<CheckCircleIcon
className="w-10 h-10 p-1 rounded"
style={{ color: nodeColors[types[data.type]] }}
/>
Boolean
</div>
<button
onClick={() => {
deleteNode(data.id);
}}
>
<TrashIcon className="text-gray-600 w-6 h-6 hover:text-red-500"></TrashIcon>
</button>
</div>
<div className="w-full flex justify-center p-5 h-full">
<ToggleComponent enabled={enabled} disabled={false} setEnabled={(x) => {setEnabled(x); data.value = x}} />
</div>
<Handle
type="source"
position={Position.Right}
id={data.type}
isValidConnection={(connection) => isValidConnection(connection,reactFlowInstance)}
className={"-mr-0.5 w-3 h-3 rounded-full border-2 bg-white dark:bg-gray-800"}
style={{
borderColor: nodeColors[types[data.type]],
}}
></Handle>
</div>
);
}

View file

@ -1,55 +0,0 @@
import {
Bars3CenterLeftIcon,
} from "@heroicons/react/24/outline";
import { isValidConnection, nodeColors } from "../../utils";
import { Handle, Position } from "reactflow";
import Tooltip from "../../components/TooltipComponent";
import { typesContext } from "../../contexts/typesContext";
import { useContext } from "react";
import { NodeDataType } from "../../types/flow";
export default function ChatInputNode({ data }:{data:NodeDataType}) {
const { types,reactFlowInstance } = useContext(typesContext);
return (
<div
className="prompt-node relative rounded-lg solid border flex justify-center align-center py-3 px-6 bg-gray-50 dark:bg-gray-800 dark:border-gray-700"
style={{ color: nodeColors[types[data.type]] }}
>
<Tooltip title="Prefix: str">
<Handle
type="target"
isValidConnection={(connection) =>
isValidConnection(connection,reactFlowInstance)
}
position={Position.Left}
id={"str|Prefix|" + data.id}
className={"-ml-0.5 w-3 h-3 rounded-full border-2 bg-white dark:bg-gray-800"}
style={{
borderColor: nodeColors[types[data.type]],
}}
></Handle>
</Tooltip>
<Tooltip title={"Message: str"}>
<Handle
type="source"
isValidConnection={(connection) =>
isValidConnection(connection,reactFlowInstance)
}
position={Position.Right}
id={"str|str|" + data.id}
className={"-mr-0.5 w-3 h-3 rounded-full border-2 bg-white dark:bg-gray-800"}
style={{
borderColor: nodeColors[types[data.type]],
}}
></Handle>
</Tooltip>
<div
className="flex gap-3 text-lg font-medium items-center"
style={{ color: nodeColors[types[data.type]] }}
>
<Bars3CenterLeftIcon className="h-8 w-8 mt-1" />
Input
</div>
</div>
);
}

View file

@ -1,33 +0,0 @@
import { Bars3CenterLeftIcon } from "@heroicons/react/24/outline";
import { Handle, Position } from "reactflow";
import { isValidConnection, nodeColors } from "../../utils";
import Tooltip from "../../components/TooltipComponent";
import { useContext } from "react";
import { typesContext } from "../../contexts/typesContext";
import { NodeDataType } from "../../types/flow";
export default function ChatOutputNode({ data }:{data:NodeDataType}) {
const {types,reactFlowInstance} = useContext(typesContext);
return (
<div className="prompt-node relative rounded-lg solid border flex justify-center align-center py-3 px-6 bg-gray-50 dark:bg-gray-800 dark:border-gray-700" style={{color: nodeColors[types[data.type]]}}>
<Tooltip title="Message: str">
<Handle
type="target"
isValidConnection={(connection) => isValidConnection(connection,reactFlowInstance)}
position={Position.Left}
id={"str|output|"+data.id}
className={"-ml-0.5 w-3 h-3 rounded-full border-2 bg-white dark:bg-gray-800"
}
style={{
borderColor: nodeColors[types[data.type]],
}}
></Handle>
</Tooltip>
<div className="flex gap-3 text-lg font-medium items-center" style={{color: nodeColors[types[data.type]]}}>
Output
<Bars3CenterLeftIcon className="h-8 w-8 mt-1" />
</div>
</div>
);
}

View file

@ -1,71 +0,0 @@
import { Bars3CenterLeftIcon, TrashIcon } from "@heroicons/react/24/outline";
import InputComponent from "../../components/inputComponent";
import {
isValidConnection,
nodeColors,
} from "../../utils";
import { Handle, Position } from "reactflow";
import { useContext } from "react";
import Tooltip from "../../components/TooltipComponent";
import { typesContext } from "../../contexts/typesContext";
import { NodeDataType } from "../../types/flow";
export default function InputNode({ data }:{data:NodeDataType}) {
console.log(data)
const {types, deleteNode,reactFlowInstance} = useContext(typesContext);
return (
<div className="prompt-node relative bg-white dark:bg-gray-900 w-96 rounded-lg solid border dark:border-gray-700 flex flex-col justify-center">
<Tooltip title="Prefix: str">
<Handle
type="target"
position={Position.Left}
id={"str|Prefix|" + data.id}
isValidConnection={(connection) =>
isValidConnection(connection,reactFlowInstance)
}
className={"-ml-0.5 w-3 h-3 rounded-full border-2 bg-white dark:bg-gray-800"}
style={{
borderColor: nodeColors[types[data.type]],
}}
></Handle>
</Tooltip>
<div className="w-full flex items-center justify-between p-4 gap-8 bg-gray-50 dark:bg-gray-800 dark:text-white border-b dark:border-b-gray-700 ">
<div className="flex items-center gap-4 text-lg">
<Bars3CenterLeftIcon
className="w-10 h-10 p-1 rounded"
style={{ color: nodeColors[types[data.type]] }}
/>
String
</div>
<button
onClick={() => {
deleteNode(data.id)
}}
>
<TrashIcon className="text-gray-600 w-6 h-6 hover:text-red-500"></TrashIcon>
</button>
</div>
<div className="w-full p-5 h-full">
<InputComponent
disabled={false}
value=""
onChange={(e) => {
data.value = e;
}}
/>
</div>
<Handle
type="source"
position={Position.Right}
id={data.type}
isValidConnection={(connection) => isValidConnection(connection,reactFlowInstance)}
className={"-mr-0.5 w-3 h-3 rounded-full border-2 bg-white dark:bg-gray-800"}
style={{
borderColor: nodeColors[types[data.type]],
}}
></Handle>
</div>
);
}

View file

@ -21,8 +21,8 @@ export default function ExtraSidebar() {
} flex-shrink-0 flex overflow-hidden flex-col border-r dark:border-r-gray-700 transition-all duration-500`}
>
<div className="w-60 dark:bg-gray-800 border dark:border-gray-700 overflow-y-auto scrollbar-hide h-full flex flex-col items-start">
<div className="flex pt-4 px-4 justify-between align-middle w-full">
<span className="text-gray-900 dark:text-white text-lg ml-2 font-semibold">
<div className="flex pt-1 px-4 justify-between align-middle w-full">
<span className="text-gray-900 dark:text-white text-lg ml-2 font-medium ">
{extraNavigation.title}
</span>
</div>

View file

@ -15,6 +15,7 @@ export default function Header(){
const {layerProps,renderLayer, triggerProps} = useLayer({
isOpen,
placement: "left-start",
auto:true,
onOutsideClick:()=>setIsOpen(false),
preferX: "left",
triggerOffset: 10,

View file

@ -1,8 +1,8 @@
import { Transition } from "@headlessui/react";
import {
Bars3CenterLeftIcon,
PaperAirplaneIcon,
XMarkIcon,
Bars3CenterLeftIcon,
PaperAirplaneIcon,
XMarkIcon,
} from "@heroicons/react/24/outline";
import { useContext, useEffect, useRef, useState } from "react";
import { sendAll } from "../../controllers/NodesServices";
@ -13,170 +13,190 @@ import { ChatType } from "../../types/chat";
const _ = require("lodash");
export default function Chat({flow, reactFlowInstance }:ChatType) {
const {updateFlow} = useContext(TabsContext)
const [saveChat,setSaveChat] = useState(false)
const [open, setOpen] = useState(true);
const [chatValue, setChatValue] = useState("");
const [chatHistory, setChatHistory] = useState(flow.chat);
const {setErrorData} = useContext(alertContext);
const addChatHistory = (message:string, isSend:boolean) => {
setChatHistory((old) => {
let newChat = _.cloneDeep(old);
newChat.push({ message, isSend });
return newChat;
});
setSaveChat(chat=>!chat)
};
useEffect(()=>{
updateFlow({..._.cloneDeep(flow),chat:chatHistory})
// eslint-disable-next-line react-hooks/exhaustive-deps
},[saveChat])
useEffect(()=>{
setChatHistory(flow.chat)
},[flow])
useEffect(()=>{
if(ref.current)
ref.current.scrollIntoView({behavior: 'smooth'});
}, [chatHistory])
function validateNodes(){
if(reactFlowInstance.getNodes().some((n) => (n.data.node && Object.keys(n.data.node.template).some((t: any) => ((n.data.node.template[t].required && n.data.node.template[t].value === "") && (n.data.node.template[t].required && !reactFlowInstance.getEdges().some((e) => (e.sourceHandle.split('|')[1] === t && e.sourceHandle.split('|')[2] === n.id)))))))){
return false;
}
return true;
}
function validateChatNodes(){
if(!reactFlowInstance.getNodes().some((n)=> (n.type === 'chatOutputNode'))){
return false;
}
return true;
}
const ref = useRef(null);
export default function Chat({ flow, reactFlowInstance }: ChatType) {
const { updateFlow } = useContext(TabsContext);
const [saveChat, setSaveChat] = useState(false);
const [open, setOpen] = useState(true);
const [chatValue, setChatValue] = useState("");
const [chatHistory, setChatHistory] = useState(flow.chat);
const { setErrorData } = useContext(alertContext);
const addChatHistory = (message: string, isSend: boolean) => {
setChatHistory((old) => {
let newChat = _.cloneDeep(old);
newChat.push({ message, isSend });
return newChat;
});
setSaveChat((chat) => !chat);
};
useEffect(() => {
updateFlow({ ..._.cloneDeep(flow), chat: chatHistory });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [saveChat]);
useEffect(() => {
setChatHistory(flow.chat);
}, [flow]);
useEffect(() => {
if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" });
}, [chatHistory]);
function validateNodes() {
if (
reactFlowInstance
.getNodes()
.some(
(n) =>
n.data.node &&
Object.keys(n.data.node.template).some(
(t: any) =>
n.data.node.template[t].required &&
n.data.node.template[t].value === "" &&
n.data.node.template[t].required &&
!reactFlowInstance
.getEdges()
.some(
(e) =>
e.sourceHandle.split("|")[1] === t &&
e.sourceHandle.split("|")[2] === n.id
)
)
)
) {
return false;
}
return true;
}
const ref = useRef(null);
function sendMessage(){
if(chatValue !== ""){
if(validateNodes()){
if(validateChatNodes()){
let message = chatValue;
setChatValue("");
addChatHistory(message, true);
console.log({...reactFlowInstance.toObject(),message,chatHistory})
sendAll({...reactFlowInstance.toObject(),message,chatHistory}).then((r) => {addChatHistory(r.data.result, false);});
} else {
setErrorData({title: 'Error sending message', list:['Chat nodes are missing.']})
}
} else {
setErrorData({title: 'Error sending message', list:['There are required fields not filled yet.']})
}
} else {
setErrorData({title: 'Error sending message', list:['The message cannot be empty.']})
}
}
function sendMessage() {
if (chatValue !== "") {
if (validateNodes()) {
let message = chatValue;
setChatValue("");
addChatHistory(message, true);
console.log({ ...reactFlowInstance.toObject(), message, chatHistory });
sendAll({ ...reactFlowInstance.toObject(), message, chatHistory }).then(
(r) => {
addChatHistory(r.data.result, false);
}
);
} else {
setErrorData({
title: "Error sending message",
list: ["There are required fields not filled yet."],
});
}
} else {
setErrorData({
title: "Error sending message",
list: ["The message cannot be empty."],
});
}
}
return (
<>
<Transition
show={open}
appear={true}
enter="transition ease-out duration-300"
enterFrom="translate-y-96"
enterTo="translate-y-0"
leave="transition ease-in duration-300"
leaveFrom="translate-y-0"
leaveTo="translate-y-96"
>
<div className="w-[400px] absolute bottom-0 right-6">
<div className="border dark:border-gray-700 h-full rounded-xl rounded-b-none bg-white dark:bg-gray-800 shadow">
<div className="flex justify-between items-center px-5 py-3 border-b dark:border-b-gray-700">
<div className="flex gap-3 text-xl dark:text-white font-medium items-center">
<Bars3CenterLeftIcon className="h-8 w-8 mt-1" style={{color: nodeColors['chat']}} />
Chat
</div>
<button
onClick={() => {
setOpen(false);
}}
>
<XMarkIcon className="h-6 w-6 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" />
</button>
</div>
<div className="w-full h-[400px] flex gap-3 mb-auto overflow-y-auto scrollbar-hide flex-col bg-gray-50 dark:bg-gray-900 p-3 py-5">
{chatHistory.map((c, i) => (
<div key={i}>
{!c.isSend ? (
<div className="w-full text-start">
<div style={{backgroundColor: nodeColors['chat']}} className="text-start inline-block text-white rounded-xl p-3 overflow-hidden w-fit max-w-[280px] px-5 text-sm font-normal rounded-tl-none">
{c.message}
</div>
</div>
) : (
<div className="w-full text-end">
<div className="text-start inline-block rounded-xl p-3 overflow-hidden w-fit max-w-[280px] px-5 text-sm text-black dark:text-white dark:bg-gray-700 bg-gray-200 font-normal rounded-tr-none">
{c.message}
</div>
</div>
)}
</div>
))}
<div ref={ref}></div>
</div>
<div className="w-full bg-white dark:bg-gray-800 border-t dark:border-t-gray-600 flex items-center justify-between p-3">
<div className="relative w-full mt-1 rounded-md shadow-sm">
<input
onKeyDown={(event)=>{
if(event.key==='Enter'){
sendMessage()
}
}}
type="text"
value={chatValue}
onChange={(e) => {
setChatValue(e.target.value);
}}
className="form-input block w-full rounded-md border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white pr-10 sm:text-sm"
placeholder="Send a message..."
/>
<div className="absolute inset-y-0 right-0 flex items-center pr-3">
<button
onClick={() => sendMessage()}
>
<PaperAirplaneIcon
className="h-5 w-5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
aria-hidden="true"
/>
</button>
</div>
</div>
</div>
</div>
</div>
</Transition>
<Transition
show={!open}
appear={true}
enter="transition ease-out duration-300"
enterFrom="translate-y-96"
enterTo="translate-y-0"
leave="transition ease-in duration-300"
leaveFrom="translate-y-0"
leaveTo="translate-y-96"
>
<div className="absolute bottom-0 right-6">
<div className="border flex justify-center align-center py-2 px-4 rounded-xl rounded-b-none bg-white dark:bg-gray-800 dark:border-gray-600 dark:text-white shadow">
<button
onClick={() => {
setOpen(true);
}}
>
<div className="flex gap-3 text-lg font-medium items-center">
<Bars3CenterLeftIcon className="h-8 w-8 mt-1" style={{color: nodeColors['chat']}}/>
Chat
</div>
</button>
</div>
</div>
</Transition>
</>
);
return (
<>
<Transition
show={open}
appear={true}
enter="transition ease-out duration-300"
enterFrom="translate-y-96"
enterTo="translate-y-0"
leave="transition ease-in duration-300"
leaveFrom="translate-y-0"
leaveTo="translate-y-96"
>
<div className="w-[340px] absolute bottom-0 right-6">
<div className="border dark:border-gray-700 h-full rounded-xl rounded-b-none bg-white dark:bg-gray-800 shadow">
<div onClick={() => {
setOpen(false);
}} className="flex justify-between cursor-pointer items-center px-5 py-2 border-b dark:border-b-gray-700">
<div className="flex gap-3 text-lg dark:text-white font-medium items-center">
<Bars3CenterLeftIcon
className="h-5 w-5 mt-1"
style={{ color: nodeColors["chat"] }}
/>
Chat
</div>
</div>
<div className="w-full h-[400px] flex gap-3 mb-auto overflow-y-auto scrollbar-hide flex-col bg-gray-50 dark:bg-gray-900 p-3 py-5">
{chatHistory.map((c, i) => (
<div key={i}>
{!c.isSend ? (
<div className="w-full text-start">
<div
style={{ backgroundColor: nodeColors["chat"] }}
className="text-start inline-block text-white rounded-xl p-3 overflow-hidden w-fit max-w-[280px] px-5 text-sm font-normal rounded-tl-none"
>
{c.message}
</div>
</div>
) : (
<div className="w-full text-end">
<div className="text-start inline-block rounded-xl p-3 overflow-hidden w-fit max-w-[280px] px-5 text-sm text-black dark:text-white dark:bg-gray-700 bg-gray-200 font-normal rounded-tr-none">
{c.message}
</div>
</div>
)}
</div>
))}
<div ref={ref}></div>
</div>
<div className="w-full bg-white dark:bg-gray-800 border-t dark:border-t-gray-600 flex items-center justify-between p-3">
<div className="relative w-full mt-1 rounded-md shadow-sm">
<input
onKeyDown={(event) => {
if (event.key === "Enter") {
sendMessage();
}
}}
type="text"
value={chatValue}
onChange={(e) => {
setChatValue(e.target.value);
}}
className="form-input block w-full rounded-md border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white pr-10 sm:text-sm"
placeholder="Send a message..."
/>
<div className="absolute inset-y-0 right-0 flex items-center pr-3">
<button onClick={() => sendMessage()}>
<PaperAirplaneIcon
className="h-5 w-5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
aria-hidden="true"
/>
</button>
</div>
</div>
</div>
</div>
</div>
</Transition>
<Transition
show={!open}
appear={true}
enter="transition ease-out duration-300"
enterFrom="translate-y-96"
enterTo="translate-y-0"
leave="transition ease-in duration-300"
leaveFrom="translate-y-0"
leaveTo="translate-y-96"
>
<div className="absolute bottom-0 right-6">
<div className="border flex justify-center align-center py-2 px-4 rounded-xl rounded-b-none bg-white dark:bg-gray-800 dark:border-gray-600 dark:text-white shadow">
<button
onClick={() => {
setOpen(true);
}}
>
<div className="flex gap-3 text-lg font-medium items-center">
<Bars3CenterLeftIcon
className="h-8 w-8 mt-1"
style={{ color: nodeColors["chat"] }}
/>
Chat
</div>
</button>
</div>
</div>
</Transition>
</>
);
}

View file

@ -16,12 +16,6 @@ export default function ExtraSidebar() {
useEffect(() => {
async function getTypes():Promise<void>{
// Define an object with initial values for the types.
const initialValue:{[char: string]: string} = {
str: "advanced",
bool: "advanced",
chatOutput: "chat",
}
// Make an asynchronous API call to retrieve all data.
let result = await getAll();
@ -41,8 +35,7 @@ export default function ExtraSidebar() {
});
});
return acc;
},
initialValue
},{}
)
);
}
@ -58,7 +51,7 @@ export default function ExtraSidebar() {
}
return (
<div className="mt-4 w-full">
<div className="mt-1 w-full">
{Object.keys(data).map((d:keyof APIObjectType, i) => (
<DisclosureComponent
key={i}
@ -88,69 +81,6 @@ export default function ExtraSidebar() {
</div>
</DisclosureComponent>
))}
<DisclosureComponent
button={{ title: nodeNames["chat"], Icon: nodeIcons["chat"] }}
>
<div className="p-2 flex flex-col gap-2">
<div>
<div
draggable
className={" cursor-grab border-l-8 rounded-l-md"}
style={{ borderLeftColor: nodeColors["chat"] }}
onDragStart={(event) =>
onDragStart(event, {
type: "chatOutput",
})
}
>
<div className="flex w-full justify-between text-sm px-4 py-3 items-center dark:border-gray-600 border-dashed border-gray-400 border-l-0 rounded-md rounded-l-none border-2">
<span className="text-black dark:text-white w-36 truncate">Chat Output</span>
<Bars2Icon className="w-6 h-6 text-gray-400 dark:text-gray-600" />
</div>
</div>
</div>
</div>
</DisclosureComponent>
<DisclosureComponent
button={{ title: nodeNames["advanced"], Icon: nodeIcons["advanced"] }}
>
<div className="p-2 flex flex-col gap-2">
<div>
<div
draggable
className={" cursor-grab border-l-8 rounded-l-md"}
style={{ borderLeftColor: nodeColors["advanced"] }}
onDragStart={(event) =>
onDragStart(event, {
type: "str",
})
}
>
<div className="flex w-full justify-between text-sm px-4 py-3 items-center border-dashed dark:border-gray-600 border-gray-400 border-l-0 rounded-md rounded-l-none border-2">
<span className="text-black dark:text-white w-36 truncate">String</span>
<Bars2Icon className="w-6 h-6 text-gray-400 dark:text-gray-600" />
</div>
</div>
</div>
<div>
<div
draggable
className={" cursor-grab border-l-8 rounded-l-md"}
style={{ borderLeftColor: nodeColors["advanced"] }}
onDragStart={(event) =>
onDragStart(event, {
type: "bool",
})
}
>
<div className="flex w-full justify-between text-sm px-4 py-3 items-center border-dashed dark:border-gray-600 border-gray-400 border-l-0 rounded-md rounded-l-none border-2">
<span className="text-black dark:text-white w-36 truncate">Boolean</span>
<Bars2Icon className="w-6 h-6 text-gray-400 dark:text-gray-600" />
</div>
</div>
</div>
</div>
</DisclosureComponent>
</div>
);
}

View file

@ -14,10 +14,6 @@ import { locationContext } from "../../contexts/locationContext";
import ExtraSidebar from "./components/extraSidebarComponent";
import Chat from "../../components/chatComponent";
import GenericNode from "../../CustomNodes/GenericNode";
import ChatInputNode from "../../CustomNodes/ChatInputNode";
import ChatOutputNode from "../../CustomNodes/ChatOutputNode";
import InputNode from "../../CustomNodes/InputNode";
import BooleanNode from "../../CustomNodes/BooleanNode";
import { alertContext } from "../../contexts/alertContext";
import { TabsContext } from "../../contexts/tabsContext";
import { typesContext } from "../../contexts/typesContext";
@ -31,10 +27,6 @@ import { APIClassType } from "../../types/api";
const nodeTypes = {
genericNode: GenericNode,
inputNode: InputNode,
chatInputNode: ChatInputNode,
chatOutputNode: ChatOutputNode,
booleanNode: BooleanNode,
};
var _ = require("lodash");
@ -74,7 +66,7 @@ export default function FlowPage({ flow }:{flow:FlowType}) {
//set extra sidebar
useEffect(() => {
setExtraComponent(<ExtraSidebar />);
setExtraNavigation({ title: "Componets" });
setExtraNavigation({ title: "Components" });
}, [setExtraComponent, setExtraNavigation]);
const onEdgesChangeMod = useCallback(
@ -139,14 +131,7 @@ export default function FlowPage({ flow }:{flow:FlowType}) {
// Create a new node object
const newNode:NodeType = {
id: newId,
type:
data.type === "str"
? "inputNode"
: data.type === "chatOutput"
? "chatOutputNode"
: data.type === "bool"
? "booleanNode"
: "genericNode",
type: "genericNode",
position,
data: {
...data,