List logic implemented at the nodes

This commit is contained in:
Lucas Oliveira 2023-02-16 14:06:11 -03:00
commit 2a0547279c
9 changed files with 331 additions and 299 deletions

View file

@ -1,7 +1,7 @@
import { Bars3CenterLeftIcon, TrashIcon } from "@heroicons/react/24/outline";
import { Input } from "@mui/material";
import { Handle, Position } from "reactflow";
import { nodeColors } from "../../utils";
import { isValidConnection, nodeColors } from "../../utils";
import ToggleComponent from "../../components/toggleComponent";
import { useEffect, useState } from "react";
@ -32,11 +32,7 @@ export default function BooleanNode({ data }) {
type="target"
position={Position.Right}
id={data.name}
isValidConnection={({ sourceHandle, targetHandle }) =>
targetHandle === sourceHandle ||
data.types[targetHandle] === sourceHandle ||
sourceHandle === "str"
}
isValidConnection={(connection) => isValidConnection(data,connection)}
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>

View file

@ -1,6 +1,6 @@
import { ChatBubbleBottomCenterTextIcon } from "@heroicons/react/24/outline";
import Input from "../../components/inputComponent";
import { snakeToNormalCase } from "../../utils";
import { isValidConnection, snakeToNormalCase } from "../../utils";
import { Handle, Position } from "reactflow";
import Tooltip from "../../components/TooltipComponent";
@ -11,8 +11,8 @@ export default function ChatInputNode({ data }) {
<Handle
type="target"
position={Position.Right}
id={data.name}
isValidConnection={({sourceHandle, targetHandle}) => (targetHandle === sourceHandle || data.types[targetHandle] === sourceHandle || sourceHandle === 'str')}
id='str'
isValidConnection={(connection) => isValidConnection(data,connection)}
className="-mr-1 bg-transparent border-solid border-l-8 border-l-blue-600 border-y-transparent border-y-8 border-r-0 rounded-none"
></Handle>
</Tooltip>

View file

@ -1,7 +1,7 @@
import { ChatBubbleBottomCenterTextIcon } from "@heroicons/react/24/outline";
import { Handle, Position } from "reactflow";
import Input from "../../components/inputComponent";
import { snakeToNormalCase } from "../../utils";
import { isValidConnection, snakeToNormalCase } from "../../utils";
import Tooltip from "../../components/TooltipComponent";
export default function ChatOutputNode({ data }) {
@ -10,13 +10,9 @@ export default function ChatOutputNode({ data }) {
<Tooltip title="Message: str">
<Handle
type="source"
isValidConnection={({ sourceHandle, targetHandle }) =>
targetHandle === sourceHandle ||
data.types[targetHandle] === sourceHandle ||
sourceHandle === "str"
}
isValidConnection={(connection) => isValidConnection(data,connection)}
position={Position.Left}
id="str"
id={"str|output|"+data.id}
className="ml-1 bg-transparent border-solid border-l-8 border-l-white border-y-transparent border-y-8 border-r-0 rounded-none"
></Handle>
</Tooltip>

View file

@ -6,8 +6,9 @@ import {
import { Handle, Position } from "reactflow";
import Dropdown from "../../components/dropdownComponent";
import Input from "../../components/inputComponent";
import { nodeColors, nodeIcons, snakeToNormalCase } from "../../utils";
import { isValidConnection, nodeColors, nodeIcons, snakeToNormalCase } from "../../utils";
import Tooltip from "../../components/TooltipComponent";
import { useEffect } from "react";
export default function GenericNode({ data }) {
const Icon = nodeIcons[data.type];
@ -36,12 +37,8 @@ export default function GenericNode({ data }) {
<Handle
type="source"
position={Position.Left}
id={data.node.template[t].type}
isValidConnection={({ sourceHandle, targetHandle }) =>
targetHandle === sourceHandle ||
data.types[targetHandle] === sourceHandle ||
sourceHandle === "str"
}
id={data.node.template[t].type + "|" + t + "|" + data.id}
isValidConnection={(connection) => isValidConnection(data,connection)}
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",
@ -58,11 +55,7 @@ export default function GenericNode({ data }) {
type="target"
position={Position.Right}
id={data.name}
isValidConnection={({ sourceHandle, targetHandle }) =>
targetHandle === sourceHandle ||
data.types[targetHandle] === sourceHandle ||
sourceHandle === "str"
}
isValidConnection={(connection) => isValidConnection(data,connection)}
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>

View file

@ -1,6 +1,6 @@
import { Bars3CenterLeftIcon, TrashIcon } from "@heroicons/react/24/outline";
import Input from "../../components/inputComponent";
import { nodeColors, nodeIcons, snakeToNormalCase } from "../../utils";
import { isValidConnection, nodeColors, nodeIcons, snakeToNormalCase } from "../../utils";
import { Handle, Position } from "reactflow";
import { useEffect } from "react";
@ -34,7 +34,7 @@ export default function InputNode({ data }) {
type="target"
position={Position.Right}
id={data.name}
isValidConnection={({sourceHandle, targetHandle}) => (targetHandle === sourceHandle || data.types[targetHandle] === sourceHandle || sourceHandle === 'str')}
isValidConnection={(connection) => isValidConnection(data,connection)}
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>

View file

@ -71,7 +71,6 @@ export default function ExtraSidebar() {
onDragStart(event, {
type: 'elements',
name: 'str',
types: types
})
}
>

View file

@ -74,7 +74,7 @@ export default function FlowPage() {
id: newId,
type: data.name === 'str' ? 'inputNode' : (data.name === 'chatInput' ? 'chatInputNode' : (data.name === 'chatOutput' ? 'chatOutputNode' : (data.name === 'bool' ? 'booleanNode' : 'genericNode'))),
position,
data: { ...data, input: '', enabled: false, instance: reactFlowInstance, onDelete: () => {setNodes(reactFlowInstance.getNodes().filter((n)=>n.id !== newId))} },
data: { ...data, id: newId, input: '', enabled: false, reactFlowInstance, onDelete: () => {setNodes(reactFlowInstance.getNodes().filter((n)=>n.id !== newId))} },
};
setNodes((nds) => nds.concat(newNode));
},

View file

@ -1,57 +1,65 @@
import { RocketLaunchIcon, LinkIcon, CpuChipIcon, LightBulbIcon, CommandLineIcon, WrenchScrewdriverIcon, ComputerDesktopIcon } from "@heroicons/react/24/outline";
import {
RocketLaunchIcon,
LinkIcon,
CpuChipIcon,
LightBulbIcon,
CommandLineIcon,
WrenchScrewdriverIcon,
ComputerDesktopIcon,
} from "@heroicons/react/24/outline";
import { Edge, Node } from "reactflow";
export function classNames(...classes) {
return classes.filter(Boolean).join(" ");
}
export const textColors = {
white: "text-white",
red: "text-red-700",
orange: "text-orange-700",
amber: "text-amber-700",
yellow: "text-yellow-700",
lime: "text-lime-700",
green: "text-green-700",
emerald: "text-emerald-700",
teal: "text-teal-700",
cyan: "text-cyan-700",
sky: "text-sky-700",
blue: "text-blue-700",
indigo: "text-indigo-700",
violet: "text-violet-700",
purple: "text-purple-700",
fuchsia: "text-fuchsia-700",
pink: "text-pink-700",
rose: "text-rose-700",
black: "text-black-700",
gray: "text-gray-700",
};
return classes.filter(Boolean).join(" ");
}
export const borderLColors = {
white: "border-l-white",
red: "border-l-red-500",
orange: "border-l-orange-500",
amber: "border-l-amber-500",
yellow: "border-l-yellow-500",
lime: "border-l-lime-500",
green: "border-l-green-500",
emerald: "border-l-emerald-500",
teal: "border-l-teal-500",
cyan: "border-l-cyan-500",
sky: "border-l-sky-500",
blue: "border-l-blue-500",
indigo: "border-l-indigo-500",
violet: "border-l-violet-500",
purple: "border-l-purple-500",
fuchsia: "border-l-fuchsia-500",
pink: "border-l-pink-500",
rose: "border-l-rose-500",
black: "border-l-black-500",
gray: "border-l-gray-500",
};
export const textColors = {
white: "text-white",
red: "text-red-700",
orange: "text-orange-700",
amber: "text-amber-700",
yellow: "text-yellow-700",
lime: "text-lime-700",
green: "text-green-700",
emerald: "text-emerald-700",
teal: "text-teal-700",
cyan: "text-cyan-700",
sky: "text-sky-700",
blue: "text-blue-700",
indigo: "text-indigo-700",
violet: "text-violet-700",
purple: "text-purple-700",
fuchsia: "text-fuchsia-700",
pink: "text-pink-700",
rose: "text-rose-700",
black: "text-black-700",
gray: "text-gray-700",
};
/* export const nodeColors = {
export const borderLColors = {
white: "border-l-white",
red: "border-l-red-500",
orange: "border-l-orange-500",
amber: "border-l-amber-500",
yellow: "border-l-yellow-500",
lime: "border-l-lime-500",
green: "border-l-green-500",
emerald: "border-l-emerald-500",
teal: "border-l-teal-500",
cyan: "border-l-cyan-500",
sky: "border-l-sky-500",
blue: "border-l-blue-500",
indigo: "border-l-indigo-500",
violet: "border-l-violet-500",
purple: "border-l-purple-500",
fuchsia: "border-l-fuchsia-500",
pink: "border-l-pink-500",
rose: "border-l-rose-500",
black: "border-l-black-500",
gray: "border-l-gray-500",
};
/* export const nodeColors = {
prompt: "#35ADAE",
model: "#4266BE",
chain: "#6344BE",
@ -60,7 +68,7 @@ export function classNames(...classes) {
memory: "#FF3434",
} */
/* export const nodeColors = {
/* export const nodeColors = {
prompt: "#36D635",
model: "#4266BE",
chain: "#903BBE",
@ -69,7 +77,7 @@ export function classNames(...classes) {
memory: "#FFFF33",
} */
/* export const nodeColors = {
/* export const nodeColors = {
prompt: "#36D635",
model: "#35ADAE",
chain: "#903BBE",
@ -78,7 +86,7 @@ export function classNames(...classes) {
memory: "#FFDC35",
} */
/* export const nodeColors = {
/* export const nodeColors = {
prompt: "#36D635",
model: "#35ADAE",
chain: "#903BBE",
@ -87,227 +95,267 @@ export function classNames(...classes) {
memory: "#FF9135",
} */
export const nodeColors = {
prompts: "#7C7C7C",
llms: "#35ADAE",
chains: "#FFDC35",
agents: "#903BBE",
tools: "#FF3434",
memories: "#FF9135",
elements: "#6344BE"
}
export const nodeColors = {
prompts: "#7C7C7C",
llms: "#35ADAE",
chains: "#FFDC35",
agents: "#903BBE",
tools: "#FF3434",
memories: "#FF9135",
elements: "#6344BE",
};
export const nodeNames = {
prompts: "Prompts",
llms: "LLMs",
chains: "Chains",
agents: "Agents",
tools: "Tools",
memories: "Memories",
elements: "Elements",
}
export const nodeNames = {
prompts: "Prompts",
llms: "LLMs",
chains: "Chains",
agents: "Agents",
tools: "Tools",
memories: "Memories",
elements: "Elements",
};
export const nodeIcons = {
agents: RocketLaunchIcon,
chains: LinkIcon,
memories: CpuChipIcon,
llms: LightBulbIcon,
prompts: CommandLineIcon,
tools: WrenchScrewdriverIcon,
elements: ComputerDesktopIcon,
};
export const nodeIcons = {
agents: RocketLaunchIcon,
chains: LinkIcon,
memories: CpuChipIcon,
llms: LightBulbIcon,
prompts: CommandLineIcon,
tools: WrenchScrewdriverIcon,
elements: ComputerDesktopIcon
export const bgColors = {
white: "bg-white",
red: "bg-red-100",
orange: "bg-orange-100",
amber: "bg-amber-100",
yellow: "bg-yellow-100",
lime: "bg-lime-100",
green: "bg-green-100",
emerald: "bg-emerald-100",
teal: "bg-teal-100",
cyan: "bg-cyan-100",
sky: "bg-sky-100",
blue: "bg-blue-100",
indigo: "bg-indigo-100",
violet: "bg-violet-100",
purple: "bg-purple-100",
fuchsia: "bg-fuchsia-100",
pink: "bg-pink-100",
rose: "bg-rose-100",
black: "bg-black-100",
gray: "bg-gray-100",
};
export const bgColorsHover = {
white: "hover:bg-white",
black: "hover:bg-black-50",
gray: "hover:bg-gray-50",
red: "hover:bg-red-50",
orange: "hover:bg-orange-50",
amber: "hover:bg-amber-50",
yellow: "hover:bg-yellow-50",
lime: "hover:bg-lime-50",
green: "hover:bg-green-50",
emerald: "hover:bg-emerald-50",
teal: "hover:bg-teal-50",
cyan: "hover:bg-cyan-50",
sky: "hover:bg-sky-50",
blue: "hover:bg-blue-50",
indigo: "hover:bg-indigo-50",
violet: "hover:bg-violet-50",
purple: "hover:bg-purple-50",
fuchsia: "hover:bg-fuchsia-50",
pink: "hover:bg-pink-50",
rose: "hover:bg-rose-50",
};
export const textColorsHex = {
red: "rgb(185 28 28)",
orange: "rgb(194 65 12)",
amber: "rgb(180 83 9)",
yellow: "rgb(161 98 7)",
lime: "rgb(77 124 15)",
green: "rgb(21 128 61)",
emerald: "rgb(4 120 87)",
teal: "rgb(15 118 110)",
cyan: "rgb(14 116 144)",
sky: "rgb(3 105 161)",
blue: "rgb(29 78 216)",
indigo: "rgb(67 56 202)",
violet: "rgb(109 40 217)",
purple: "rgb(126 34 206)",
fuchsia: "rgb(162 28 175)",
pink: "rgb(190 24 93)",
rose: "rgb(190 18 60)",
};
export const bgColorsHex = {
red: "rgb(254 226 226)",
orange: "rgb(255 237 213)",
amber: "rgb(254 243 199)",
yellow: "rgb(254 249 195)",
lime: "rgb(236 252 203)",
green: "rgb(220 252 231)",
emerald: "rgb(209 250 229)",
teal: "rgb(204 251 241)",
cyan: "rgb(207 250 254)",
sky: "rgb(224 242 254)",
blue: "rgb(219 234 254)",
indigo: "rgb(224 231 255)",
violet: "rgb(237 233 254)",
purple: "rgb(243 232 255)",
fuchsia: "rgb(250 232 255)",
pink: "rgb(252 231 243)",
rose: "rgb(255 228 230)",
};
export const taskTypeMap: { [key: string]: string } = {
MULTICLASS_CLASSIFICATION: "Multiclass Classification",
};
const charWidths = {
" ": 0.2,
"!": 0.2,
'"': 0.3,
"#": 0.5,
$: 0.5,
"%": 0.5,
"&": 0.5,
"(": 0.2,
")": 0.2,
"*": 0.5,
"+": 0.5,
",": 0.2,
"-": 0.2,
".": 0.1,
"/": 0.5,
":": 0.2,
";": 0.2,
"<": 0.5,
"=": 0.5,
">": 0.5,
"?": 0.2,
"@": 0.5,
"[": 0.2,
"\\": 0.5,
"]": 0.2,
"^": 0.5,
_: 0.2,
"`": 0.5,
"{": 0.2,
"|": 0.2,
"}": 0.2,
"~": 0.5,
};
for (let i = 65; i <= 90; i++) {
charWidths[String.fromCharCode(i)] = 0.6;
}
for (let i = 97; i <= 122; i++) {
charWidths[String.fromCharCode(i)] = 0.5;
}
export function measureTextWidth(text: string, fontSize) {
let wordWidth = 0;
for (let j = 0; j < text.length; j++) {
let char = text[j];
let charWidth = charWidths[char] || 0.5;
wordWidth += charWidth * fontSize;
}
export const bgColors = {
white: "bg-white",
red: "bg-red-100",
orange: "bg-orange-100",
amber: "bg-amber-100",
yellow: "bg-yellow-100",
lime: "bg-lime-100",
green: "bg-green-100",
emerald: "bg-emerald-100",
teal: "bg-teal-100",
cyan: "bg-cyan-100",
sky: "bg-sky-100",
blue: "bg-blue-100",
indigo: "bg-indigo-100",
violet: "bg-violet-100",
purple: "bg-purple-100",
fuchsia: "bg-fuchsia-100",
pink: "bg-pink-100",
rose: "bg-rose-100",
black: "bg-black-100",
gray: "bg-gray-100",
};
export const bgColorsHover = {
white: "hover:bg-white",
black: "hover:bg-black-50",
gray: "hover:bg-gray-50",
red: "hover:bg-red-50",
orange: "hover:bg-orange-50",
amber: "hover:bg-amber-50",
yellow: "hover:bg-yellow-50",
lime: "hover:bg-lime-50",
green: "hover:bg-green-50",
emerald: "hover:bg-emerald-50",
teal: "hover:bg-teal-50",
cyan: "hover:bg-cyan-50",
sky: "hover:bg-sky-50",
blue: "hover:bg-blue-50",
indigo: "hover:bg-indigo-50",
violet: "hover:bg-violet-50",
purple: "hover:bg-purple-50",
fuchsia: "hover:bg-fuchsia-50",
pink: "hover:bg-pink-50",
rose: "hover:bg-rose-50",
};
export const textColorsHex = {
red: "rgb(185 28 28)",
orange: "rgb(194 65 12)",
amber: "rgb(180 83 9)",
yellow: "rgb(161 98 7)",
lime: "rgb(77 124 15)",
green: "rgb(21 128 61)",
emerald: "rgb(4 120 87)",
teal: "rgb(15 118 110)",
cyan: "rgb(14 116 144)",
sky: "rgb(3 105 161)",
blue: "rgb(29 78 216)",
indigo: "rgb(67 56 202)",
violet: "rgb(109 40 217)",
purple: "rgb(126 34 206)",
fuchsia: "rgb(162 28 175)",
pink: "rgb(190 24 93)",
rose: "rgb(190 18 60)",
};
export const bgColorsHex = {
red: "rgb(254 226 226)",
orange: "rgb(255 237 213)",
amber: "rgb(254 243 199)",
yellow: "rgb(254 249 195)",
lime: "rgb(236 252 203)",
green: "rgb(220 252 231)",
emerald: "rgb(209 250 229)",
teal: "rgb(204 251 241)",
cyan: "rgb(207 250 254)",
sky: "rgb(224 242 254)",
blue: "rgb(219 234 254)",
indigo: "rgb(224 231 255)",
violet: "rgb(237 233 254)",
purple: "rgb(243 232 255)",
fuchsia: "rgb(250 232 255)",
pink: "rgb(252 231 243)",
rose: "rgb(255 228 230)",
};
export const taskTypeMap: { [key: string]: string } = {
MULTICLASS_CLASSIFICATION: "Multiclass Classification",
};
const charWidths = {
" ": 0.2,
"!": 0.2,
'"': 0.3,
"#": 0.5,
"$": 0.5,
"%": 0.5,
"&": 0.5,
"(": 0.2,
")": 0.2,
"*": 0.5,
"+": 0.5,
",": 0.2,
"-": 0.2,
".": 0.1,
"/": 0.5,
":": 0.2,
";": 0.2,
"<": 0.5,
"=": 0.5,
">": 0.5,
"?": 0.2,
"@": 0.5,
"[": 0.2,
"\\": 0.5,
"]": 0.2,
"^": 0.5,
"_": 0.2,
"`": 0.5,
"{": 0.2,
"|": 0.2,
"}": 0.2,
"~": 0.5,
};
for (let i = 65; i <= 90; i++) {
charWidths[String.fromCharCode(i)] = 0.6;
}
for (let i = 97; i <= 122; i++) {
charWidths[String.fromCharCode(i)] = 0.5;
}
export function measureTextWidth(text: string, fontSize) {
let wordWidth = 0;
for (let j = 0; j < text.length; j++) {
let char = text[j];
let charWidth = charWidths[char] || 0.5;
wordWidth += charWidth * fontSize;
return wordWidth;
}
export function measureTextHeight(text: string, width, fontSize) {
const charHeight = fontSize;
const lineHeight = charHeight * 1.5;
const words = text.split(" ");
let lineWidth = 0;
let totalHeight = 0;
for (let i = 0; i < words.length; i++) {
let word = words[i];
let wordWidth = measureTextWidth(word, fontSize);
if (lineWidth + wordWidth + charWidths[" "] * fontSize <= width) {
lineWidth += wordWidth + charWidths[" "] * fontSize;
} else {
totalHeight += lineHeight;
lineWidth = wordWidth;
}
return wordWidth;
}
export function measureTextHeight(text: string, width, fontSize) {
const charHeight = fontSize;
const lineHeight = charHeight * 1.5;
const words = text.split(" ");
let lineWidth = 0;
let totalHeight = 0;
for (let i = 0; i < words.length; i++) {
let word = words[i];
let wordWidth = measureTextWidth(word, fontSize);
if (lineWidth + wordWidth + charWidths[" "] * fontSize <= width) {
lineWidth += wordWidth + charWidths[" "] * fontSize;
} else {
totalHeight += lineHeight;
lineWidth = wordWidth;
totalHeight += lineHeight;
return totalHeight;
}
export function toCamelCase(str: string) {
return str
.split(" ")
.map((word, index) =>
index === 0
? word.toLowerCase()
: word[0].toUpperCase() + word.slice(1).toLowerCase()
)
.join("");
}
export function toFirstUpperCase(str: string) {
return str
.split(" ")
.map((word, index) => word[0].toUpperCase() + word.slice(1).toLowerCase())
.join("");
}
export function snakeToNormalCase(str: string) {
return str
.split("_")
.map((word, index) => {
if (index === 0) {
return word[0].toUpperCase() + word.slice(1).toLowerCase();
}
return word.toLowerCase();
})
.join(" ");
}
export function roundNumber(x, decimals) {
return Math.round(x * Math.pow(10, decimals)) / Math.pow(10, decimals);
}
export function getConnectedNodes(edge: Edge, nodes: Array<Node>): Array<Node> {
const sourceId = edge.source;
const targetId = edge.target;
const connectedNodes = nodes.filter(
(node) => node.id === sourceId || node.id === targetId
);
return connectedNodes;
}
export function isValidConnection(
data,
{ source, target, sourceHandle, targetHandle }
) {
if (
targetHandle === sourceHandle.split("|")[0] ||
sourceHandle.split("|")[0] === "str" ||
data.types[targetHandle] === sourceHandle.split("|")[0]
) {
let sourceNode = data.reactFlowInstance.getNode(source).data.node;
if (!sourceNode) {
if (
!data.reactFlowInstance
.getEdges()
.find((e) => e.sourceHandle === sourceHandle)
) {
return true;
}
} else if (
(!sourceNode.template[sourceHandle.split("|")[1]].list &&
!data.reactFlowInstance
.getEdges()
.find((e) => e.sourceHandle === sourceHandle)) ||
sourceNode.template[sourceHandle.split("|")[1]].list
) {
return true;
}
totalHeight += lineHeight;
return totalHeight;
}
export function toCamelCase(str: string){
return str
.split(' ')
.map((word, index) => (index === 0 ? word.toLowerCase() : word[0].toUpperCase() + word.slice(1).toLowerCase()))
.join('');
};
export function toFirstUpperCase(str: string){
return str
.split(' ')
.map((word, index) => (word[0].toUpperCase() + word.slice(1).toLowerCase()))
.join('');
};
export function snakeToNormalCase(str: string){
return str
.split('_')
.map((word, index) => {if(index === 0){return word[0].toUpperCase() + word.slice(1).toLowerCase()} return word.toLowerCase()})
.join(' ');
};
export function roundNumber(x, decimals){
return Math.round(x * Math.pow(10, decimals))/Math.pow(10, decimals)
}
export function getConnectedNodes(edge:Edge,nodes:Array<Node>):Array<Node>{
const sourceId = edge.source;
const targetId = edge.target;
const connectedNodes = nodes.filter(node=>node.id===sourceId||node.id===targetId)
return connectedNodes
}
return false;
}