Inputs and outputs lines implemented at the generic node

This commit is contained in:
Lucas Oliveira 2023-02-17 00:16:52 -03:00
commit 61e56659aa
2 changed files with 101 additions and 34 deletions

View file

@ -0,0 +1,54 @@
import { Handle, Position, useUpdateNodeInternals } from "reactflow";
import Tooltip from "../../../../components/TooltipComponent";
import {
isValidConnection,
nodeColors,
snakeToNormalCase,
} from "../../../../utils";
import { useEffect, useRef, useState } from "react";
export default function ParameterComponent({
left,
id,
data,
tooltipTitle,
title,
color,
}) {
const ref = useRef(null);
const updateNodeInternals = useUpdateNodeInternals();
const [position, setPosition] = useState(0);
useEffect(() => {
if (ref.current && ref.current.offsetTop && ref.current.clientHeight) {
setPosition(ref.current.offsetTop + (ref.current.clientHeight / 2));
updateNodeInternals(data.id);
}
}, [data.id, ref, updateNodeInternals]);
useEffect(() => {
updateNodeInternals(data.id);
}, [data.id, position, updateNodeInternals])
return (
<div ref={ref} className="w-full bg-gray-50 mt-1 px-5 py-2">
<>
<div className="text-sm truncate">{title}</div>
<Tooltip title={tooltipTitle}>
<Handle
type={left ? "source" : "target"}
position={left ? Position.Left : Position.Right}
id={id}
isValidConnection={(connection) =>
isValidConnection(data, connection)
}
className={(left ? "-ml-0.5 " : "-mr-0.5 ") +"w-3 h-3 rounded-full border-2 bg-white"}
style={{
borderColor: color,
top: position,
}}
></Handle>
</Tooltip>
</>
</div>
);
}

View file

@ -6,60 +6,73 @@ import {
import { Handle, Position } from "reactflow"; import { Handle, Position } from "reactflow";
import Dropdown from "../../components/dropdownComponent"; import Dropdown from "../../components/dropdownComponent";
import Input from "../../components/inputComponent"; import Input from "../../components/inputComponent";
import { isValidConnection, nodeColors, nodeIcons, snakeToNormalCase } from "../../utils"; import {
isValidConnection,
nodeColors,
nodeIcons,
snakeToNormalCase,
} from "../../utils";
import Tooltip from "../../components/TooltipComponent"; import Tooltip from "../../components/TooltipComponent";
import { useEffect } from "react"; import { useEffect, useRef, useState } from "react";
import ParameterComponent from "./components/parameterComponent";
export default function GenericNode({ data }) { export default function GenericNode({ data }) {
const Icon = nodeIcons[data.type]; const Icon = nodeIcons[data.type];
return ( return (
<div className="prompt-node relative bg-white w-96 rounded-lg solid border flex flex-col justify-center"> <div className="prompt-node relative bg-white w-96 rounded-lg solid border flex flex-col justify-center">
<div className="w-full flex items-center justify-between p-4 gap-8 bg-gray-50 border-b "> <div className="w-full flex items-center justify-between p-4 gap-8 bg-gray-50 border-b ">
<div className="flex items-center gap-4 text-lg"> <div className="w-full flex items-center truncate gap-4 text-lg">
<Icon <Icon
className="w-10 h-10 p-1 text-white rounded" className="w-10 h-10 p-1 text-white rounded"
style={{ background: nodeColors[data.type] }} style={{ background: nodeColors[data.type] }}
/> />
{data.name} <div className="truncate">{data.name}</div>
</div> </div>
<button onClick={data.onDelete}> <button onClick={data.onDelete}>
<TrashIcon className="w-6 h-6 hover:text-red-500"></TrashIcon> <TrashIcon className="w-6 h-6 hover:text-red-500"></TrashIcon>
</button> </button>
</div> </div>
<div className="w-full p-5 h-full"> <div className="w-full h-full py-5 pointer-events-none">
<div className="w-full text-gray-500 text-sm"> <div className="w-full text-gray-500 px-5 text-sm">
{data.node.description} {data.node.description}
</div> </div>
<div className="px-5 py-2 mt-2 text-center">Inputs:</div>
<>
{Object.keys(data.node.template).map((t, idx) => ( {Object.keys(data.node.template).map((t, idx) => (
<div key={idx} className="w-full mt-5"> <ParameterComponent
<Tooltip title={t + ": " + data.node.template[t].type + (data.node.template[t].list ? " list" : "") + (data.node.template[t].required ? " (required)" : "")}> key={idx}
<Handle data={data}
type="source" color={
position={Position.Left} nodeColors[
data.types[data.node.template[t].type] ??
data.node.template[t].type
] ?? "gray"
}
title={snakeToNormalCase(t)}
tooltipTitle={
t +
": " +
data.node.template[t].type +
(data.node.template[t].list ? " list" : "") +
(data.node.template[t].required ? " (required)" : "")
}
id={data.node.template[t].type + "|" + t + "|" + data.id} id={data.node.template[t].type + "|" + t + "|" + data.id}
isValidConnection={(connection) => isValidConnection(data,connection)} left={true}
className="ml-1 bg-transparent border-solid border-l-8 border-y-transparent border-y-8 border-r-0 rounded-none" />
style={{
borderLeftColor: (nodeColors[(data.types[data.node.template[t].type] ?? data.node.template[t].type)]) ?? "gray",
marginTop: idx * 30 - 50 + "px",
}}
></Handle>
</Tooltip>
</div>
))} ))}
<div className="w-full mt-5"></div> <div className="px-5 py-2 mt-2 text-center">Output:</div>
</div> <ParameterComponent
<Tooltip title={"Output: " + data.name}> data={data}
<Handle color={nodeColors[data.type]}
type="target" title={data.name}
position={Position.Right} tooltipTitle={"Output: " + data.name}
id={data.name} id={data.name}
isValidConnection={(connection) => isValidConnection(data,connection)} left={false}
className="-mr-1 bg-transparent border-solid border-l-8 border-y-transparent border-y-8 border-r-0 rounded-none" />
style={{ borderLeftColor: nodeColors[data.type] }} </>
></Handle> </div>
</Tooltip>
</div> </div>
); );
} }