Merge branch 'tabs' into dev
This commit is contained in:
commit
62d75a0446
16 changed files with 1025 additions and 101 deletions
58
space_flow/package-lock.json
generated
58
space_flow/package-lock.json
generated
|
|
@ -23,11 +23,13 @@
|
|||
"@types/react-dom": "^18.0.10",
|
||||
"axios": "^1.3.2",
|
||||
"react": "^18.2.0",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.7.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"react-router-dom": "^6.8.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-tabs": "^6.0.0",
|
||||
"reactflow": "^11.5.5",
|
||||
"tailwindcss": "^3.2.6",
|
||||
"typescript": "^4.9.5",
|
||||
|
|
@ -4211,6 +4213,11 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz",
|
||||
"integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow=="
|
||||
},
|
||||
"node_modules/@types/d3": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz",
|
||||
|
|
@ -4490,6 +4497,15 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/hoist-non-react-statics": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
|
||||
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/html-minifier-terser": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
|
||||
|
|
@ -14801,6 +14817,19 @@
|
|||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/react-cookie": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-4.1.1.tgz",
|
||||
"integrity": "sha512-ffn7Y7G4bXiFbnE+dKhHhbP+b8I34mH9jqnm8Llhj89zF4nPxPutxHT1suUqMeCEhLDBI7InYwf1tpaSoK5w8A==",
|
||||
"dependencies": {
|
||||
"@types/hoist-non-react-statics": "^3.0.1",
|
||||
"hoist-non-react-statics": "^3.0.0",
|
||||
"universal-cookie": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dev-utils": {
|
||||
"version": "12.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
|
||||
|
|
@ -15070,6 +15099,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-tabs": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-6.0.0.tgz",
|
||||
"integrity": "sha512-8jKLKrlwxmn5/+xsa76yi27ZdB8E/WhlhQZw739O5UlOeUGtVoVeWnpqIewv/KbjTw7gQf/uA51zWUNt4IVygQ==",
|
||||
"dependencies": {
|
||||
"clsx": "^1.1.0",
|
||||
"prop-types": "^15.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
|
|
@ -16819,6 +16860,23 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/universal-cookie": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz",
|
||||
"integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.3.3",
|
||||
"cookie": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/universal-cookie/node_modules/cookie": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
|
||||
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -18,11 +18,13 @@
|
|||
"@types/react-dom": "^18.0.10",
|
||||
"axios": "^1.3.2",
|
||||
"react": "^18.2.0",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.7.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"react-router-dom": "^6.8.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-tabs": "^6.0.0",
|
||||
"reactflow": "^11.5.5",
|
||||
"tailwindcss": "^3.2.6",
|
||||
"typescript": "^4.9.5",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import { locationContext } from "./contexts/locationContext";
|
|||
import FlowPage from "./pages/FlowPage";
|
||||
import Sidebar from "./components/SidebarComponent";
|
||||
import Header from "./components/HeaderComponent";
|
||||
import { TabsProvider } from "./contexts/tabsContext";
|
||||
import { TabsManager } from "./pages/FlowPage/flowManager";
|
||||
|
||||
export default function App() {
|
||||
var _ = require("lodash");
|
||||
|
|
@ -96,7 +98,7 @@ export default function App() {
|
|||
return (
|
||||
//need parent component with width and height
|
||||
<div className="h-full flex flex-col">
|
||||
<ReactFlowProvider>
|
||||
|
||||
<div className="flex grow-0 shrink basis-auto">
|
||||
<Header userNavigation={userNavigation} user={user}></Header>
|
||||
</div>
|
||||
|
|
@ -108,7 +110,7 @@ export default function App() {
|
|||
<main className="min-w-0 flex-1 border-t border-gray-200 flex">
|
||||
{/* Primary column */}
|
||||
<div className="w-full h-full">
|
||||
<FlowPage />
|
||||
<TabsManager></TabsManager>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
|
@ -142,7 +144,6 @@ export default function App() {
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ReactFlowProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { typesContext } from "../../contexts/typesContext";
|
|||
|
||||
export default function BooleanNode({ data }) {
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
const {types} = useContext(typesContext);
|
||||
const {types, deleteNode} = useContext(typesContext);
|
||||
return (
|
||||
<div className="prompt-node relative bg-white rounded-lg solid border flex flex-col justify-center">
|
||||
<div className="w-full flex items-center justify-between gap-8 p-4 bg-gray-50 border-b ">
|
||||
|
|
@ -21,7 +21,7 @@ export default function BooleanNode({ data }) {
|
|||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
data.onDelete(data);
|
||||
deleteNode(data.id);
|
||||
}}
|
||||
>
|
||||
<TrashIcon className="text-gray-600 w-6 h-6 hover:text-red-500"></TrashIcon>
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ import {
|
|||
nodeColors,
|
||||
snakeToNormalCase,
|
||||
} from "../../../../utils";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import InputComponent from "../../../../components/inputComponent";
|
||||
import ToggleComponent from "../../../../components/toggleComponent";
|
||||
import InputListComponent from "../../../../components/inputListComponent";
|
||||
import TextAreaComponent from "../../../../components/textAreaComponent";
|
||||
import { typesContext } from "../../../../contexts/typesContext";
|
||||
|
||||
export default function ParameterComponent({
|
||||
left,
|
||||
|
|
@ -38,7 +39,8 @@ export default function ParameterComponent({
|
|||
}, [data.id, position, updateNodeInternals]);
|
||||
|
||||
const [enabled, setEnabled] = useState(data.node.template[name]?.value ?? false);
|
||||
let disabled = data.reactFlowInstance.getEdges().some((e) => (e.targetHandle === id));
|
||||
const {reactFlowInstance} = useContext(typesContext);
|
||||
let disabled = reactFlowInstance?.getEdges().some((e) => (e.targetHandle === id)) ?? false;
|
||||
|
||||
return (
|
||||
<div ref={ref} className="w-full flex flex-wrap justify-between items-center bg-gray-50 mt-1 px-5 py-2">
|
||||
|
|
@ -50,7 +52,7 @@ export default function ParameterComponent({
|
|||
position={left ? Position.Left : Position.Right}
|
||||
id={id}
|
||||
isValidConnection={(connection) =>
|
||||
isValidConnection(data, connection)
|
||||
isValidConnection(connection,reactFlowInstance)
|
||||
}
|
||||
className={
|
||||
(left ? "-ml-0.5 " : "-mr-0.5 ") +
|
||||
|
|
|
|||
|
|
@ -11,9 +11,10 @@ import { typesContext } from "../../contexts/typesContext";
|
|||
import { useContext } from "react";
|
||||
|
||||
export default function GenericNode({ data }) {
|
||||
const {types} = useContext(typesContext);
|
||||
const {types, deleteNode} = useContext(typesContext);
|
||||
const Icon = nodeIcons[types[data.type]];
|
||||
|
||||
|
||||
return (
|
||||
<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 ">
|
||||
|
|
@ -24,7 +25,7 @@ export default function GenericNode({ data }) {
|
|||
/>
|
||||
<div className="truncate">{data.type}</div>
|
||||
</div>
|
||||
<button onClick={data.onDelete}>
|
||||
<button onClick={() => {deleteNode(data.id)}}>
|
||||
<TrashIcon className="w-6 h-6 hover:text-red-500"></TrashIcon>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { typesContext } from "../../contexts/typesContext";
|
|||
import TextAreaComponent from "../../components/textAreaComponent";
|
||||
|
||||
export default function InputNode({ data }) {
|
||||
const { types } = useContext(typesContext);
|
||||
const {types, deleteNode} = useContext(typesContext);
|
||||
return (
|
||||
<div className="prompt-node relative bg-white w-96 rounded-lg solid border flex flex-col justify-center">
|
||||
<Tooltip title="Prefix: str">
|
||||
|
|
@ -39,7 +39,7 @@ export default function InputNode({ data }) {
|
|||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
data.onDelete(data);
|
||||
deleteNode(data.id)
|
||||
}}
|
||||
>
|
||||
<TrashIcon className="text-gray-600 w-6 h-6 hover:text-red-500"></TrashIcon>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { AlertProvider } from "./alertContext";
|
||||
import { LocationProvider } from "./locationContext";
|
||||
import PopUpProvider from "./popUpContext";
|
||||
import { TabsProvider } from "./tabsContext";
|
||||
import { TypesProvider } from "./typesContext";
|
||||
|
||||
export default function ContextWrapper({ children }) {
|
||||
|
|
@ -9,7 +10,9 @@ export default function ContextWrapper({ children }) {
|
|||
<LocationProvider>
|
||||
<PopUpProvider>
|
||||
<TypesProvider>
|
||||
<AlertProvider>{children}</AlertProvider>
|
||||
<TabsProvider>
|
||||
<AlertProvider>{children}</AlertProvider>
|
||||
</TabsProvider>
|
||||
</TypesProvider>
|
||||
</PopUpProvider>
|
||||
</LocationProvider>
|
||||
|
|
|
|||
95
space_flow/src/contexts/tabsContext.tsx
Normal file
95
space_flow/src/contexts/tabsContext.tsx
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import { createContext, useEffect, useState } from "react";
|
||||
|
||||
type flow={name:string,id:string,data:any}
|
||||
|
||||
type TabsContextType={
|
||||
tabIndex:number;
|
||||
setTabIndex:(index:number)=>void;
|
||||
flows:Array<flow>
|
||||
removeFlow:(id:string)=>void;
|
||||
addFlow:(flowData?:any)=>void;
|
||||
updateFlow:(newFlow:flow)=>void;
|
||||
nodeId:number;
|
||||
}
|
||||
|
||||
const TabsContextInitialValue = {
|
||||
tabIndex : 0,
|
||||
setTabIndex:(index:number)=>{},
|
||||
flows:[],
|
||||
removeFlow:(id:string)=>{},
|
||||
addFlow:(flowData?:any)=>{},
|
||||
updateFlow:(newFlow:flow)=>{},
|
||||
nodeId:0,
|
||||
|
||||
|
||||
}
|
||||
|
||||
export const TabsContext = createContext<TabsContextType>(TabsContextInitialValue)
|
||||
|
||||
export function TabsProvider({children}){
|
||||
const [tabIndex,setTabIndex] = useState(0)
|
||||
const [flows,setFlows] = useState<Array<flow>>([])
|
||||
const [id, setId] = useState(0);
|
||||
let nodeId = 0;
|
||||
useEffect(() => {
|
||||
if(flows.length !== 0)
|
||||
window.localStorage.setItem('tabsData', JSON.stringify({tabIndex, flows, id, nodeId}));
|
||||
}, [flows, id, nodeId, tabIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
let cookie = window.localStorage.getItem('tabsData');
|
||||
if(cookie){
|
||||
let cookieObject = JSON.parse(cookie);
|
||||
setTabIndex(cookieObject.tabIndex);
|
||||
setFlows(cookieObject.flows)
|
||||
setId(cookieObject.id)
|
||||
nodeId = cookieObject.nodeId
|
||||
}
|
||||
}, [])
|
||||
|
||||
function removeFlow(id:string){
|
||||
setFlows(prevState=>{
|
||||
const newFlows = [...prevState];
|
||||
const index = newFlows.findIndex(flow=>flow.id===id);
|
||||
if(index >= 0){
|
||||
if(index===tabIndex){
|
||||
setTabIndex(flows.length-2);
|
||||
newFlows.splice(index,1);
|
||||
} else {
|
||||
let flowId = flows[tabIndex].id;
|
||||
newFlows.splice(index,1);
|
||||
setTabIndex(newFlows.findIndex(flow=>flow.id === flowId));
|
||||
}
|
||||
|
||||
}
|
||||
return newFlows;
|
||||
});
|
||||
}
|
||||
function addFlow(flowData?:flow) {
|
||||
const data = flowData?flowData:null
|
||||
let newFlow: flow = {name: "flow"+id, id: id.toString(), data}
|
||||
setId((old) => old+1);
|
||||
setFlows(prevState => {
|
||||
const newFlows = [...prevState, newFlow];
|
||||
return newFlows;
|
||||
});
|
||||
setTabIndex(flows.length);
|
||||
}
|
||||
function updateFlow(newFlow:flow){
|
||||
setFlows(prevState=>{
|
||||
const newFlows = [...prevState];
|
||||
const index = newFlows.findIndex(flow=>flow.id===newFlow.id)
|
||||
if(index!==-1){
|
||||
newFlows[index].data = newFlow.data
|
||||
newFlows[index].name = newFlow.name
|
||||
}
|
||||
return newFlows;
|
||||
});
|
||||
}
|
||||
|
||||
return(
|
||||
<TabsContext.Provider value={{tabIndex,setTabIndex,flows, nodeId,removeFlow,addFlow,updateFlow}}>
|
||||
{children}
|
||||
</TabsContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,12 +1,20 @@
|
|||
import { createContext, useState } from "react";
|
||||
import { ReactEventHandler, createContext, useState } from "react";
|
||||
import { ReactFlowInstance } from "reactflow";
|
||||
|
||||
type typesContextType=
|
||||
{
|
||||
reactFlowInstance: ReactFlowInstance;
|
||||
setReactFlowInstance: any;
|
||||
deleteNode:(idx:number)=>void;
|
||||
types: {};
|
||||
setTypes:(newState:{})=>void;
|
||||
|
||||
}
|
||||
|
||||
const initialValue= {
|
||||
reactFlowInstance: null,
|
||||
setReactFlowInstance: ()=>{},
|
||||
deleteNode: ()=>{},
|
||||
types: {},
|
||||
setTypes:()=>{},
|
||||
}
|
||||
|
|
@ -15,8 +23,14 @@ export const typesContext = createContext<typesContextType>(initialValue);
|
|||
|
||||
export function TypesProvider({children}){
|
||||
const [types, setTypes] = useState({});
|
||||
const [reactFlowInstance, setReactFlowInstance] = useState(null);
|
||||
function deleteNode(idx){
|
||||
reactFlowInstance.setNodes(
|
||||
reactFlowInstance.getNodes().filter((n) => n.id !== idx)
|
||||
);
|
||||
}
|
||||
return (
|
||||
<typesContext.Provider value={{ types, setTypes}}>
|
||||
<typesContext.Provider value={{ types, setTypes, reactFlowInstance, setReactFlowInstance, deleteNode}}>
|
||||
{children}
|
||||
</typesContext.Provider>
|
||||
)
|
||||
|
|
|
|||
606
space_flow/src/data_assets/example.ts
Normal file
606
space_flow/src/data_assets/example.ts
Normal file
|
|
@ -0,0 +1,606 @@
|
|||
export const example = {
|
||||
"nodes": [
|
||||
{
|
||||
"width": 384,
|
||||
"height": 271,
|
||||
"id": "dndnode_}5",
|
||||
"type": "genericNode",
|
||||
"position": {
|
||||
"x": -640.9237482084102,
|
||||
"y": 117.60473769101873
|
||||
},
|
||||
"data": {
|
||||
"type": "ConversationBufferMemory",
|
||||
"node": {
|
||||
"template": {
|
||||
"_type": "conversation_buffer",
|
||||
"human_prefix": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": "Human"
|
||||
},
|
||||
"ai_prefix": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": "AI"
|
||||
},
|
||||
"buffer": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": ""
|
||||
},
|
||||
"output_key": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": null
|
||||
},
|
||||
"input_key": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": null
|
||||
},
|
||||
"memory_key": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": "history"
|
||||
}
|
||||
},
|
||||
"description": "Buffer for storing conversation memory.",
|
||||
"base_classes": [
|
||||
"Memory"
|
||||
]
|
||||
},
|
||||
"id": "dndnode_}5",
|
||||
"value": null
|
||||
},
|
||||
"selected": false,
|
||||
"positionAbsolute": {
|
||||
"x": -640.9237482084102,
|
||||
"y": 117.60473769101873
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"width": 384,
|
||||
"height": 447,
|
||||
"id": "dndnode_}7",
|
||||
"type": "genericNode",
|
||||
"position": {
|
||||
"x": -86,
|
||||
"y": 522
|
||||
},
|
||||
"data": {
|
||||
"type": "LLMChain",
|
||||
"node": {
|
||||
"template": {
|
||||
"_type": "llm_chain",
|
||||
"memory": {
|
||||
"type": "Memory",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multline": false,
|
||||
"value": null
|
||||
},
|
||||
"verbose": {
|
||||
"type": "bool",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multline": false,
|
||||
"value": false
|
||||
},
|
||||
"prompt": {
|
||||
"type": "BasePromptTemplate",
|
||||
"required": true,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multline": false
|
||||
},
|
||||
"llm": {
|
||||
"type": "BaseLLM",
|
||||
"required": true,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multline": false
|
||||
},
|
||||
"output_key": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": "text"
|
||||
}
|
||||
},
|
||||
"description": "Chain to run queries against LLMs.",
|
||||
"base_classes": [
|
||||
"Chain"
|
||||
]
|
||||
},
|
||||
"id": "dndnode_}7",
|
||||
"value": null
|
||||
},
|
||||
"selected": false,
|
||||
"positionAbsolute": {
|
||||
"x": -86,
|
||||
"y": 522
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"width": 384,
|
||||
"height": 357,
|
||||
"id": "dndnode_}8",
|
||||
"type": "genericNode",
|
||||
"position": {
|
||||
"x": -633.4,
|
||||
"y": 230
|
||||
},
|
||||
"data": {
|
||||
"type": "PromptTemplate",
|
||||
"node": {
|
||||
"template": {
|
||||
"_type": "prompt",
|
||||
"input_variables": {
|
||||
"type": "str",
|
||||
"required": true,
|
||||
"placeholder": "",
|
||||
"list": true,
|
||||
"show": false,
|
||||
"multline": false
|
||||
},
|
||||
"output_parser": {
|
||||
"type": "BaseOutputParser",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": null
|
||||
},
|
||||
"template": {
|
||||
"type": "str",
|
||||
"required": true,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multline": true,
|
||||
"value": "aaaaa"
|
||||
},
|
||||
"template_format": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": "f-string"
|
||||
},
|
||||
"validate_template": {
|
||||
"type": "bool",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": true
|
||||
}
|
||||
},
|
||||
"description": "Schema to represent a prompt for an LLM.",
|
||||
"base_classes": [
|
||||
"BasePromptTemplate"
|
||||
]
|
||||
},
|
||||
"id": "dndnode_}8",
|
||||
"value": null
|
||||
},
|
||||
"selected": false,
|
||||
"positionAbsolute": {
|
||||
"x": -633.4,
|
||||
"y": 230
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"width": 384,
|
||||
"height": 453,
|
||||
"id": "dndnode_}9",
|
||||
"type": "genericNode",
|
||||
"position": {
|
||||
"x": -655.1999999999999,
|
||||
"y": 615
|
||||
},
|
||||
"data": {
|
||||
"type": "AI21",
|
||||
"node": {
|
||||
"template": {
|
||||
"_type": "ai21",
|
||||
"cache": {
|
||||
"type": "bool",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": null
|
||||
},
|
||||
"verbose": {
|
||||
"type": "bool",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multline": false,
|
||||
"value": false
|
||||
},
|
||||
"model": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": "j1-jumbo"
|
||||
},
|
||||
"temperature": {
|
||||
"type": "float",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": 0.7
|
||||
},
|
||||
"maxTokens": {
|
||||
"type": "int",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": 256
|
||||
},
|
||||
"minTokens": {
|
||||
"type": "int",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": 0
|
||||
},
|
||||
"topP": {
|
||||
"type": "float",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": 1
|
||||
},
|
||||
"presencePenalty": {
|
||||
"type": "AI21PenaltyData",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": {
|
||||
"scale": 0,
|
||||
"applyToWhitespaces": true,
|
||||
"applyToPunctuations": true,
|
||||
"applyToNumbers": true,
|
||||
"applyToStopwords": true,
|
||||
"applyToEmojis": true
|
||||
}
|
||||
},
|
||||
"countPenalty": {
|
||||
"type": "AI21PenaltyData",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": {
|
||||
"scale": 0,
|
||||
"applyToWhitespaces": true,
|
||||
"applyToPunctuations": true,
|
||||
"applyToNumbers": true,
|
||||
"applyToStopwords": true,
|
||||
"applyToEmojis": true
|
||||
}
|
||||
},
|
||||
"frequencyPenalty": {
|
||||
"type": "AI21PenaltyData",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": {
|
||||
"scale": 0,
|
||||
"applyToWhitespaces": true,
|
||||
"applyToPunctuations": true,
|
||||
"applyToNumbers": true,
|
||||
"applyToStopwords": true,
|
||||
"applyToEmojis": true
|
||||
}
|
||||
},
|
||||
"numResults": {
|
||||
"type": "int",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": 1
|
||||
},
|
||||
"logitBias": {
|
||||
"type": "dict[str, float]",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": null
|
||||
},
|
||||
"ai21_api_key": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multline": false,
|
||||
"value": "aaaa"
|
||||
},
|
||||
"base_url": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": null
|
||||
}
|
||||
},
|
||||
"description": "Wrapper around AI21 large language models.To use, you should have the environment variable ``AI21_API_KEY``set with your API key.",
|
||||
"base_classes": [
|
||||
"LLM",
|
||||
"BaseLLM"
|
||||
]
|
||||
},
|
||||
"id": "dndnode_}9",
|
||||
"value": null
|
||||
},
|
||||
"selected": false,
|
||||
"positionAbsolute": {
|
||||
"x": -655.1999999999999,
|
||||
"y": 615
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"width": 384,
|
||||
"height": 351,
|
||||
"id": "dndnode_}11",
|
||||
"type": "genericNode",
|
||||
"position": {
|
||||
"x": 638.4588569554073,
|
||||
"y": 325.32407743706693
|
||||
},
|
||||
"data": {
|
||||
"type": "ZeroShotAgent",
|
||||
"node": {
|
||||
"template": {
|
||||
"_type": "zero-shot-react-description",
|
||||
"llm_chain": {
|
||||
"type": "LLMChain",
|
||||
"required": true,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multline": false
|
||||
},
|
||||
"allowed_tools": {
|
||||
"type": "Tool",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": true,
|
||||
"show": true,
|
||||
"multline": false,
|
||||
"value": null
|
||||
},
|
||||
"return_values": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": true,
|
||||
"show": false,
|
||||
"multline": false,
|
||||
"value": [
|
||||
"output"
|
||||
]
|
||||
}
|
||||
},
|
||||
"description": "Agent for the MRKL chain.",
|
||||
"base_classes": [
|
||||
"Agent"
|
||||
]
|
||||
},
|
||||
"id": "dndnode_}11",
|
||||
"value": null
|
||||
},
|
||||
"positionAbsolute": {
|
||||
"x": 638.4588569554073,
|
||||
"y": 325.32407743706693
|
||||
}
|
||||
},
|
||||
{
|
||||
"width": 384,
|
||||
"height": 283,
|
||||
"id": "dndnode_}12",
|
||||
"type": "genericNode",
|
||||
"position": {
|
||||
"x": -88.20259321315393,
|
||||
"y": 992.0115499525607
|
||||
},
|
||||
"data": {
|
||||
"type": "Requests",
|
||||
"node": {
|
||||
"template": {
|
||||
"_type": "requests"
|
||||
},
|
||||
"name": "Requests",
|
||||
"description": "A portal to the internet. Use this when you need to get specific content from a site. Input should be a specific url, and the output will be all the text on that page.",
|
||||
"base_classes": [
|
||||
"Tool"
|
||||
]
|
||||
},
|
||||
"id": "dndnode_}12",
|
||||
"value": null
|
||||
},
|
||||
"selected": false,
|
||||
"positionAbsolute": {
|
||||
"x": -88.20259321315393,
|
||||
"y": 992.0115499525607
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"width": 155,
|
||||
"height": 62,
|
||||
"id": "dndnode_}13",
|
||||
"type": "chatOutputNode",
|
||||
"position": {
|
||||
"x": 1187.9878614974666,
|
||||
"y": 492.6933173991155
|
||||
},
|
||||
"data": {
|
||||
"type": "chatOutput",
|
||||
"id": "dndnode_}13",
|
||||
"value": null
|
||||
},
|
||||
"selected": false,
|
||||
"positionAbsolute": {
|
||||
"x": 1187.9878614974666,
|
||||
"y": 492.6933173991155
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"width": 139,
|
||||
"height": 62,
|
||||
"id": "dndnode_}14",
|
||||
"type": "chatInputNode",
|
||||
"position": {
|
||||
"x": -1098.8338538506573,
|
||||
"y": 562.4305007166358
|
||||
},
|
||||
"data": {
|
||||
"type": "chatInput",
|
||||
"id": "dndnode_}14",
|
||||
"value": null
|
||||
},
|
||||
"selected": true,
|
||||
"positionAbsolute": {
|
||||
"x": -1098.8338538506573,
|
||||
"y": 562.4305007166358
|
||||
},
|
||||
"dragging": false
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "dndnode_}2",
|
||||
"sourceHandle": "PromptTemplate|example_prompt|dndnode_}2",
|
||||
"target": "dndnode_}1",
|
||||
"targetHandle": "PromptTemplate|dndnode_}1|BasePromptTemplate",
|
||||
"className": "animate-pulse",
|
||||
"id": "reactflow__edge-dndnode_}2PromptTemplate|example_prompt|dndnode_}2-dndnode_}1PromptTemplate|dndnode_}1|BasePromptTemplate"
|
||||
},
|
||||
{
|
||||
"source": "dndnode_}7",
|
||||
"sourceHandle": "BasePromptTemplate|prompt|dndnode_}7",
|
||||
"target": "dndnode_}8",
|
||||
"targetHandle": "PromptTemplate|dndnode_}8|BasePromptTemplate",
|
||||
"className": "animate-pulse",
|
||||
"id": "reactflow__edge-dndnode_}7BasePromptTemplate|prompt|dndnode_}7-dndnode_}8PromptTemplate|dndnode_}8|BasePromptTemplate"
|
||||
},
|
||||
{
|
||||
"source": "dndnode_}7",
|
||||
"sourceHandle": "BaseLLM|llm|dndnode_}7",
|
||||
"target": "dndnode_}9",
|
||||
"targetHandle": "AI21|dndnode_}9|LLM,|BaseLLM",
|
||||
"className": "animate-pulse",
|
||||
"id": "reactflow__edge-dndnode_}7BaseLLM|llm|dndnode_}7-dndnode_}9AI21|dndnode_}9|LLM,|BaseLLM"
|
||||
},
|
||||
{
|
||||
"source": "dndnode_}7",
|
||||
"sourceHandle": "Memory|memory|dndnode_}7",
|
||||
"target": "dndnode_}5",
|
||||
"targetHandle": "ConversationBufferMemory|dndnode_}5|Memory",
|
||||
"className": "animate-pulse",
|
||||
"id": "reactflow__edge-dndnode_}7Memory|memory|dndnode_}7-dndnode_}5ConversationBufferMemory|dndnode_}5|Memory"
|
||||
},
|
||||
{
|
||||
"source": "dndnode_}11",
|
||||
"sourceHandle": "LLMChain|llm_chain|dndnode_}11",
|
||||
"target": "dndnode_}7",
|
||||
"targetHandle": "LLMChain|dndnode_}7|Chain",
|
||||
"className": "animate-pulse",
|
||||
"id": "reactflow__edge-dndnode_}11LLMChain|llm_chain|dndnode_}11-dndnode_}7LLMChain|dndnode_}7|Chain"
|
||||
},
|
||||
{
|
||||
"source": "dndnode_}11",
|
||||
"sourceHandle": "Tool|allowed_tools|dndnode_}11",
|
||||
"target": "dndnode_}12",
|
||||
"targetHandle": "Requests|dndnode_}12|Tool",
|
||||
"className": "animate-pulse",
|
||||
"id": "reactflow__edge-dndnode_}11Tool|allowed_tools|dndnode_}11-dndnode_}12Requests|dndnode_}12|Tool"
|
||||
},
|
||||
{
|
||||
"source": "dndnode_}13",
|
||||
"sourceHandle": "str|output|dndnode_}13",
|
||||
"target": "dndnode_}11",
|
||||
"targetHandle": "ZeroShotAgent|dndnode_}11|Agent",
|
||||
"className": "animate-pulse",
|
||||
"id": "reactflow__edge-dndnode_}13str|output|dndnode_}13-dndnode_}11ZeroShotAgent|dndnode_}11|Agent",
|
||||
"selected": false
|
||||
}
|
||||
],
|
||||
"viewport": {
|
||||
"x": 765.8392857133035,
|
||||
"y": -83.25008407339476,
|
||||
"zoom": 0.7169776240079136
|
||||
}
|
||||
}
|
||||
|
|
@ -12,58 +12,36 @@ import { typesContext } from "../../../../contexts/typesContext";
|
|||
|
||||
export default function ExtraSidebar() {
|
||||
const [data, setData] = useState({});
|
||||
const { setTypes } = useContext(typesContext);
|
||||
const { setTypes} = useContext(typesContext);
|
||||
|
||||
async function getTypes(){
|
||||
let d = await getAll();
|
||||
setData(d.data);
|
||||
setTypes(
|
||||
Object.keys(d.data).reduce(
|
||||
(acc, curr) => {
|
||||
Object.keys(d.data[curr]).forEach((c) => {
|
||||
acc[c] = curr;
|
||||
d.data[curr][c].base_classes?.forEach((b) => {
|
||||
acc[b] = curr;
|
||||
});
|
||||
});
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
str: "advanced",
|
||||
bool: "advanced",
|
||||
chatOutput: "chat",
|
||||
chatInput: "chat",
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getAll().then((d) => {
|
||||
setData(d.data);
|
||||
setTypes(
|
||||
Object.keys(d.data).reduce(
|
||||
(acc, curr) => {
|
||||
Object.keys(d.data[curr]).forEach((c) => {
|
||||
acc[c] = curr;
|
||||
d.data[curr][c].base_classes?.forEach((b) => {
|
||||
acc[b] = curr;
|
||||
});
|
||||
});
|
||||
// console.log(acc);
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
str: "advanced",
|
||||
bool: "advanced",
|
||||
chatOutput: "chat",
|
||||
chatInput: "chat",
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
getTypes();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if(data){
|
||||
setTypes(
|
||||
Object.keys(data).reduce(
|
||||
(acc, curr) => {
|
||||
Object.keys(data[curr]).forEach((c) => {
|
||||
acc[c] = curr;
|
||||
data[curr][c].base_classes?.forEach((b) => {
|
||||
acc[b] = curr;
|
||||
});
|
||||
});
|
||||
// console.log(acc);
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
str: "advanced",
|
||||
bool: "advanced",
|
||||
chatOutput: "chat",
|
||||
chatInput: "chat",
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}, [data, setTypes])
|
||||
|
||||
function onDragStart(event: React.DragEvent<any>, data) {
|
||||
event.dataTransfer.effectAllowed = "move";
|
||||
|
|
|
|||
49
space_flow/src/pages/FlowPage/flowManager/index.tsx
Normal file
49
space_flow/src/pages/FlowPage/flowManager/index.tsx
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { useContext, useEffect } from "react";
|
||||
import { ReactFlowProvider } from "reactflow";
|
||||
import FlowPage from "..";
|
||||
import { TabsContext } from "../../../contexts/tabsContext";
|
||||
import TabComponent from "./tabComponent";
|
||||
import { example } from "../../../data_assets/example";
|
||||
var _ = require("lodash");
|
||||
|
||||
export function TabsManager() {
|
||||
const { flows, addFlow, tabIndex, setTabIndex } = useContext(TabsContext);
|
||||
useEffect(() => {
|
||||
if (flows.length === 0) {
|
||||
addFlow();
|
||||
}
|
||||
}, [addFlow, flows.length]);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex flex-col">
|
||||
<div className="w-full flex pr-2 flex-row text-center items-center bg-gray-100 px-2">
|
||||
{flows.map((flow, index) => {
|
||||
return (
|
||||
<TabComponent
|
||||
onClick={() => setTabIndex(index)}
|
||||
selected={index === tabIndex}
|
||||
key={index}
|
||||
flow={flow}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<TabComponent
|
||||
onClick={() => {
|
||||
addFlow();
|
||||
}}
|
||||
selected={false}
|
||||
flow={null}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full h-full">
|
||||
<ReactFlowProvider>
|
||||
{flows[tabIndex] ? (
|
||||
<FlowPage flow={flows[tabIndex]}></FlowPage>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</ReactFlowProvider>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import { PlusIcon, XMarkIcon } from "@heroicons/react/24/solid";
|
||||
import { useContext, useRef, useState } from "react";
|
||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||
|
||||
var _ = require("lodash");
|
||||
|
||||
export default function TabComponent({ selected, flow, onClick }) {
|
||||
const { removeFlow, updateFlow } = useContext(TabsContext);
|
||||
const [isRename, setIsRename] = useState(false);
|
||||
const [value, setValue] = useState("");
|
||||
return (
|
||||
<>
|
||||
{flow ? (
|
||||
!selected ? (
|
||||
<div
|
||||
className="flex justify-between select-none truncate w-44 items-center px-4 my-1.5 border-x border-t border-t-transparent border-gray-300 -ml-px"
|
||||
onClick={onClick}
|
||||
>
|
||||
{flow.name}
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
removeFlow(flow.id);
|
||||
}}
|
||||
>
|
||||
<XMarkIcon className="h-4 hover:bg-white rounded-full" />
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="bg-white flex select-none justify-between w-44 items-center border border-b-0 border-gray-300 px-4 py-1.5 rounded-t-xl -ml-px">
|
||||
{isRename ? (
|
||||
<input
|
||||
autoFocus
|
||||
className="bg-transparent focus:border-none active:outline hover:outline focus:outline outline-gray-300 rounded-md w-28"
|
||||
onBlur={() => {
|
||||
setIsRename(false);
|
||||
if (value !== "") {
|
||||
let newFlow = _.cloneDeep(flow);
|
||||
newFlow.name = value;
|
||||
updateFlow(newFlow);
|
||||
}
|
||||
}}
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
setValue(e.target.value);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span
|
||||
className="text-left truncate"
|
||||
onDoubleClick={() => {
|
||||
setIsRename(true);
|
||||
setValue(flow.name);
|
||||
}}
|
||||
>
|
||||
{flow.name}
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
onClick={() => {
|
||||
removeFlow(flow.id);
|
||||
}}
|
||||
>
|
||||
<XMarkIcon className="h-4 hover:bg-gray-100 rounded-full" />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<div className="h-full py-1.5 flex justify-center items-center">
|
||||
<button
|
||||
className="px-3 flex items-center h-full pb-0.5 pt-0.5 border-gray-300 -ml-px border-t border-t-transparent"
|
||||
onClick={onClick}
|
||||
>
|
||||
<PlusIcon className="h-5 rounded-full hover:bg-white" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@ import ReactFlow, {
|
|||
addEdge,
|
||||
useEdgesState,
|
||||
useNodesState,
|
||||
ReactFlowProvider,
|
||||
useReactFlow,
|
||||
} from "reactflow";
|
||||
import { locationContext } from "../../contexts/locationContext";
|
||||
import ExtraSidebar from "./components/extraSidebarComponent";
|
||||
|
|
@ -16,6 +18,8 @@ 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";
|
||||
|
||||
const nodeTypes = {
|
||||
genericNode: GenericNode,
|
||||
|
|
@ -27,17 +31,44 @@ const nodeTypes = {
|
|||
|
||||
var _ = require("lodash");
|
||||
|
||||
export default function FlowPage() {
|
||||
export default function FlowPage({ flow }) {
|
||||
let { updateFlow, nodeId } = useContext(TabsContext);
|
||||
const { types, reactFlowInstance, setReactFlowInstance } =
|
||||
useContext(typesContext);
|
||||
const reactFlowWrapper = useRef(null);
|
||||
|
||||
const getId = () => `dndnode_${_.uniqueId()}`;
|
||||
function getId(){
|
||||
console.log(nodeId);
|
||||
nodeId = nodeId+1
|
||||
return `dndnode_}`+nodeId;
|
||||
};
|
||||
|
||||
const { setExtraComponent, setExtraNavigation } = useContext(locationContext);
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
const [reactFlowInstance, setReactFlowInstance] = useState(null);
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState(
|
||||
flow.data?.nodes ?? []
|
||||
);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState(
|
||||
flow.data?.edges ?? []
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (reactFlowInstance && flow) {
|
||||
flow.data = reactFlowInstance.toObject();
|
||||
updateFlow(flow);
|
||||
}
|
||||
}, [nodes, edges]);
|
||||
|
||||
useEffect(() => {
|
||||
setNodes(flow?.data?.nodes ?? []);
|
||||
setEdges(flow?.data?.edges ?? []);
|
||||
if (reactFlowInstance) {
|
||||
reactFlowInstance.setViewport(
|
||||
flow?.data?.viewport ?? { x: 1, y: 0, zoom: 1 }
|
||||
);
|
||||
}
|
||||
}, [flow, reactFlowInstance, setEdges, setNodes]);
|
||||
|
||||
useEffect(() => {
|
||||
setExtraComponent(<ExtraSidebar />);
|
||||
|
|
@ -89,30 +120,24 @@ export default function FlowPage() {
|
|||
y: event.clientY - reactflowBounds.top,
|
||||
});
|
||||
let newId = getId();
|
||||
|
||||
|
||||
const newNode = {
|
||||
id: newId,
|
||||
type:
|
||||
(data.type === "str"
|
||||
data.type === "str"
|
||||
? "inputNode"
|
||||
: (data.type === "chatInput"
|
||||
: data.type === "chatInput"
|
||||
? "chatInputNode"
|
||||
: (data.type === "chatOutput"
|
||||
: data.type === "chatOutput"
|
||||
? "chatOutputNode"
|
||||
: (data.type === "bool"
|
||||
: data.type === "bool"
|
||||
? "booleanNode"
|
||||
: "genericNode")))),
|
||||
: "genericNode",
|
||||
position,
|
||||
data: {
|
||||
...data,
|
||||
id: newId,
|
||||
value: null,
|
||||
reactFlowInstance,
|
||||
onDelete: () => {
|
||||
setNodes(
|
||||
reactFlowInstance.getNodes().filter((n) => n.id !== newId)
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
setNodes((nds) => nds.concat(newNode));
|
||||
|
|
@ -128,22 +153,32 @@ export default function FlowPage() {
|
|||
|
||||
return (
|
||||
<div className="w-full h-full" ref={reactFlowWrapper}>
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChangeMod}
|
||||
onConnect={onConnect}
|
||||
onInit={setReactFlowInstance}
|
||||
nodeTypes={nodeTypes}
|
||||
connectionLineComponent={connection}
|
||||
onDragOver={onDragOver}
|
||||
onDrop={onDrop}
|
||||
>
|
||||
<Background />
|
||||
<Controls></Controls>
|
||||
</ReactFlow>
|
||||
<Chat reactFlowInstance={reactFlowInstance} />
|
||||
{Object.keys(types).length > 0 ? (
|
||||
<>
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
onMove={() =>
|
||||
updateFlow({ ...flow, data: reactFlowInstance.toObject() })
|
||||
}
|
||||
edges={edges}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChangeMod}
|
||||
onConnect={onConnect}
|
||||
onLoad={setReactFlowInstance}
|
||||
onInit={setReactFlowInstance}
|
||||
nodeTypes={nodeTypes}
|
||||
connectionLineComponent={connection}
|
||||
onDragOver={onDragOver}
|
||||
onDrop={onDrop}
|
||||
>
|
||||
<Background />
|
||||
<Controls></Controls>
|
||||
</ReactFlow>
|
||||
<Chat reactFlowInstance={reactFlowInstance} />
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -335,18 +335,18 @@ export function getConnectedNodes(edge: Edge, nodes: Array<Node>): Array<Node> {
|
|||
}
|
||||
|
||||
export function isValidConnection(
|
||||
data,
|
||||
{ source, target, sourceHandle, targetHandle }
|
||||
{ source, target, sourceHandle, targetHandle },
|
||||
reactFlowInstance
|
||||
) {
|
||||
if (
|
||||
sourceHandle.split('|')[0] === targetHandle.split("|")[0] ||
|
||||
sourceHandle.split('|').slice(2).some((t) => t === targetHandle.split("|")[0]) ||
|
||||
targetHandle.split("|")[0] === "str"
|
||||
) {
|
||||
let targetNode = data.reactFlowInstance.getNode(target).data.node;
|
||||
let targetNode = reactFlowInstance.getNode(target).data.node;
|
||||
if (!targetNode) {
|
||||
if (
|
||||
!data.reactFlowInstance
|
||||
!reactFlowInstance
|
||||
.getEdges()
|
||||
.find((e) => e.targetHandle === targetHandle)
|
||||
) {
|
||||
|
|
@ -354,7 +354,7 @@ export function isValidConnection(
|
|||
}
|
||||
} else if (
|
||||
(!targetNode.template[targetHandle.split("|")[1]].list &&
|
||||
!data.reactFlowInstance
|
||||
!reactFlowInstance
|
||||
.getEdges()
|
||||
.find((e) => e.targetHandle === targetHandle)) ||
|
||||
targetNode.template[targetHandle.split("|")[1]].list
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue