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",
|
"@types/react-dom": "^18.0.10",
|
||||||
"axios": "^1.3.2",
|
"axios": "^1.3.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-cookie": "^4.1.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-icons": "^4.7.1",
|
"react-icons": "^4.7.1",
|
||||||
"react-laag": "^2.0.5",
|
"react-laag": "^2.0.5",
|
||||||
"react-router-dom": "^6.8.1",
|
"react-router-dom": "^6.8.1",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
|
"react-tabs": "^6.0.0",
|
||||||
"reactflow": "^11.5.5",
|
"reactflow": "^11.5.5",
|
||||||
"tailwindcss": "^3.2.6",
|
"tailwindcss": "^3.2.6",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
|
|
@ -4211,6 +4213,11 @@
|
||||||
"@types/node": "*"
|
"@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": {
|
"node_modules/@types/d3": {
|
||||||
"version": "7.4.0",
|
"version": "7.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz",
|
||||||
|
|
@ -4490,6 +4497,15 @@
|
||||||
"@types/node": "*"
|
"@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": {
|
"node_modules/@types/html-minifier-terser": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
|
||||||
|
|
@ -14801,6 +14817,19 @@
|
||||||
"node": ">=14"
|
"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": {
|
"node_modules/react-dev-utils": {
|
||||||
"version": "12.0.1",
|
"version": "12.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
|
"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": {
|
"node_modules/react-transition-group": {
|
||||||
"version": "4.4.5",
|
"version": "4.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||||
|
|
@ -16819,6 +16860,23 @@
|
||||||
"node": ">=8"
|
"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": {
|
"node_modules/universalify": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,13 @@
|
||||||
"@types/react-dom": "^18.0.10",
|
"@types/react-dom": "^18.0.10",
|
||||||
"axios": "^1.3.2",
|
"axios": "^1.3.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-cookie": "^4.1.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-icons": "^4.7.1",
|
"react-icons": "^4.7.1",
|
||||||
"react-laag": "^2.0.5",
|
"react-laag": "^2.0.5",
|
||||||
"react-router-dom": "^6.8.1",
|
"react-router-dom": "^6.8.1",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
|
"react-tabs": "^6.0.0",
|
||||||
"reactflow": "^11.5.5",
|
"reactflow": "^11.5.5",
|
||||||
"tailwindcss": "^3.2.6",
|
"tailwindcss": "^3.2.6",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ import { locationContext } from "./contexts/locationContext";
|
||||||
import FlowPage from "./pages/FlowPage";
|
import FlowPage from "./pages/FlowPage";
|
||||||
import Sidebar from "./components/SidebarComponent";
|
import Sidebar from "./components/SidebarComponent";
|
||||||
import Header from "./components/HeaderComponent";
|
import Header from "./components/HeaderComponent";
|
||||||
|
import { TabsProvider } from "./contexts/tabsContext";
|
||||||
|
import { TabsManager } from "./pages/FlowPage/flowManager";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
|
|
@ -96,7 +98,7 @@ export default function App() {
|
||||||
return (
|
return (
|
||||||
//need parent component with width and height
|
//need parent component with width and height
|
||||||
<div className="h-full flex flex-col">
|
<div className="h-full flex flex-col">
|
||||||
<ReactFlowProvider>
|
|
||||||
<div className="flex grow-0 shrink basis-auto">
|
<div className="flex grow-0 shrink basis-auto">
|
||||||
<Header userNavigation={userNavigation} user={user}></Header>
|
<Header userNavigation={userNavigation} user={user}></Header>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -108,7 +110,7 @@ export default function App() {
|
||||||
<main className="min-w-0 flex-1 border-t border-gray-200 flex">
|
<main className="min-w-0 flex-1 border-t border-gray-200 flex">
|
||||||
{/* Primary column */}
|
{/* Primary column */}
|
||||||
<div className="w-full h-full">
|
<div className="w-full h-full">
|
||||||
<FlowPage />
|
<TabsManager></TabsManager>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -142,7 +144,6 @@ export default function App() {
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</ReactFlowProvider>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import { typesContext } from "../../contexts/typesContext";
|
||||||
|
|
||||||
export default function BooleanNode({ data }) {
|
export default function BooleanNode({ data }) {
|
||||||
const [enabled, setEnabled] = useState(false);
|
const [enabled, setEnabled] = useState(false);
|
||||||
const {types} = useContext(typesContext);
|
const {types, deleteNode} = useContext(typesContext);
|
||||||
return (
|
return (
|
||||||
<div className="prompt-node relative bg-white rounded-lg solid border flex flex-col justify-center">
|
<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 ">
|
<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>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
data.onDelete(data);
|
deleteNode(data.id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TrashIcon className="text-gray-600 w-6 h-6 hover:text-red-500"></TrashIcon>
|
<TrashIcon className="text-gray-600 w-6 h-6 hover:text-red-500"></TrashIcon>
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,12 @@ import {
|
||||||
nodeColors,
|
nodeColors,
|
||||||
snakeToNormalCase,
|
snakeToNormalCase,
|
||||||
} from "../../../../utils";
|
} from "../../../../utils";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useContext, useEffect, useRef, useState } from "react";
|
||||||
import InputComponent from "../../../../components/inputComponent";
|
import InputComponent from "../../../../components/inputComponent";
|
||||||
import ToggleComponent from "../../../../components/toggleComponent";
|
import ToggleComponent from "../../../../components/toggleComponent";
|
||||||
import InputListComponent from "../../../../components/inputListComponent";
|
import InputListComponent from "../../../../components/inputListComponent";
|
||||||
import TextAreaComponent from "../../../../components/textAreaComponent";
|
import TextAreaComponent from "../../../../components/textAreaComponent";
|
||||||
|
import { typesContext } from "../../../../contexts/typesContext";
|
||||||
|
|
||||||
export default function ParameterComponent({
|
export default function ParameterComponent({
|
||||||
left,
|
left,
|
||||||
|
|
@ -38,7 +39,8 @@ export default function ParameterComponent({
|
||||||
}, [data.id, position, updateNodeInternals]);
|
}, [data.id, position, updateNodeInternals]);
|
||||||
|
|
||||||
const [enabled, setEnabled] = useState(data.node.template[name]?.value ?? false);
|
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 (
|
return (
|
||||||
<div ref={ref} className="w-full flex flex-wrap justify-between items-center bg-gray-50 mt-1 px-5 py-2">
|
<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}
|
position={left ? Position.Left : Position.Right}
|
||||||
id={id}
|
id={id}
|
||||||
isValidConnection={(connection) =>
|
isValidConnection={(connection) =>
|
||||||
isValidConnection(data, connection)
|
isValidConnection(connection,reactFlowInstance)
|
||||||
}
|
}
|
||||||
className={
|
className={
|
||||||
(left ? "-ml-0.5 " : "-mr-0.5 ") +
|
(left ? "-ml-0.5 " : "-mr-0.5 ") +
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ import { typesContext } from "../../contexts/typesContext";
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
|
||||||
export default function GenericNode({ data }) {
|
export default function GenericNode({ data }) {
|
||||||
const {types} = useContext(typesContext);
|
const {types, deleteNode} = useContext(typesContext);
|
||||||
const Icon = nodeIcons[types[data.type]];
|
const Icon = nodeIcons[types[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 ">
|
||||||
|
|
@ -24,7 +25,7 @@ export default function GenericNode({ data }) {
|
||||||
/>
|
/>
|
||||||
<div className="truncate">{data.type}</div>
|
<div className="truncate">{data.type}</div>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={data.onDelete}>
|
<button onClick={() => {deleteNode(data.id)}}>
|
||||||
<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>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import { typesContext } from "../../contexts/typesContext";
|
||||||
import TextAreaComponent from "../../components/textAreaComponent";
|
import TextAreaComponent from "../../components/textAreaComponent";
|
||||||
|
|
||||||
export default function InputNode({ data }) {
|
export default function InputNode({ data }) {
|
||||||
const { types } = useContext(typesContext);
|
const {types, deleteNode} = useContext(typesContext);
|
||||||
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">
|
||||||
<Tooltip title="Prefix: str">
|
<Tooltip title="Prefix: str">
|
||||||
|
|
@ -39,7 +39,7 @@ export default function InputNode({ data }) {
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
data.onDelete(data);
|
deleteNode(data.id)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TrashIcon className="text-gray-600 w-6 h-6 hover:text-red-500"></TrashIcon>
|
<TrashIcon className="text-gray-600 w-6 h-6 hover:text-red-500"></TrashIcon>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { AlertProvider } from "./alertContext";
|
import { AlertProvider } from "./alertContext";
|
||||||
import { LocationProvider } from "./locationContext";
|
import { LocationProvider } from "./locationContext";
|
||||||
import PopUpProvider from "./popUpContext";
|
import PopUpProvider from "./popUpContext";
|
||||||
|
import { TabsProvider } from "./tabsContext";
|
||||||
import { TypesProvider } from "./typesContext";
|
import { TypesProvider } from "./typesContext";
|
||||||
|
|
||||||
export default function ContextWrapper({ children }) {
|
export default function ContextWrapper({ children }) {
|
||||||
|
|
@ -9,7 +10,9 @@ export default function ContextWrapper({ children }) {
|
||||||
<LocationProvider>
|
<LocationProvider>
|
||||||
<PopUpProvider>
|
<PopUpProvider>
|
||||||
<TypesProvider>
|
<TypesProvider>
|
||||||
|
<TabsProvider>
|
||||||
<AlertProvider>{children}</AlertProvider>
|
<AlertProvider>{children}</AlertProvider>
|
||||||
|
</TabsProvider>
|
||||||
</TypesProvider>
|
</TypesProvider>
|
||||||
</PopUpProvider>
|
</PopUpProvider>
|
||||||
</LocationProvider>
|
</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=
|
type typesContextType=
|
||||||
{
|
{
|
||||||
|
reactFlowInstance: ReactFlowInstance;
|
||||||
|
setReactFlowInstance: any;
|
||||||
|
deleteNode:(idx:number)=>void;
|
||||||
types: {};
|
types: {};
|
||||||
setTypes:(newState:{})=>void;
|
setTypes:(newState:{})=>void;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialValue= {
|
const initialValue= {
|
||||||
|
reactFlowInstance: null,
|
||||||
|
setReactFlowInstance: ()=>{},
|
||||||
|
deleteNode: ()=>{},
|
||||||
types: {},
|
types: {},
|
||||||
setTypes:()=>{},
|
setTypes:()=>{},
|
||||||
}
|
}
|
||||||
|
|
@ -15,8 +23,14 @@ export const typesContext = createContext<typesContextType>(initialValue);
|
||||||
|
|
||||||
export function TypesProvider({children}){
|
export function TypesProvider({children}){
|
||||||
const [types, setTypes] = useState({});
|
const [types, setTypes] = useState({});
|
||||||
|
const [reactFlowInstance, setReactFlowInstance] = useState(null);
|
||||||
|
function deleteNode(idx){
|
||||||
|
reactFlowInstance.setNodes(
|
||||||
|
reactFlowInstance.getNodes().filter((n) => n.id !== idx)
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<typesContext.Provider value={{ types, setTypes}}>
|
<typesContext.Provider value={{ types, setTypes, reactFlowInstance, setReactFlowInstance, deleteNode}}>
|
||||||
{children}
|
{children}
|
||||||
</typesContext.Provider>
|
</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,10 +12,10 @@ import { typesContext } from "../../../../contexts/typesContext";
|
||||||
|
|
||||||
export default function ExtraSidebar() {
|
export default function ExtraSidebar() {
|
||||||
const [data, setData] = useState({});
|
const [data, setData] = useState({});
|
||||||
const { setTypes } = useContext(typesContext);
|
const { setTypes} = useContext(typesContext);
|
||||||
|
|
||||||
useEffect(() => {
|
async function getTypes(){
|
||||||
getAll().then((d) => {
|
let d = await getAll();
|
||||||
setData(d.data);
|
setData(d.data);
|
||||||
setTypes(
|
setTypes(
|
||||||
Object.keys(d.data).reduce(
|
Object.keys(d.data).reduce(
|
||||||
|
|
@ -26,7 +26,6 @@ export default function ExtraSidebar() {
|
||||||
acc[b] = curr;
|
acc[b] = curr;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// console.log(acc);
|
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -37,33 +36,12 @@ export default function ExtraSidebar() {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(data){
|
getTypes();
|
||||||
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) {
|
function onDragStart(event: React.DragEvent<any>, data) {
|
||||||
event.dataTransfer.effectAllowed = "move";
|
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,
|
addEdge,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
|
ReactFlowProvider,
|
||||||
|
useReactFlow,
|
||||||
} from "reactflow";
|
} from "reactflow";
|
||||||
import { locationContext } from "../../contexts/locationContext";
|
import { locationContext } from "../../contexts/locationContext";
|
||||||
import ExtraSidebar from "./components/extraSidebarComponent";
|
import ExtraSidebar from "./components/extraSidebarComponent";
|
||||||
|
|
@ -16,6 +18,8 @@ import ChatOutputNode from "../../CustomNodes/ChatOutputNode";
|
||||||
import InputNode from "../../CustomNodes/InputNode";
|
import InputNode from "../../CustomNodes/InputNode";
|
||||||
import BooleanNode from "../../CustomNodes/BooleanNode";
|
import BooleanNode from "../../CustomNodes/BooleanNode";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
|
import { typesContext } from "../../contexts/typesContext";
|
||||||
|
|
||||||
const nodeTypes = {
|
const nodeTypes = {
|
||||||
genericNode: GenericNode,
|
genericNode: GenericNode,
|
||||||
|
|
@ -27,17 +31,44 @@ const nodeTypes = {
|
||||||
|
|
||||||
var _ = require("lodash");
|
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 reactFlowWrapper = useRef(null);
|
||||||
|
|
||||||
const getId = () => `dndnode_${_.uniqueId()}`;
|
function getId(){
|
||||||
|
console.log(nodeId);
|
||||||
|
nodeId = nodeId+1
|
||||||
|
return `dndnode_}`+nodeId;
|
||||||
|
};
|
||||||
|
|
||||||
const { setExtraComponent, setExtraNavigation } = useContext(locationContext);
|
const { setExtraComponent, setExtraNavigation } = useContext(locationContext);
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
|
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
const [nodes, setNodes, onNodesChange] = useNodesState(
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
flow.data?.nodes ?? []
|
||||||
const [reactFlowInstance, setReactFlowInstance] = useState(null);
|
);
|
||||||
|
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(() => {
|
useEffect(() => {
|
||||||
setExtraComponent(<ExtraSidebar />);
|
setExtraComponent(<ExtraSidebar />);
|
||||||
|
|
@ -93,26 +124,20 @@ export default function FlowPage() {
|
||||||
const newNode = {
|
const newNode = {
|
||||||
id: newId,
|
id: newId,
|
||||||
type:
|
type:
|
||||||
(data.type === "str"
|
data.type === "str"
|
||||||
? "inputNode"
|
? "inputNode"
|
||||||
: (data.type === "chatInput"
|
: data.type === "chatInput"
|
||||||
? "chatInputNode"
|
? "chatInputNode"
|
||||||
: (data.type === "chatOutput"
|
: data.type === "chatOutput"
|
||||||
? "chatOutputNode"
|
? "chatOutputNode"
|
||||||
: (data.type === "bool"
|
: data.type === "bool"
|
||||||
? "booleanNode"
|
? "booleanNode"
|
||||||
: "genericNode")))),
|
: "genericNode",
|
||||||
position,
|
position,
|
||||||
data: {
|
data: {
|
||||||
...data,
|
...data,
|
||||||
id: newId,
|
id: newId,
|
||||||
value: null,
|
value: null,
|
||||||
reactFlowInstance,
|
|
||||||
onDelete: () => {
|
|
||||||
setNodes(
|
|
||||||
reactFlowInstance.getNodes().filter((n) => n.id !== newId)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
setNodes((nds) => nds.concat(newNode));
|
setNodes((nds) => nds.concat(newNode));
|
||||||
|
|
@ -128,12 +153,18 @@ export default function FlowPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full" ref={reactFlowWrapper}>
|
<div className="w-full h-full" ref={reactFlowWrapper}>
|
||||||
|
{Object.keys(types).length > 0 ? (
|
||||||
|
<>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
|
onMove={() =>
|
||||||
|
updateFlow({ ...flow, data: reactFlowInstance.toObject() })
|
||||||
|
}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
onNodesChange={onNodesChange}
|
onNodesChange={onNodesChange}
|
||||||
onEdgesChange={onEdgesChangeMod}
|
onEdgesChange={onEdgesChangeMod}
|
||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
|
onLoad={setReactFlowInstance}
|
||||||
onInit={setReactFlowInstance}
|
onInit={setReactFlowInstance}
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
connectionLineComponent={connection}
|
connectionLineComponent={connection}
|
||||||
|
|
@ -144,6 +175,10 @@ export default function FlowPage() {
|
||||||
<Controls></Controls>
|
<Controls></Controls>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
<Chat reactFlowInstance={reactFlowInstance} />
|
<Chat reactFlowInstance={reactFlowInstance} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -335,18 +335,18 @@ export function getConnectedNodes(edge: Edge, nodes: Array<Node>): Array<Node> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isValidConnection(
|
export function isValidConnection(
|
||||||
data,
|
{ source, target, sourceHandle, targetHandle },
|
||||||
{ source, target, sourceHandle, targetHandle }
|
reactFlowInstance
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
sourceHandle.split('|')[0] === targetHandle.split("|")[0] ||
|
sourceHandle.split('|')[0] === targetHandle.split("|")[0] ||
|
||||||
sourceHandle.split('|').slice(2).some((t) => t === targetHandle.split("|")[0]) ||
|
sourceHandle.split('|').slice(2).some((t) => t === targetHandle.split("|")[0]) ||
|
||||||
targetHandle.split("|")[0] === "str"
|
targetHandle.split("|")[0] === "str"
|
||||||
) {
|
) {
|
||||||
let targetNode = data.reactFlowInstance.getNode(target).data.node;
|
let targetNode = reactFlowInstance.getNode(target).data.node;
|
||||||
if (!targetNode) {
|
if (!targetNode) {
|
||||||
if (
|
if (
|
||||||
!data.reactFlowInstance
|
!reactFlowInstance
|
||||||
.getEdges()
|
.getEdges()
|
||||||
.find((e) => e.targetHandle === targetHandle)
|
.find((e) => e.targetHandle === targetHandle)
|
||||||
) {
|
) {
|
||||||
|
|
@ -354,7 +354,7 @@ export function isValidConnection(
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
(!targetNode.template[targetHandle.split("|")[1]].list &&
|
(!targetNode.template[targetHandle.split("|")[1]].list &&
|
||||||
!data.reactFlowInstance
|
!reactFlowInstance
|
||||||
.getEdges()
|
.getEdges()
|
||||||
.find((e) => e.targetHandle === targetHandle)) ||
|
.find((e) => e.targetHandle === targetHandle)) ||
|
||||||
targetNode.template[targetHandle.split("|")[1]].list
|
targetNode.template[targetHandle.split("|")[1]].list
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue