merge
This commit is contained in:
commit
34592f87e8
30 changed files with 437 additions and 556 deletions
|
|
@ -150,10 +150,9 @@ class OllamaLLM(CustomComponent):
|
||||||
"top_k": top_k,
|
"top_k": top_k,
|
||||||
"top_p": top_p,
|
"top_p": top_p,
|
||||||
}
|
}
|
||||||
|
|
||||||
# None Value remove
|
|
||||||
llm_params = {k: v for k, v in llm_params.items() if v is not None}
|
|
||||||
|
|
||||||
|
# None Value remove
|
||||||
|
llm_params = {k: v for k, v in llm_params.items() if v is not None}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
llm = Ollama(**llm_params)
|
llm = Ollama(**llm_params)
|
||||||
|
|
|
||||||
|
|
@ -15,29 +15,21 @@ class VectaraSelfQueryRetriverComponent(CustomComponent):
|
||||||
|
|
||||||
display_name: str = "Vectara Self Query Retriever for Vectara Vector Store"
|
display_name: str = "Vectara Self Query Retriever for Vectara Vector Store"
|
||||||
description: str = "Implementation of Vectara Self Query Retriever"
|
description: str = "Implementation of Vectara Self Query Retriever"
|
||||||
documentation = (
|
documentation = "https://python.langchain.com/docs/integrations/retrievers/self_query/vectara_self_query"
|
||||||
"https://python.langchain.com/docs/integrations/retrievers/self_query/vectara_self_query"
|
|
||||||
)
|
|
||||||
beta = True
|
beta = True
|
||||||
|
|
||||||
field_config = {
|
field_config = {
|
||||||
"code": {"show": True},
|
"code": {"show": True},
|
||||||
"vectorstore": {
|
"vectorstore": {"display_name": "Vector Store", "info": "Input Vectara Vectore Store"},
|
||||||
"display_name": "Vector Store",
|
"llm": {"display_name": "LLM", "info": "For self query retriever"},
|
||||||
"info": "Input Vectara Vectore Store"
|
"document_content_description": {
|
||||||
},
|
"display_name": "Document Content Description",
|
||||||
"llm": {
|
|
||||||
"display_name": "LLM",
|
|
||||||
"info": "For self query retriever"
|
|
||||||
},
|
|
||||||
"document_content_description":{
|
|
||||||
"display_name": "Document Content Description",
|
|
||||||
"info": "For self query retriever",
|
"info": "For self query retriever",
|
||||||
},
|
},
|
||||||
"metadata_field_info": {
|
"metadata_field_info": {
|
||||||
"display_name": "Metadata Field Info",
|
"display_name": "Metadata Field Info",
|
||||||
"info": "Each metadata field info is a string in the form of key value pair dictionary containing additional search metadata.\nExample input: {\"name\":\"speech\",\"description\":\"what name of the speech\",\"type\":\"string or list[string]\"}.\nThe keys should remain constant(name, description, type)",
|
"info": 'Each metadata field info is a string in the form of key value pair dictionary containing additional search metadata.\nExample input: {"name":"speech","description":"what name of the speech","type":"string or list[string]"}.\nThe keys should remain constant(name, description, type)',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def build(
|
def build(
|
||||||
|
|
@ -47,24 +39,19 @@ class VectaraSelfQueryRetriverComponent(CustomComponent):
|
||||||
llm: BaseLanguageModel,
|
llm: BaseLanguageModel,
|
||||||
metadata_field_info: List[str],
|
metadata_field_info: List[str],
|
||||||
) -> BaseRetriever:
|
) -> BaseRetriever:
|
||||||
|
|
||||||
metadata_field_obj = []
|
metadata_field_obj = []
|
||||||
|
|
||||||
for meta in metadata_field_info:
|
for meta in metadata_field_info:
|
||||||
meta_obj = json.loads(meta)
|
meta_obj = json.loads(meta)
|
||||||
if 'name' not in meta_obj or 'description' not in meta_obj or 'type' not in meta_obj :
|
if "name" not in meta_obj or "description" not in meta_obj or "type" not in meta_obj:
|
||||||
raise Exception('Incorrect metadata field info format.')
|
raise Exception("Incorrect metadata field info format.")
|
||||||
attribute_info = AttributeInfo(
|
attribute_info = AttributeInfo(
|
||||||
name = meta_obj['name'],
|
name=meta_obj["name"],
|
||||||
description = meta_obj['description'],
|
description=meta_obj["description"],
|
||||||
type = meta_obj['type'],
|
type=meta_obj["type"],
|
||||||
)
|
)
|
||||||
metadata_field_obj.append(attribute_info)
|
metadata_field_obj.append(attribute_info)
|
||||||
|
|
||||||
return SelfQueryRetriever.from_llm(
|
return SelfQueryRetriever.from_llm(
|
||||||
llm,
|
llm, vectorstore, document_content_description, metadata_field_obj, verbose=True
|
||||||
vectorstore,
|
)
|
||||||
document_content_description,
|
|
||||||
metadata_field_obj,
|
|
||||||
verbose=True
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ import {
|
||||||
FETCH_ERROR_MESSAGE,
|
FETCH_ERROR_MESSAGE,
|
||||||
} from "./constants/constants";
|
} from "./constants/constants";
|
||||||
import { alertContext } from "./contexts/alertContext";
|
import { alertContext } from "./contexts/alertContext";
|
||||||
import { FlowsContext } from "./contexts/flowsContext";
|
|
||||||
import { locationContext } from "./contexts/locationContext";
|
import { locationContext } from "./contexts/locationContext";
|
||||||
import { typesContext } from "./contexts/typesContext";
|
import { typesContext } from "./contexts/typesContext";
|
||||||
import Router from "./routes";
|
import Router from "./routes";
|
||||||
|
|
@ -30,7 +29,6 @@ export default function App() {
|
||||||
setShowSideBar(true);
|
setShowSideBar(true);
|
||||||
setIsStackedOpen(true);
|
setIsStackedOpen(true);
|
||||||
}, [location.pathname, setCurrent, setIsStackedOpen, setShowSideBar]);
|
}, [location.pathname, setCurrent, setIsStackedOpen, setShowSideBar]);
|
||||||
const { hardReset } = useContext(FlowsContext);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
errorData,
|
errorData,
|
||||||
|
|
@ -136,10 +134,7 @@ export default function App() {
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
<ErrorBoundary
|
<ErrorBoundary
|
||||||
onReset={() => {
|
onReset={() => {
|
||||||
window.localStorage.removeItem("tabsData");
|
// any reset function
|
||||||
window.localStorage.clear();
|
|
||||||
hardReset();
|
|
||||||
window.location.href = window.location.href;
|
|
||||||
}}
|
}}
|
||||||
FallbackComponent={CrashErrorComponent}
|
FallbackComponent={CrashErrorComponent}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import { FlowsContext } from "../../../../contexts/flowsContext";
|
||||||
import { typesContext } from "../../../../contexts/typesContext";
|
import { typesContext } from "../../../../contexts/typesContext";
|
||||||
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
||||||
import { postCustomComponentUpdate } from "../../../../controllers/API";
|
import { postCustomComponentUpdate } from "../../../../controllers/API";
|
||||||
|
import useFlow from "../../../../stores/flowManagerStore";
|
||||||
import { APIClassType } from "../../../../types/api";
|
import { APIClassType } from "../../../../types/api";
|
||||||
import { ParameterComponentType } from "../../../../types/components";
|
import { ParameterComponentType } from "../../../../types/components";
|
||||||
import { NodeDataType } from "../../../../types/flow";
|
import { NodeDataType } from "../../../../types/flow";
|
||||||
|
|
@ -70,13 +71,8 @@ export default function ParameterComponent({
|
||||||
const { setErrorData, modalContextOpen } = useContext(alertContext);
|
const { setErrorData, modalContextOpen } = useContext(alertContext);
|
||||||
const updateNodeInternals = useUpdateNodeInternals();
|
const updateNodeInternals = useUpdateNodeInternals();
|
||||||
const [position, setPosition] = useState(0);
|
const [position, setPosition] = useState(0);
|
||||||
const {
|
const { tabId, flows } = useContext(FlowsContext);
|
||||||
tabId,
|
const { nodes, edges, setNode } = useFlow();
|
||||||
flows,
|
|
||||||
nodes,
|
|
||||||
edges,
|
|
||||||
setNode,
|
|
||||||
} = useContext(FlowsContext);
|
|
||||||
|
|
||||||
const flow = flows.find((flow) => flow.id === tabId)?.data?.nodes ?? null;
|
const flow = flows.find((flow) => flow.id === tabId)?.data?.nodes ?? null;
|
||||||
|
|
||||||
|
|
@ -133,8 +129,8 @@ export default function ParameterComponent({
|
||||||
let newNode = cloneDeep(oldNode);
|
let newNode = cloneDeep(oldNode);
|
||||||
|
|
||||||
newNode.data = {
|
newNode.data = {
|
||||||
...newNode.data
|
...newNode.data,
|
||||||
}
|
};
|
||||||
|
|
||||||
newNode.data.node.template[name].value = newValue;
|
newNode.data.node.template[name].value = newValue;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import InputComponent from "../../components/inputComponent";
|
||||||
import { Textarea } from "../../components/ui/textarea";
|
import { Textarea } from "../../components/ui/textarea";
|
||||||
import { priorityFields } from "../../constants/constants";
|
import { priorityFields } from "../../constants/constants";
|
||||||
import { useSSE } from "../../contexts/SSEContext";
|
import { useSSE } from "../../contexts/SSEContext";
|
||||||
import { FlowsContext } from "../../contexts/flowsContext";
|
|
||||||
import { typesContext } from "../../contexts/typesContext";
|
import { typesContext } from "../../contexts/typesContext";
|
||||||
import { undoRedoContext } from "../../contexts/undoRedoContext";
|
import { undoRedoContext } from "../../contexts/undoRedoContext";
|
||||||
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
||||||
|
|
@ -17,6 +16,7 @@ import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
|
||||||
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
||||||
import { classNames, cn, getFieldTitle } from "../../utils/utils";
|
import { classNames, cn, getFieldTitle } from "../../utils/utils";
|
||||||
import ParameterComponent from "./components/parameterComponent";
|
import ParameterComponent from "./components/parameterComponent";
|
||||||
|
import useFlow from "../../stores/flowManagerStore";
|
||||||
|
|
||||||
export default function GenericNode({
|
export default function GenericNode({
|
||||||
data,
|
data,
|
||||||
|
|
@ -30,7 +30,7 @@ export default function GenericNode({
|
||||||
yPos: number;
|
yPos: number;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const { types } = useContext(typesContext);
|
const { types } = useContext(typesContext);
|
||||||
const { deleteNode, setNode } = useContext(FlowsContext);
|
const { deleteNode, setNode } = useFlow();
|
||||||
const name = nodeIconsLucide[data.type] ? data.type : types[data.type];
|
const name = nodeIconsLucide[data.type] ? data.type : types[data.type];
|
||||||
const [inputName, setInputName] = useState(false);
|
const [inputName, setInputName] = useState(false);
|
||||||
const [nodeName, setNodeName] = useState(data.node!.display_name);
|
const [nodeName, setNodeName] = useState(data.node!.display_name);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import { useContext, useState } from "react";
|
||||||
import Loading from "../../../components/ui/loading";
|
import Loading from "../../../components/ui/loading";
|
||||||
import { useSSE } from "../../../contexts/SSEContext";
|
import { useSSE } from "../../../contexts/SSEContext";
|
||||||
import { alertContext } from "../../../contexts/alertContext";
|
import { alertContext } from "../../../contexts/alertContext";
|
||||||
import { typesContext } from "../../../contexts/typesContext";
|
|
||||||
import { postBuildInit } from "../../../controllers/API";
|
import { postBuildInit } from "../../../controllers/API";
|
||||||
import { FlowType } from "../../../types/flow";
|
import { FlowType } from "../../../types/flow";
|
||||||
|
|
||||||
|
|
@ -13,6 +12,7 @@ import { FlowsState } from "../../../types/tabs";
|
||||||
import { validateNodes } from "../../../utils/reactflowUtils";
|
import { validateNodes } from "../../../utils/reactflowUtils";
|
||||||
import RadialProgressComponent from "../../RadialProgress";
|
import RadialProgressComponent from "../../RadialProgress";
|
||||||
import IconComponent from "../../genericIconComponent";
|
import IconComponent from "../../genericIconComponent";
|
||||||
|
import useFlow from "../../../stores/flowManagerStore";
|
||||||
|
|
||||||
export default function BuildTrigger({
|
export default function BuildTrigger({
|
||||||
open,
|
open,
|
||||||
|
|
@ -25,7 +25,8 @@ export default function BuildTrigger({
|
||||||
isBuilt: boolean;
|
isBuilt: boolean;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const { updateSSEData, isBuilding, setIsBuilding, sseData } = useSSE();
|
const { updateSSEData, isBuilding, setIsBuilding, sseData } = useSSE();
|
||||||
const { setTabsState, saveFlow, nodes, edges } = useContext(FlowsContext);
|
const { setTabsState, saveFlow } = useContext(FlowsContext);
|
||||||
|
const { nodes, edges } = useFlow();
|
||||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||||
const [isIconTouched, setIsIconTouched] = useState(false);
|
const [isIconTouched, setIsIconTouched] = useState(false);
|
||||||
const eventClick = isBuilding ? "pointer-events-none" : "";
|
const eventClick = isBuilding ? "pointer-events-none" : "";
|
||||||
|
|
@ -36,10 +37,7 @@ export default function BuildTrigger({
|
||||||
if (isBuilding) {
|
if (isBuilding) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const errors = validateNodes(
|
const errors = validateNodes(nodes, edges);
|
||||||
nodes,
|
|
||||||
edges
|
|
||||||
);
|
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
setErrorData({
|
setErrorData({
|
||||||
title: "Oops! Looks like you missed something",
|
title: "Oops! Looks like you missed something",
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,14 @@ import { FlowsContext } from "../../contexts/flowsContext";
|
||||||
import { getBuildStatus } from "../../controllers/API";
|
import { getBuildStatus } from "../../controllers/API";
|
||||||
import FormModal from "../../modals/formModal";
|
import FormModal from "../../modals/formModal";
|
||||||
import { NodeType } from "../../types/flow";
|
import { NodeType } from "../../types/flow";
|
||||||
|
import useFlow from "../../stores/flowManagerStore";
|
||||||
|
|
||||||
export default function Chat({ flow }: ChatType): JSX.Element {
|
export default function Chat({ flow }: ChatType): JSX.Element {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [canOpen, setCanOpen] = useState(false);
|
const [canOpen, setCanOpen] = useState(false);
|
||||||
const { tabsState, isBuilt, setIsBuilt, isPending } = useContext(FlowsContext);
|
const { isBuilt, setIsBuilt, isPending } = useFlow();
|
||||||
|
const { tabsState } =
|
||||||
|
useContext(FlowsContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeyDown = (event: KeyboardEvent) => {
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import {
|
||||||
TabsTrigger,
|
TabsTrigger,
|
||||||
} from "../../components/ui/tabs";
|
} from "../../components/ui/tabs";
|
||||||
import { LANGFLOW_SUPPORTED_TYPES } from "../../constants/constants";
|
import { LANGFLOW_SUPPORTED_TYPES } from "../../constants/constants";
|
||||||
import { FlowsContext } from "../../contexts/flowsContext";
|
|
||||||
import { useDarkStore } from "../../stores/darkStore";
|
import { useDarkStore } from "../../stores/darkStore";
|
||||||
import { codeTabsPropsType } from "../../types/components";
|
import { codeTabsPropsType } from "../../types/components";
|
||||||
import {
|
import {
|
||||||
|
|
@ -41,6 +40,7 @@ import { classNames } from "../../utils/utils";
|
||||||
import DictComponent from "../dictComponent";
|
import DictComponent from "../dictComponent";
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
import KeypairListComponent from "../keypairListComponent";
|
import KeypairListComponent from "../keypairListComponent";
|
||||||
|
import useFlow from "../../stores/flowManagerStore";
|
||||||
|
|
||||||
export default function CodeTabsComponent({
|
export default function CodeTabsComponent({
|
||||||
flow,
|
flow,
|
||||||
|
|
@ -53,9 +53,9 @@ export default function CodeTabsComponent({
|
||||||
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
||||||
const [data, setData] = useState(flow ? flow["data"]!["nodes"] : null);
|
const [data, setData] = useState(flow ? flow["data"]!["nodes"] : null);
|
||||||
const [openAccordion, setOpenAccordion] = useState<string[]>([]);
|
const [openAccordion, setOpenAccordion] = useState<string[]>([]);
|
||||||
const dark = useDarkStore((state) => state.dark);
|
const {dark} = useDarkStore();
|
||||||
|
|
||||||
const { setNodes } = useContext(FlowsContext);
|
const { setNodes } = useFlow();
|
||||||
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import { AuthContext } from "../../contexts/authContext";
|
||||||
|
|
||||||
import { FlowsContext } from "../../contexts/flowsContext";
|
import { FlowsContext } from "../../contexts/flowsContext";
|
||||||
import { useDarkStore } from "../../stores/darkStore";
|
import { useDarkStore } from "../../stores/darkStore";
|
||||||
import { useStoreStore } from "../../stores/storeStore";
|
|
||||||
import { gradients } from "../../utils/styleUtils";
|
import { gradients } from "../../utils/styleUtils";
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
|
@ -30,12 +29,7 @@ export default function Header(): JSX.Element {
|
||||||
const { logout, autoLogin, isAdmin, userData } = useContext(AuthContext);
|
const { logout, autoLogin, isAdmin, userData } = useContext(AuthContext);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const hasStore = useStoreStore((state) => state.hasStore);
|
const { dark, setDark, stars, gradientIndex } = useDarkStore();
|
||||||
|
|
||||||
const dark = useDarkStore((state) => state.dark);
|
|
||||||
const setDark = useDarkStore((state) => state.updateDark);
|
|
||||||
const stars = useDarkStore((state) => state.stars);
|
|
||||||
const gradientIndex = useDarkStore((state) => state.gradientIndex);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dark) {
|
if (dark) {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export default function PageLayout({
|
||||||
description: string;
|
description: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
button?: React.ReactNode;
|
button?: React.ReactNode;
|
||||||
betaIcon: boolean;
|
betaIcon?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen w-full flex-col">
|
<div className="flex h-screen w-full flex-col">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useDarkStore } from "../../stores/darkStore";
|
|
||||||
import { cn } from "../../utils/utils";
|
import { cn } from "../../utils/utils";
|
||||||
import { Badge } from "../ui/badge";
|
import { Badge } from "../ui/badge";
|
||||||
|
|
||||||
|
|
@ -24,7 +23,6 @@ export function TagsSelector({
|
||||||
: selectedTags.filter((_, i) => i !== index);
|
: selectedTags.filter((_, i) => i !== index);
|
||||||
setSelectedTags(newArray);
|
setSelectedTags(newArray);
|
||||||
};
|
};
|
||||||
const dark = useDarkStore((state) => state.dark);
|
|
||||||
|
|
||||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const fadeContainerRef = useRef<HTMLDivElement>(null);
|
const fadeContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import {
|
||||||
updateFlowInDatabase,
|
updateFlowInDatabase,
|
||||||
uploadFlowsToDatabase,
|
uploadFlowsToDatabase,
|
||||||
} from "../controllers/API";
|
} from "../controllers/API";
|
||||||
import { APIClassType, APITemplateType } from "../types/api";
|
import { APIClassType } from "../types/api";
|
||||||
import { tweakType } from "../types/components";
|
import { tweakType } from "../types/components";
|
||||||
import {
|
import {
|
||||||
FlowType,
|
FlowType,
|
||||||
|
|
@ -46,12 +46,13 @@ import {
|
||||||
checkOldEdgesHandles,
|
checkOldEdgesHandles,
|
||||||
cleanEdges,
|
cleanEdges,
|
||||||
createFlowComponent,
|
createFlowComponent,
|
||||||
|
processFlowEdges,
|
||||||
removeFileNameFromComponents,
|
removeFileNameFromComponents,
|
||||||
scapeJSONParse,
|
scapeJSONParse,
|
||||||
scapedJSONStringfy,
|
scapedJSONStringfy,
|
||||||
|
updateEdges,
|
||||||
updateEdgesHandleIds,
|
updateEdgesHandleIds,
|
||||||
updateIds,
|
updateIds,
|
||||||
updateTemplate,
|
|
||||||
} from "../utils/reactflowUtils";
|
} from "../utils/reactflowUtils";
|
||||||
import {
|
import {
|
||||||
createRandomKey,
|
createRandomKey,
|
||||||
|
|
@ -61,10 +62,12 @@ import {
|
||||||
import { alertContext } from "./alertContext";
|
import { alertContext } from "./alertContext";
|
||||||
import { AuthContext } from "./authContext";
|
import { AuthContext } from "./authContext";
|
||||||
import { typesContext } from "./typesContext";
|
import { typesContext } from "./typesContext";
|
||||||
|
import useFlow from "../stores/flowManagerStore";
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 5 });
|
const uid = new ShortUniqueId({ length: 5 });
|
||||||
|
|
||||||
const FlowsContextInitialValue: FlowsContextType = {
|
const FlowsContextInitialValue: FlowsContextType = {
|
||||||
|
//Remove tab id and get current id from url
|
||||||
tabId: "",
|
tabId: "",
|
||||||
setTabId: (index: string) => {},
|
setTabId: (index: string) => {},
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
|
|
@ -75,41 +78,16 @@ const FlowsContextInitialValue: FlowsContextType = {
|
||||||
flowData?: FlowType,
|
flowData?: FlowType,
|
||||||
override?: boolean
|
override?: boolean
|
||||||
) => "",
|
) => "",
|
||||||
deleteNode: () => {},
|
|
||||||
deleteEdge: () => {},
|
|
||||||
incrementNodeId: () => uid(),
|
|
||||||
downloadFlow: (flow: FlowType) => {},
|
downloadFlow: (flow: FlowType) => {},
|
||||||
downloadFlows: () => {},
|
downloadFlows: () => {},
|
||||||
uploadFlows: () => {},
|
uploadFlows: () => {},
|
||||||
uploadFlow: async () => "",
|
uploadFlow: async () => "",
|
||||||
isBuilt: false,
|
|
||||||
setIsBuilt: (state: boolean) => {},
|
|
||||||
hardReset: () => {},
|
|
||||||
saveFlow: async (flow?: FlowType, silent?: boolean) => {},
|
saveFlow: async (flow?: FlowType, silent?: boolean) => {},
|
||||||
lastCopiedSelection: null,
|
|
||||||
setLastCopiedSelection: (selection: any) => {},
|
|
||||||
isPending: false,
|
|
||||||
setPending: (pending: boolean) => {},
|
|
||||||
tabsState: {},
|
tabsState: {},
|
||||||
setTabsState: () => {},
|
setTabsState: () => {},
|
||||||
getNodeId: (nodeType: string) => "",
|
|
||||||
setTweak: (tweak: any) => {},
|
|
||||||
getTweak: [],
|
|
||||||
paste: (
|
|
||||||
selection: { nodes: any; edges: any },
|
|
||||||
position: { x: number; y: number; paneX?: number; paneY?: number }
|
|
||||||
) => {},
|
|
||||||
saveComponent: async (component: NodeDataType, override: boolean) => "",
|
saveComponent: async (component: NodeDataType, override: boolean) => "",
|
||||||
deleteComponent: (key: string) => {},
|
deleteComponent: (key: string) => {},
|
||||||
version: "",
|
version: "",
|
||||||
nodes: [],
|
|
||||||
setNodes: () => {},
|
|
||||||
setNode: () => {},
|
|
||||||
getNode: () => undefined,
|
|
||||||
onNodesChange: () => {},
|
|
||||||
edges: [],
|
|
||||||
setEdges: () => {},
|
|
||||||
onEdgesChange: () => {},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FlowsContext = createContext<FlowsContextType>(
|
export const FlowsContext = createContext<FlowsContextType>(
|
||||||
|
|
@ -123,107 +101,10 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
const [tabId, setTabId] = useState("");
|
const [tabId, setTabId] = useState("");
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [flows, setFlows] = useState<Array<FlowType>>([]);
|
const [flows, setFlows] = useState<Array<FlowType>>([]);
|
||||||
const [id, setId] = useState(uid());
|
const { setData } = useContext(typesContext);
|
||||||
const { reactFlowInstance, setData } = useContext(typesContext);
|
|
||||||
const [lastCopiedSelection, setLastCopiedSelection] = useState<{
|
|
||||||
nodes: any;
|
|
||||||
edges: any;
|
|
||||||
} | null>(null);
|
|
||||||
const [tabsState, setTabsState] = useState<FlowsState>({});
|
const [tabsState, setTabsState] = useState<FlowsState>({});
|
||||||
const [getTweak, setTweak] = useState<tweakType>([]);
|
|
||||||
|
|
||||||
const [nodes, setNodesInternal, onNodesChangeInternal] = useNodesState([]);
|
const {nodes, edges, paste, setPending, reactFlowInstance} = useFlow();
|
||||||
|
|
||||||
const [edges, setEdgesInternal, onEdgesChangeInternal] = useEdgesState([]);
|
|
||||||
|
|
||||||
const setPending = (pending: boolean) => {
|
|
||||||
setTabsState((prev: FlowsState) => {
|
|
||||||
return {
|
|
||||||
...prev,
|
|
||||||
[tabId]: {
|
|
||||||
...prev[tabId],
|
|
||||||
isPending: pending,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const isPending = tabsState[tabId]?.isPending ?? false;
|
|
||||||
|
|
||||||
const onNodesChange = useCallback(
|
|
||||||
(change: NodeChange[]) => {
|
|
||||||
onNodesChangeInternal(change);
|
|
||||||
if(!isPending)
|
|
||||||
setPending(true);
|
|
||||||
},
|
|
||||||
[onNodesChangeInternal, setPending, isPending]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onEdgesChange = useCallback(
|
|
||||||
(edges: EdgeChange[]) => {
|
|
||||||
onEdgesChangeInternal(edges);
|
|
||||||
if(!isPending)
|
|
||||||
setPending(true);
|
|
||||||
},
|
|
||||||
[onEdgesChangeInternal, setPending, isPending]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setNodes = (change: Node[] | ((oldState: Node[]) => Node[])) => {
|
|
||||||
let newChange = typeof change === "function" ? change(nodes) : change;
|
|
||||||
let newEdges = cleanEdges(newChange, edges);
|
|
||||||
|
|
||||||
saveCurrentFlow(
|
|
||||||
newChange,
|
|
||||||
newEdges,
|
|
||||||
reactFlowInstance?.getViewport() ?? { zoom: 1, x: 0, y: 0 }
|
|
||||||
);
|
|
||||||
setEdgesInternal(newEdges);
|
|
||||||
setNodesInternal(newChange);
|
|
||||||
};
|
|
||||||
|
|
||||||
const setNode = (id: string, change: Node | ((oldState: Node) => Node)) => {
|
|
||||||
let newChange =
|
|
||||||
typeof change === "function"
|
|
||||||
? change(nodes.find((node) => node.id === id)!)
|
|
||||||
: change;
|
|
||||||
|
|
||||||
setNodes((oldNodes) =>
|
|
||||||
oldNodes.map((node) => {
|
|
||||||
if (node.id === id) {
|
|
||||||
return newChange;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getNode = (id: string) => {
|
|
||||||
return nodes.find((node) => node.id === id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const setEdges = (change: Edge[] | ((oldState: Edge[]) => Edge[])) => {
|
|
||||||
let newChange = typeof change === "function" ? change(edges) : change;
|
|
||||||
|
|
||||||
saveCurrentFlow(
|
|
||||||
nodes,
|
|
||||||
newChange,
|
|
||||||
reactFlowInstance?.getViewport() ?? { zoom: 1, x: 0, y: 0 }
|
|
||||||
);
|
|
||||||
setEdgesInternal(newChange);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isAuthenticated) {
|
|
||||||
hardReset();
|
|
||||||
}
|
|
||||||
}, [isAuthenticated]);
|
|
||||||
|
|
||||||
const newNodeId = useRef(uid());
|
|
||||||
|
|
||||||
function incrementNodeId() {
|
|
||||||
newNodeId.current = uid();
|
|
||||||
return newNodeId.current;
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshFlows() {
|
function refreshFlows() {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
@ -231,7 +112,7 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
if (DbData) {
|
if (DbData) {
|
||||||
try {
|
try {
|
||||||
processFlows(DbData, false);
|
processFlows(DbData, false);
|
||||||
updateStateWithDbData(DbData);
|
setFlows(DbData);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
@ -281,31 +162,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function processFlowEdges(flow: FlowType) {
|
|
||||||
if (!flow.data || !flow.data.edges) return;
|
|
||||||
if (checkOldEdgesHandles(flow.data.edges)) {
|
|
||||||
const newEdges = updateEdgesHandleIds(flow.data);
|
|
||||||
flow.data.edges = newEdges;
|
|
||||||
}
|
|
||||||
//update edges colors
|
|
||||||
flow.data.edges.forEach((edge) => {
|
|
||||||
edge.className = "";
|
|
||||||
edge.style = { stroke: "#555" };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateStateWithDbData(tabsData: FlowType[]) {
|
|
||||||
setFlows(tabsData);
|
|
||||||
}
|
|
||||||
|
|
||||||
function hardReset() {
|
|
||||||
newNodeId.current = uid();
|
|
||||||
setTabId("");
|
|
||||||
setFlows([]);
|
|
||||||
setIsLoading(true);
|
|
||||||
setId(uid());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloads the current flow as a JSON file
|
* Downloads the current flow as a JSON file
|
||||||
*/
|
*/
|
||||||
|
|
@ -353,11 +209,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
link.click();
|
link.click();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodeId(nodeType: string) {
|
|
||||||
return nodeType + "-" + incrementNodeId();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a file input and listens to a change event to upload a JSON flow file.
|
* Creates a file input and listens to a change event to upload a JSON flow file.
|
||||||
* If the file type is application/json, the file is read and parsed into a JSON object.
|
* If the file type is application/json, the file is read and parsed into a JSON object.
|
||||||
|
|
@ -466,111 +317,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
processFlows(flows.filter((flow) => flow.id !== id));
|
processFlows(flows.filter((flow) => flow.id !== id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Add a new flow to the list of flows.
|
|
||||||
* @param flow Optional flow to add.
|
|
||||||
*/
|
|
||||||
function paste(
|
|
||||||
selectionInstance: { nodes: Node[]; edges: Edge[] },
|
|
||||||
position: { x: number; y: number; paneX?: number; paneY?: number }
|
|
||||||
) {
|
|
||||||
let minimumX = Infinity;
|
|
||||||
let minimumY = Infinity;
|
|
||||||
let idsMap = {};
|
|
||||||
let newNodes: Node<NodeDataType>[] = nodes;
|
|
||||||
let newEdges = edges;
|
|
||||||
selectionInstance.nodes.forEach((node: Node) => {
|
|
||||||
if (node.position.y < minimumY) {
|
|
||||||
minimumY = node.position.y;
|
|
||||||
}
|
|
||||||
if (node.position.x < minimumX) {
|
|
||||||
minimumX = node.position.x;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const insidePosition = position.paneX
|
|
||||||
? { x: position.paneX + position.x, y: position.paneY! + position.y }
|
|
||||||
: reactFlowInstance!.screenToFlowPosition({
|
|
||||||
x: position.x,
|
|
||||||
y: position.y,
|
|
||||||
});
|
|
||||||
|
|
||||||
selectionInstance.nodes.forEach((node: NodeType) => {
|
|
||||||
// Generate a unique node ID
|
|
||||||
let newId = getNodeId(node.data.type);
|
|
||||||
idsMap[node.id] = newId;
|
|
||||||
|
|
||||||
// Create a new node object
|
|
||||||
const newNode: NodeType = {
|
|
||||||
id: newId,
|
|
||||||
type: "genericNode",
|
|
||||||
position: {
|
|
||||||
x: insidePosition.x + node.position!.x - minimumX,
|
|
||||||
y: insidePosition.y + node.position!.y - minimumY,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
..._.cloneDeep(node.data),
|
|
||||||
id: newId,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add the new node to the list of nodes in state
|
|
||||||
newNodes = newNodes
|
|
||||||
.map((node) => ({ ...node, selected: false }))
|
|
||||||
.concat({ ...newNode, selected: false });
|
|
||||||
});
|
|
||||||
setNodes(newNodes);
|
|
||||||
|
|
||||||
selectionInstance.edges.forEach((edge: Edge) => {
|
|
||||||
let source = idsMap[edge.source];
|
|
||||||
let target = idsMap[edge.target];
|
|
||||||
const sourceHandleObject: sourceHandleType = scapeJSONParse(
|
|
||||||
edge.sourceHandle!
|
|
||||||
);
|
|
||||||
let sourceHandle = scapedJSONStringfy({
|
|
||||||
...sourceHandleObject,
|
|
||||||
id: source,
|
|
||||||
});
|
|
||||||
sourceHandleObject.id = source;
|
|
||||||
|
|
||||||
edge.data.sourceHandle = sourceHandleObject;
|
|
||||||
const targetHandleObject: targetHandleType = scapeJSONParse(
|
|
||||||
edge.targetHandle!
|
|
||||||
);
|
|
||||||
let targetHandle = scapedJSONStringfy({
|
|
||||||
...targetHandleObject,
|
|
||||||
id: target,
|
|
||||||
});
|
|
||||||
targetHandleObject.id = target;
|
|
||||||
edge.data.targetHandle = targetHandleObject;
|
|
||||||
let id =
|
|
||||||
"reactflow__edge-" +
|
|
||||||
source +
|
|
||||||
sourceHandle +
|
|
||||||
"-" +
|
|
||||||
target +
|
|
||||||
targetHandle;
|
|
||||||
newEdges = addEdge(
|
|
||||||
{
|
|
||||||
source,
|
|
||||||
target,
|
|
||||||
sourceHandle,
|
|
||||||
targetHandle,
|
|
||||||
id,
|
|
||||||
data: cloneDeep(edge.data),
|
|
||||||
style: { stroke: "#555" },
|
|
||||||
className:
|
|
||||||
targetHandleObject.type === "Text"
|
|
||||||
? "stroke-gray-800 "
|
|
||||||
: "stroke-gray-900 ",
|
|
||||||
animated: targetHandleObject.type === "Text",
|
|
||||||
selected: false,
|
|
||||||
},
|
|
||||||
newEdges.map((edge) => ({ ...edge, selected: false }))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
setEdges(newEdges);
|
|
||||||
}
|
|
||||||
|
|
||||||
const addFlow = async (
|
const addFlow = async (
|
||||||
newProject: Boolean,
|
newProject: Boolean,
|
||||||
|
|
@ -634,26 +380,12 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
//add animation to text type edges
|
//add animation to text type edges
|
||||||
updateEdges(data.edges);
|
updateEdges(data.edges);
|
||||||
// updateNodes(data.nodes, data.edges);
|
// updateNodes(data.nodes, data.edges);
|
||||||
if (refreshIds) updateIds(data, getNodeId); // Assuming updateIds is defined elsewhere
|
if (refreshIds) updateIds(data); // Assuming updateIds is defined elsewhere
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateEdges = (edges: Edge[]) => {
|
|
||||||
if (edges)
|
|
||||||
edges.forEach((edge) => {
|
|
||||||
const targetHandleObject: targetHandleType = scapeJSONParse(
|
|
||||||
edge.targetHandle!
|
|
||||||
);
|
|
||||||
edge.className =
|
|
||||||
(targetHandleObject.type === "Text"
|
|
||||||
? "stroke-gray-800 "
|
|
||||||
: "stroke-gray-900 ") + " stroke-connection";
|
|
||||||
edge.animated = targetHandleObject.type === "Text";
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const createNewFlow = (
|
const createNewFlow = (
|
||||||
flowData: ReactFlowJsonObject | null,
|
flowData: ReactFlowJsonObject | null,
|
||||||
flow: FlowType
|
flow: FlowType
|
||||||
|
|
@ -697,7 +429,11 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
|
|
||||||
const saveTimeoutId = useRef<NodeJS.Timeout | null>(null);
|
const saveTimeoutId = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
const saveCurrentFlow = (nodes: Node[], edges: Edge[], viewport: Viewport) => {
|
const saveCurrentFlow = (
|
||||||
|
nodes: Node[],
|
||||||
|
edges: Edge[],
|
||||||
|
viewport: Viewport
|
||||||
|
) => {
|
||||||
// Clear the previous timeout if it exists.
|
// Clear the previous timeout if it exists.
|
||||||
if (saveTimeoutId.current) {
|
if (saveTimeoutId.current) {
|
||||||
clearTimeout(saveTimeoutId.current);
|
clearTimeout(saveTimeoutId.current);
|
||||||
|
|
@ -710,8 +446,7 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
saveFlow({ ...currentFlow, data: { nodes, edges, viewport } }, true);
|
saveFlow({ ...currentFlow, data: { nodes, edges, viewport } }, true);
|
||||||
}
|
}
|
||||||
}, 300); // Delay of 300ms.
|
}, 300); // Delay of 300ms.
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
async function saveFlow(flow?: FlowType, silent?: boolean) {
|
async function saveFlow(flow?: FlowType, silent?: boolean) {
|
||||||
let newFlow;
|
let newFlow;
|
||||||
|
|
@ -765,7 +500,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const [isBuilt, setIsBuilt] = useState(false);
|
|
||||||
// Initialize state variable for the version
|
// Initialize state variable for the version
|
||||||
const [version, setVersion] = useState("");
|
const [version, setVersion] = useState("");
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -774,63 +508,26 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function deleteNode(idx: string | Array<string>) {
|
|
||||||
setNodes((oldNodes) =>
|
|
||||||
oldNodes.filter((node) =>
|
|
||||||
typeof idx === "string" ? node.id !== idx : !idx.includes(node.id)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteEdge(idx: string | Array<string>) {
|
|
||||||
setEdges((oldEdges) =>
|
|
||||||
oldEdges.filter((edge) =>
|
|
||||||
typeof idx === "string" ? edge.id !== idx : !idx.includes(edge.id)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FlowsContext.Provider
|
<FlowsContext.Provider
|
||||||
value={{
|
value={{
|
||||||
version,
|
version,
|
||||||
|
flows,
|
||||||
saveFlow,
|
saveFlow,
|
||||||
isBuilt,
|
|
||||||
setIsBuilt,
|
|
||||||
lastCopiedSelection,
|
|
||||||
setLastCopiedSelection,
|
|
||||||
hardReset,
|
|
||||||
tabId,
|
tabId,
|
||||||
setTabId,
|
setTabId,
|
||||||
flows,
|
|
||||||
incrementNodeId,
|
|
||||||
removeFlow,
|
removeFlow,
|
||||||
addFlow,
|
addFlow,
|
||||||
downloadFlow,
|
downloadFlow,
|
||||||
downloadFlows,
|
downloadFlows,
|
||||||
uploadFlows,
|
uploadFlows,
|
||||||
uploadFlow,
|
uploadFlow,
|
||||||
getNodeId,
|
|
||||||
deleteNode,
|
|
||||||
deleteEdge,
|
|
||||||
isPending,
|
|
||||||
setPending,
|
|
||||||
tabsState,
|
tabsState,
|
||||||
setTabsState,
|
setTabsState,
|
||||||
paste,
|
|
||||||
getTweak,
|
|
||||||
setTweak,
|
|
||||||
isLoading,
|
isLoading,
|
||||||
saveComponent,
|
saveComponent,
|
||||||
deleteComponent,
|
deleteComponent,
|
||||||
nodes,
|
|
||||||
setNodes,
|
|
||||||
setNode,
|
|
||||||
getNode,
|
|
||||||
onNodesChange,
|
|
||||||
edges,
|
|
||||||
setEdges,
|
|
||||||
onEdgesChange,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,6 @@ import { AuthContext } from "./authContext";
|
||||||
//context to share types adn functions from nodes to flow
|
//context to share types adn functions from nodes to flow
|
||||||
|
|
||||||
const initialValue: typesContextType = {
|
const initialValue: typesContextType = {
|
||||||
reactFlowInstance: null,
|
|
||||||
setReactFlowInstance: (newState: ReactFlowInstance) => {},
|
|
||||||
types: {},
|
types: {},
|
||||||
setTypes: () => {},
|
setTypes: () => {},
|
||||||
templates: {},
|
templates: {},
|
||||||
|
|
@ -34,8 +32,6 @@ export const typesContext = createContext<typesContextType>(initialValue);
|
||||||
|
|
||||||
export function TypesProvider({ children }: { children: ReactNode }) {
|
export function TypesProvider({ children }: { children: ReactNode }) {
|
||||||
const [types, setTypes] = useState({});
|
const [types, setTypes] = useState({});
|
||||||
const [reactFlowInstance, setReactFlowInstance] =
|
|
||||||
useState<ReactFlowInstance | null>(null);
|
|
||||||
const [templates, setTemplates] = useState({});
|
const [templates, setTemplates] = useState({});
|
||||||
const [data, setData] = useState({});
|
const [data, setData] = useState({});
|
||||||
const [fetchError, setFetchError] = useState(false);
|
const [fetchError, setFetchError] = useState(false);
|
||||||
|
|
@ -95,14 +91,11 @@ export function TypesProvider({ children }: { children: ReactNode }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<typesContext.Provider
|
<typesContext.Provider
|
||||||
value={{
|
value={{
|
||||||
types,
|
types,
|
||||||
setTypes,
|
setTypes,
|
||||||
reactFlowInstance,
|
|
||||||
setReactFlowInstance,
|
|
||||||
setTemplates,
|
setTemplates,
|
||||||
templates,
|
templates,
|
||||||
data,
|
data,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import {
|
||||||
useEffect,
|
useEffect,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { useReactFlow } from "reactflow";
|
|
||||||
import {
|
import {
|
||||||
HistoryItem,
|
HistoryItem,
|
||||||
UseUndoRedoOptions,
|
UseUndoRedoOptions,
|
||||||
|
|
@ -14,6 +13,7 @@ import {
|
||||||
} from "../types/typesContext";
|
} from "../types/typesContext";
|
||||||
import { isWrappedWithClass } from "../utils/utils";
|
import { isWrappedWithClass } from "../utils/utils";
|
||||||
import { FlowsContext } from "./flowsContext";
|
import { FlowsContext } from "./flowsContext";
|
||||||
|
import useFlow from "../stores/flowManagerStore";
|
||||||
|
|
||||||
const initialValue = {
|
const initialValue = {
|
||||||
undo: () => {},
|
undo: () => {},
|
||||||
|
|
@ -29,7 +29,10 @@ const defaultOptions: UseUndoRedoOptions = {
|
||||||
export const undoRedoContext = createContext<undoRedoContextType>(initialValue);
|
export const undoRedoContext = createContext<undoRedoContextType>(initialValue);
|
||||||
|
|
||||||
export function UndoRedoProvider({ children }) {
|
export function UndoRedoProvider({ children }) {
|
||||||
const { tabId, flows, setNodes, setEdges, nodes, edges } = useContext(FlowsContext);
|
const { tabId, flows } =
|
||||||
|
useContext(FlowsContext);
|
||||||
|
|
||||||
|
const {setNodes, setEdges, nodes, edges} = useFlow();
|
||||||
|
|
||||||
const [past, setPast] = useState<HistoryItem[][]>(flows.map(() => []));
|
const [past, setPast] = useState<HistoryItem[][]>(flows.map(() => []));
|
||||||
const [future, setFuture] = useState<HistoryItem[][]>(flows.map(() => []));
|
const [future, setFuture] = useState<HistoryItem[][]>(flows.map(() => []));
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ const ApiModal = forwardRef(
|
||||||
const [activeTab, setActiveTab] = useState("0");
|
const [activeTab, setActiveTab] = useState("0");
|
||||||
const tweak = useRef<tweakType>([]);
|
const tweak = useRef<tweakType>([]);
|
||||||
const tweaksList = useRef<string[]>([]);
|
const tweaksList = useRef<string[]>([]);
|
||||||
const { setTweak, getTweak, tabsState } = useContext(FlowsContext);
|
const { tabsState } = useContext(FlowsContext);
|
||||||
|
const [getTweak, setTweak] = useState<tweakType>([]);
|
||||||
const pythonApiCode = getPythonApiCode(
|
const pythonApiCode = getPythonApiCode(
|
||||||
flow,
|
flow,
|
||||||
autoLogin,
|
autoLogin,
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,7 @@ import {
|
||||||
limitScrollFieldsModal,
|
limitScrollFieldsModal,
|
||||||
} from "../../constants/constants";
|
} from "../../constants/constants";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { FlowsContext } from "../../contexts/flowsContext";
|
|
||||||
import { typesContext } from "../../contexts/typesContext";
|
|
||||||
import { NodeDataType } from "../../types/flow";
|
import { NodeDataType } from "../../types/flow";
|
||||||
import { FlowsState } from "../../types/tabs";
|
|
||||||
import {
|
import {
|
||||||
convertObjToArray,
|
convertObjToArray,
|
||||||
convertValuesToNumbers,
|
convertValuesToNumbers,
|
||||||
|
|
@ -41,6 +38,7 @@ import {
|
||||||
} from "../../utils/reactflowUtils";
|
} from "../../utils/reactflowUtils";
|
||||||
import { classNames } from "../../utils/utils";
|
import { classNames } from "../../utils/utils";
|
||||||
import BaseModal from "../baseModal";
|
import BaseModal from "../baseModal";
|
||||||
|
import useFlow from "../../stores/flowManagerStore";
|
||||||
|
|
||||||
const EditNodeModal = forwardRef(
|
const EditNodeModal = forwardRef(
|
||||||
(
|
(
|
||||||
|
|
@ -59,7 +57,7 @@ const EditNodeModal = forwardRef(
|
||||||
) => {
|
) => {
|
||||||
const [myData, setMyData] = useState(data);
|
const [myData, setMyData] = useState(data);
|
||||||
|
|
||||||
const { setPending, edges, setNode } = useContext(FlowsContext);
|
const { setPending, edges, setNode } = useFlow();
|
||||||
const { setModalContextOpen } = useContext(alertContext);
|
const { setModalContextOpen } = useContext(alertContext);
|
||||||
|
|
||||||
function changeAdvanced(n) {
|
function changeAdvanced(n) {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ export default function CodeAreaModal({
|
||||||
readonly = false,
|
readonly = false,
|
||||||
}: codeAreaModalPropsType): JSX.Element {
|
}: codeAreaModalPropsType): JSX.Element {
|
||||||
const [code, setCode] = useState(value);
|
const [code, setCode] = useState(value);
|
||||||
const dark = useDarkStore((state) => state.dark);
|
const {dark} = useDarkStore();
|
||||||
|
|
||||||
const [height, setHeight] = useState<string | null>(null);
|
const [height, setHeight] = useState<string | null>(null);
|
||||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import { Checkbox } from "../../components/ui/checkbox";
|
||||||
import { EXPORT_DIALOG_SUBTITLE } from "../../constants/constants";
|
import { EXPORT_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { FlowsContext } from "../../contexts/flowsContext";
|
import { FlowsContext } from "../../contexts/flowsContext";
|
||||||
import { typesContext } from "../../contexts/typesContext";
|
|
||||||
import { removeApiKeys } from "../../utils/reactflowUtils";
|
import { removeApiKeys } from "../../utils/reactflowUtils";
|
||||||
import BaseModal from "../baseModal";
|
import BaseModal from "../baseModal";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { useContext, useEffect, useRef, useState } from "react";
|
import { useContext, useEffect, useRef, useState } from "react";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { typesContext } from "../../contexts/typesContext";
|
|
||||||
import { sendAllProps } from "../../types/api";
|
import { sendAllProps } from "../../types/api";
|
||||||
import { ChatMessageType } from "../../types/chat";
|
import { ChatMessageType } from "../../types/chat";
|
||||||
import { FlowType } from "../../types/flow";
|
import { FlowType } from "../../types/flow";
|
||||||
|
|
@ -26,6 +25,7 @@ import { CHAT_FORM_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||||
import { AuthContext } from "../../contexts/authContext";
|
import { AuthContext } from "../../contexts/authContext";
|
||||||
import { FlowsContext } from "../../contexts/flowsContext";
|
import { FlowsContext } from "../../contexts/flowsContext";
|
||||||
import { getBuildStatus } from "../../controllers/API";
|
import { getBuildStatus } from "../../controllers/API";
|
||||||
|
import useFlow from "../../stores/flowManagerStore";
|
||||||
import { FlowsState } from "../../types/tabs";
|
import { FlowsState } from "../../types/tabs";
|
||||||
import { validateNodes } from "../../utils/reactflowUtils";
|
import { validateNodes } from "../../utils/reactflowUtils";
|
||||||
|
|
||||||
|
|
@ -38,7 +38,8 @@ export default function FormModal({
|
||||||
setOpen: (open: boolean) => void;
|
setOpen: (open: boolean) => void;
|
||||||
flow: FlowType;
|
flow: FlowType;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const { tabsState, setTabsState, nodes, edges } = useContext(FlowsContext);
|
const { tabsState, setTabsState } = useContext(FlowsContext);
|
||||||
|
const { nodes, edges } = useFlow();
|
||||||
const [chatValue, setChatValue] = useState(() => {
|
const [chatValue, setChatValue] = useState(() => {
|
||||||
try {
|
try {
|
||||||
const { formKeysData } = tabsState[flow.id];
|
const { formKeysData } = tabsState[flow.id];
|
||||||
|
|
@ -383,10 +384,7 @@ export default function FormModal({
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
function sendMessage(): void {
|
function sendMessage(): void {
|
||||||
let nodeValidationErrors = validateNodes(
|
let nodeValidationErrors = validateNodes(nodes, edges);
|
||||||
nodes,
|
|
||||||
edges
|
|
||||||
);
|
|
||||||
if (nodeValidationErrors.length === 0) {
|
if (nodeValidationErrors.length === 0) {
|
||||||
setLockChat(true);
|
setLockChat(true);
|
||||||
let inputs = tabsState[id.current].formKeysData.input_keys;
|
let inputs = tabsState[id.current].formKeysData.input_keys;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import ReactFlow, {
|
||||||
SelectionDragHandler,
|
SelectionDragHandler,
|
||||||
addEdge,
|
addEdge,
|
||||||
updateEdge,
|
updateEdge,
|
||||||
useReactFlow,
|
|
||||||
} from "reactflow";
|
} from "reactflow";
|
||||||
import GenericNode from "../../../../CustomNodes/GenericNode";
|
import GenericNode from "../../../../CustomNodes/GenericNode";
|
||||||
import Chat from "../../../../components/chatComponent";
|
import Chat from "../../../../components/chatComponent";
|
||||||
|
|
@ -27,14 +26,14 @@ import { FlowsContext } from "../../../../contexts/flowsContext";
|
||||||
import { locationContext } from "../../../../contexts/locationContext";
|
import { locationContext } from "../../../../contexts/locationContext";
|
||||||
import { typesContext } from "../../../../contexts/typesContext";
|
import { typesContext } from "../../../../contexts/typesContext";
|
||||||
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
||||||
|
import useFlow from "../../../../stores/flowManagerStore";
|
||||||
import { APIClassType } from "../../../../types/api";
|
import { APIClassType } from "../../../../types/api";
|
||||||
import { FlowType, NodeType, targetHandleType } from "../../../../types/flow";
|
import { FlowType, NodeType } from "../../../../types/flow";
|
||||||
import { FlowsState } from "../../../../types/tabs";
|
|
||||||
import {
|
import {
|
||||||
generateFlow,
|
generateFlow,
|
||||||
generateNodeFromFlow,
|
generateNodeFromFlow,
|
||||||
|
getNodeId,
|
||||||
isValidConnection,
|
isValidConnection,
|
||||||
scapeJSONParse,
|
|
||||||
validateSelection,
|
validateSelection,
|
||||||
} from "../../../../utils/reactflowUtils";
|
} from "../../../../utils/reactflowUtils";
|
||||||
import { cn, getRandomName, isWrappedWithClass } from "../../../../utils/utils";
|
import { cn, getRandomName, isWrappedWithClass } from "../../../../utils/utils";
|
||||||
|
|
@ -53,26 +52,33 @@ export default function Page({
|
||||||
flow: FlowType;
|
flow: FlowType;
|
||||||
view?: boolean;
|
view?: boolean;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
let {
|
let { uploadFlow, saveFlow } = useContext(FlowsContext);
|
||||||
uploadFlow,
|
const { types, templates, setFilterEdge } = useContext(typesContext);
|
||||||
getNodeId,
|
|
||||||
paste,
|
|
||||||
lastCopiedSelection,
|
|
||||||
setLastCopiedSelection,
|
|
||||||
deleteNode,
|
|
||||||
deleteEdge,
|
|
||||||
} = useContext(FlowsContext);
|
|
||||||
const {
|
|
||||||
types,
|
|
||||||
reactFlowInstance,
|
|
||||||
setReactFlowInstance,
|
|
||||||
templates,
|
|
||||||
setFilterEdge,
|
|
||||||
} = useContext(typesContext);
|
|
||||||
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const [lastCopiedSelection, setLastCopiedSelection] = useState<{
|
||||||
|
nodes: any;
|
||||||
|
edges: any;
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
const { takeSnapshot } = useContext(undoRedoContext);
|
const { takeSnapshot } = useContext(undoRedoContext);
|
||||||
const { nodes, edges, setNodes, setEdges, onNodesChange, onEdgesChange, setPending, saveFlow, isPending } = useContext(FlowsContext);
|
|
||||||
|
const {
|
||||||
|
reactFlowInstance,
|
||||||
|
setReactFlowInstance,
|
||||||
|
nodes,
|
||||||
|
edges,
|
||||||
|
onNodesChange,
|
||||||
|
onEdgesChange,
|
||||||
|
onConnect,
|
||||||
|
setNodes,
|
||||||
|
setEdges,
|
||||||
|
deleteNode,
|
||||||
|
deleteEdge,
|
||||||
|
setPending,
|
||||||
|
isPending,
|
||||||
|
paste,
|
||||||
|
} = useFlow();
|
||||||
|
|
||||||
const position = useRef({ x: 0, y: 0 });
|
const position = useRef({ x: 0, y: 0 });
|
||||||
const [lastSelection, setLastSelection] =
|
const [lastSelection, setLastSelection] =
|
||||||
|
|
@ -136,11 +142,7 @@ export default function Page({
|
||||||
document.removeEventListener("keydown", onKeyDown);
|
document.removeEventListener("keydown", onKeyDown);
|
||||||
document.removeEventListener("mousemove", handleMouseMove);
|
document.removeEventListener("mousemove", handleMouseMove);
|
||||||
};
|
};
|
||||||
}, [
|
}, [lastCopiedSelection, lastSelection, takeSnapshot]);
|
||||||
lastCopiedSelection,
|
|
||||||
lastSelection,
|
|
||||||
takeSnapshot,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const [selectionMenuVisible, setSelectionMenuVisible] = useState(false);
|
const [selectionMenuVisible, setSelectionMenuVisible] = useState(false);
|
||||||
|
|
||||||
|
|
@ -155,10 +157,12 @@ export default function Page({
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
if(reactFlowInstance){
|
if (reactFlowInstance) {
|
||||||
reactFlowInstance.setNodes(flow?.data?.nodes ?? []);
|
reactFlowInstance.setNodes(flow?.data?.nodes ?? []);
|
||||||
reactFlowInstance.setEdges(flow?.data?.edges ?? []);
|
reactFlowInstance.setEdges(flow?.data?.edges ?? []);
|
||||||
reactFlowInstance.setViewport(flow?.data?.viewport ?? { zoom: 1, x: 0, y: 0 });
|
reactFlowInstance.setViewport(
|
||||||
|
flow?.data?.viewport ?? { zoom: 1, x: 0, y: 0 }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the previous timeout
|
// Clear the previous timeout
|
||||||
|
|
@ -177,30 +181,10 @@ export default function Page({
|
||||||
};
|
};
|
||||||
}, [flow, reactFlowInstance]);
|
}, [flow, reactFlowInstance]);
|
||||||
|
|
||||||
const onConnect = useCallback(
|
const onConnectMod = useCallback(
|
||||||
(params: Connection) => {
|
(params: Connection) => {
|
||||||
takeSnapshot();
|
takeSnapshot();
|
||||||
setEdges((eds) =>
|
onConnect(params);
|
||||||
addEdge(
|
|
||||||
{
|
|
||||||
...params,
|
|
||||||
data: {
|
|
||||||
targetHandle: scapeJSONParse(params.targetHandle!),
|
|
||||||
sourceHandle: scapeJSONParse(params.sourceHandle!),
|
|
||||||
},
|
|
||||||
style: { stroke: "#555" },
|
|
||||||
className:
|
|
||||||
((scapeJSONParse(params.targetHandle!) as targetHandleType)
|
|
||||||
.type === "Text"
|
|
||||||
? "stroke-foreground "
|
|
||||||
: "stroke-foreground ") + " stroke-connection",
|
|
||||||
animated:
|
|
||||||
(scapeJSONParse(params.targetHandle!) as targetHandleType)
|
|
||||||
.type === "Text",
|
|
||||||
},
|
|
||||||
eds
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
[setEdges, takeSnapshot, addEdge]
|
[setEdges, takeSnapshot, addEdge]
|
||||||
);
|
);
|
||||||
|
|
@ -237,10 +221,6 @@ export default function Page({
|
||||||
if (event.dataTransfer.types.some((types) => types === "nodedata")) {
|
if (event.dataTransfer.types.some((types) => types === "nodedata")) {
|
||||||
takeSnapshot();
|
takeSnapshot();
|
||||||
|
|
||||||
// Get the current bounds of the ReactFlow wrapper element
|
|
||||||
const reactflowBounds =
|
|
||||||
reactFlowWrapper.current?.getBoundingClientRect();
|
|
||||||
|
|
||||||
// Extract the data from the drag event and parse it as a JSON object
|
// Extract the data from the drag event and parse it as a JSON object
|
||||||
let data: { type: string; node?: APIClassType } = JSON.parse(
|
let data: { type: string; node?: APIClassType } = JSON.parse(
|
||||||
event.dataTransfer.getData("nodedata")
|
event.dataTransfer.getData("nodedata")
|
||||||
|
|
@ -370,10 +350,9 @@ export default function Page({
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onMove = useCallback(() => {
|
const onMove = useCallback(() => {
|
||||||
if(!isPending)
|
if (!isPending) setPending(true);
|
||||||
setPending(true);
|
|
||||||
}, [setPending]);
|
}, [setPending]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full overflow-hidden">
|
<div className="flex h-full overflow-hidden">
|
||||||
{!view && <ExtraSidebar />}
|
{!view && <ExtraSidebar />}
|
||||||
|
|
@ -399,7 +378,7 @@ export default function Page({
|
||||||
edges={edges}
|
edges={edges}
|
||||||
onNodesChange={onNodesChange}
|
onNodesChange={onNodesChange}
|
||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
onConnect={onConnect}
|
onConnect={onConnectMod}
|
||||||
disableKeyboardA11y={true}
|
disableKeyboardA11y={true}
|
||||||
onInit={setReactFlowInstance}
|
onInit={setReactFlowInstance}
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
|
|
@ -479,9 +458,7 @@ export default function Page({
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
{!view && (
|
{!view && <Chat flow={flow} />}
|
||||||
<Chat flow={flow} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { typesContext } from "../../../../contexts/typesContext";
|
||||||
import ApiModal from "../../../../modals/ApiModal";
|
import ApiModal from "../../../../modals/ApiModal";
|
||||||
import ExportModal from "../../../../modals/exportModal";
|
import ExportModal from "../../../../modals/exportModal";
|
||||||
import ShareModal from "../../../../modals/shareModal";
|
import ShareModal from "../../../../modals/shareModal";
|
||||||
|
import useFlow from "../../../../stores/flowManagerStore";
|
||||||
import { useStoreStore } from "../../../../stores/storeStore";
|
import { useStoreStore } from "../../../../stores/storeStore";
|
||||||
import { APIClassType, APIObjectType } from "../../../../types/api";
|
import { APIClassType, APIObjectType } from "../../../../types/api";
|
||||||
import {
|
import {
|
||||||
|
|
@ -28,13 +29,11 @@ import SidebarDraggableComponent from "./sideBarDraggableComponent";
|
||||||
export default function ExtraSidebar(): JSX.Element {
|
export default function ExtraSidebar(): JSX.Element {
|
||||||
const { data, templates, getFilterEdge, setFilterEdge } =
|
const { data, templates, getFilterEdge, setFilterEdge } =
|
||||||
useContext(typesContext);
|
useContext(typesContext);
|
||||||
const { flows, tabId, uploadFlow, tabsState, saveFlow, isBuilt, isPending } =
|
const { flows, tabId, uploadFlow, saveFlow } = useContext(FlowsContext);
|
||||||
useContext(FlowsContext);
|
|
||||||
|
|
||||||
const hasStore = useStoreStore((state) => state.hasStore);
|
const { hasStore, hasApiKey, validApiKey } = useStoreStore();
|
||||||
const hasApiKey = useStoreStore((state) => state.hasApiKey);
|
|
||||||
const validApiKey = useStoreStore((state) => state.validApiKey);
|
|
||||||
|
|
||||||
|
const { isBuilt, isPending } = useFlow();
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
const [dataFilter, setFilterData] = useState(data);
|
const [dataFilter, setFilterData] = useState(data);
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
|
|
@ -292,12 +291,9 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
{flow && flow.data && (
|
{flow && flow.data && (
|
||||||
<ShadTooltip content="Save" side="top">
|
<ShadTooltip content="Save" side="top">
|
||||||
<button
|
<button
|
||||||
disabled={flow?.data?.nodes.length === 0}
|
|
||||||
className={
|
className={
|
||||||
"extra-side-bar-buttons " +
|
"extra-side-bar-buttons " +
|
||||||
(isPending && flow!.data!.nodes?.length > 0
|
(isPending ? "" : "button-disable")
|
||||||
? ""
|
|
||||||
: "button-disable")
|
|
||||||
}
|
}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
saveFlow();
|
saveFlow();
|
||||||
|
|
@ -307,9 +303,7 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
name="Save"
|
name="Save"
|
||||||
className={
|
className={
|
||||||
"side-bar-button-size" +
|
"side-bar-button-size" +
|
||||||
(isPending && flow!.data!.nodes?.length > 0
|
(isPending ? " " : " extra-side-bar-save-disable")
|
||||||
? " "
|
|
||||||
: " extra-side-bar-save-disable")
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { APIClassType } from "../../../../../types/api";
|
||||||
import {
|
import {
|
||||||
createFlowComponent,
|
createFlowComponent,
|
||||||
downloadNode,
|
downloadNode,
|
||||||
|
getNodeId,
|
||||||
} from "../../../../../utils/reactflowUtils";
|
} from "../../../../../utils/reactflowUtils";
|
||||||
import { removeCountFromString } from "../../../../../utils/utils";
|
import { removeCountFromString } from "../../../../../utils/utils";
|
||||||
|
|
||||||
|
|
@ -35,7 +36,7 @@ export default function SidebarDraggableComponent({
|
||||||
official: boolean;
|
official: boolean;
|
||||||
}) {
|
}) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const { getNodeId, deleteComponent, version } = useContext(FlowsContext);
|
const { deleteComponent, version } = useContext(FlowsContext);
|
||||||
const { autoLogin, userData } = useContext(AuthContext);
|
const { autoLogin, userData } = useContext(AuthContext);
|
||||||
const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 });
|
const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 });
|
||||||
const popoverRef = useRef<HTMLDivElement>(null);
|
const popoverRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
||||||
import ConfirmationModal from "../../../../modals/ConfirmationModal";
|
import ConfirmationModal from "../../../../modals/ConfirmationModal";
|
||||||
import EditNodeModal from "../../../../modals/EditNodeModal";
|
import EditNodeModal from "../../../../modals/EditNodeModal";
|
||||||
import ShareModal from "../../../../modals/shareModal";
|
import ShareModal from "../../../../modals/shareModal";
|
||||||
|
import useFlow from "../../../../stores/flowManagerStore";
|
||||||
import { useStoreStore } from "../../../../stores/storeStore";
|
import { useStoreStore } from "../../../../stores/storeStore";
|
||||||
import { nodeToolbarPropsType } from "../../../../types/components";
|
import { nodeToolbarPropsType } from "../../../../types/components";
|
||||||
import { FlowType } from "../../../../types/flow";
|
import { FlowType } from "../../../../types/flow";
|
||||||
|
|
@ -49,11 +50,8 @@ export default function NodeToolbarComponent({
|
||||||
data.node.template[templateField].type === "NestedDict")
|
data.node.template[templateField].type === "NestedDict")
|
||||||
).length
|
).length
|
||||||
);
|
);
|
||||||
const { getNodeId } = useContext(FlowsContext);
|
|
||||||
|
|
||||||
const hasStore = useStoreStore((state) => state.hasStore);
|
const { hasStore, hasApiKey, validApiKey } = useStoreStore();
|
||||||
const hasApiKey = useStoreStore((state) => state.hasApiKey);
|
|
||||||
const validApiKey = useStoreStore((state) => state.validApiKey);
|
|
||||||
|
|
||||||
function canMinimize() {
|
function canMinimize() {
|
||||||
let countHandles: number = 0;
|
let countHandles: number = 0;
|
||||||
|
|
@ -66,16 +64,9 @@ export default function NodeToolbarComponent({
|
||||||
const isMinimal = canMinimize();
|
const isMinimal = canMinimize();
|
||||||
const isGroup = data.node?.flow ? true : false;
|
const isGroup = data.node?.flow ? true : false;
|
||||||
|
|
||||||
const {
|
const { paste, nodes, edges, setNodes, setEdges } = useFlow();
|
||||||
paste,
|
|
||||||
saveComponent,
|
const { saveComponent, flows, version } = useContext(FlowsContext);
|
||||||
version,
|
|
||||||
flows,
|
|
||||||
nodes,
|
|
||||||
edges,
|
|
||||||
setNodes,
|
|
||||||
setEdges,
|
|
||||||
} = useContext(FlowsContext);
|
|
||||||
const { takeSnapshot } = useContext(undoRedoContext);
|
const { takeSnapshot } = useContext(undoRedoContext);
|
||||||
const [showModalAdvanced, setShowModalAdvanced] = useState(false);
|
const [showModalAdvanced, setShowModalAdvanced] = useState(false);
|
||||||
const [showconfirmShare, setShowconfirmShare] = useState(false);
|
const [showconfirmShare, setShowconfirmShare] = useState(false);
|
||||||
|
|
@ -123,7 +114,7 @@ export default function NodeToolbarComponent({
|
||||||
case "ungroup":
|
case "ungroup":
|
||||||
takeSnapshot();
|
takeSnapshot();
|
||||||
updateFlowPosition(position, data.node?.flow!);
|
updateFlowPosition(position, data.node?.flow!);
|
||||||
expandGroupNode(data, getNodeId, nodes, edges, setNodes, setEdges);
|
expandGroupNode(data, nodes, edges, setNodes, setEdges);
|
||||||
break;
|
break;
|
||||||
case "override":
|
case "override":
|
||||||
setShowOverrideModal(true);
|
setShowOverrideModal(true);
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ type State = {
|
||||||
};
|
};
|
||||||
|
|
||||||
type Action = {
|
type Action = {
|
||||||
updateDark: (dark: State["dark"]) => void;
|
setDark: (dark: State["dark"]) => void;
|
||||||
updateStars: (starts: State["stars"]) => void;
|
setStars: (starts: State["stars"]) => void;
|
||||||
updateGradientIndex: (gradientIndex: State["gradientIndex"]) => void;
|
setGradientIndex: (gradientIndex: State["gradientIndex"]) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function gradientIndexInitialState() {
|
function gradientIndexInitialState() {
|
||||||
|
|
@ -23,9 +23,9 @@ export const useDarkStore = create<State & Action>((set) => ({
|
||||||
dark: JSON.parse(window.localStorage.getItem("isDark")!) ?? false,
|
dark: JSON.parse(window.localStorage.getItem("isDark")!) ?? false,
|
||||||
stars: 0,
|
stars: 0,
|
||||||
gradientIndex: gradientIndexInitialState(),
|
gradientIndex: gradientIndexInitialState(),
|
||||||
updateDark: (dark) => set(() => ({ dark: dark })),
|
setDark: (dark) => set(() => ({ dark: dark })),
|
||||||
updateStars: (starts) => set(() => ({ stars: starts })),
|
setStars: (starts) => set(() => ({ stars: starts })),
|
||||||
updateGradientIndex: (gradientIndex) =>
|
setGradientIndex: (gradientIndex) =>
|
||||||
set(() => ({ gradientIndex: gradientIndex })),
|
set(() => ({ gradientIndex: gradientIndex })),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
248
src/frontend/src/stores/flowManagerStore.ts
Normal file
248
src/frontend/src/stores/flowManagerStore.ts
Normal file
|
|
@ -0,0 +1,248 @@
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
|
import {
|
||||||
|
Connection,
|
||||||
|
Edge,
|
||||||
|
EdgeChange,
|
||||||
|
Node,
|
||||||
|
NodeChange,
|
||||||
|
OnConnect,
|
||||||
|
OnEdgesChange,
|
||||||
|
OnNodesChange,
|
||||||
|
ReactFlowInstance,
|
||||||
|
addEdge,
|
||||||
|
applyEdgeChanges,
|
||||||
|
applyNodeChanges,
|
||||||
|
} from "reactflow";
|
||||||
|
import { create } from "zustand";
|
||||||
|
import {
|
||||||
|
NodeDataType,
|
||||||
|
NodeType,
|
||||||
|
sourceHandleType,
|
||||||
|
targetHandleType,
|
||||||
|
} from "../types/flow";
|
||||||
|
import {
|
||||||
|
cleanEdges,
|
||||||
|
getHandleId,
|
||||||
|
getNodeId,
|
||||||
|
scapeJSONParse,
|
||||||
|
scapedJSONStringfy,
|
||||||
|
} from "../utils/reactflowUtils";
|
||||||
|
|
||||||
|
type RFState = {
|
||||||
|
reactFlowInstance: ReactFlowInstance | null;
|
||||||
|
setReactFlowInstance: (newState: ReactFlowInstance) => void;
|
||||||
|
nodes: Node[];
|
||||||
|
edges: Edge[];
|
||||||
|
onNodesChange: OnNodesChange;
|
||||||
|
onEdgesChange: OnEdgesChange;
|
||||||
|
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void;
|
||||||
|
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void;
|
||||||
|
setNode: (id: string, update: Node | ((oldState: Node) => Node)) => void;
|
||||||
|
getNode: (id: string) => Node | undefined;
|
||||||
|
onConnect: OnConnect;
|
||||||
|
deleteNode: (nodeId: string | Array<string>) => void;
|
||||||
|
deleteEdge: (edgeId: string | Array<string>) => void;
|
||||||
|
paste: (
|
||||||
|
selection: { nodes: any; edges: any },
|
||||||
|
position: { x: number; y: number; paneX?: number; paneY?: number }
|
||||||
|
) => void;
|
||||||
|
isBuilt: boolean;
|
||||||
|
setIsBuilt: (isBuilt: boolean) => void;
|
||||||
|
isPending: boolean;
|
||||||
|
setPending: (pending: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
// this is our useStore hook that we can use in our components to get parts of the store and call actions
|
||||||
|
const useFlow = create<RFState>((set, get) => ({
|
||||||
|
reactFlowInstance: null,
|
||||||
|
setReactFlowInstance: (newState) => {
|
||||||
|
set({ reactFlowInstance: newState });
|
||||||
|
},
|
||||||
|
nodes: [],
|
||||||
|
edges: [],
|
||||||
|
isBuilt: false,
|
||||||
|
setIsBuilt: (isBuilt) => {
|
||||||
|
set({ isBuilt });
|
||||||
|
},
|
||||||
|
onNodesChange: (changes: NodeChange[]) => {
|
||||||
|
set({
|
||||||
|
nodes: applyNodeChanges(changes, get().nodes),
|
||||||
|
});
|
||||||
|
if (!get().isPending) set({ isPending: true });
|
||||||
|
},
|
||||||
|
onEdgesChange: (changes: EdgeChange[]) => {
|
||||||
|
set({
|
||||||
|
edges: applyEdgeChanges(changes, get().edges),
|
||||||
|
});
|
||||||
|
if (!get().isPending) set({ isPending: true });
|
||||||
|
},
|
||||||
|
setNodes: (change) => {
|
||||||
|
let newChange = typeof change === "function" ? change(get().nodes) : change;
|
||||||
|
let newEdges = cleanEdges(newChange, get().edges);
|
||||||
|
|
||||||
|
set({ edges: newEdges });
|
||||||
|
set({ nodes: newChange });
|
||||||
|
},
|
||||||
|
setEdges: (change) => {
|
||||||
|
let newChange = typeof change === "function" ? change(get().edges) : change;
|
||||||
|
|
||||||
|
set({ edges: newChange });
|
||||||
|
},
|
||||||
|
setNode: (id: string, change: Node | ((oldState: Node) => Node)) => {
|
||||||
|
let newChange =
|
||||||
|
typeof change === "function"
|
||||||
|
? change(get().nodes.find((node) => node.id === id)!)
|
||||||
|
: change;
|
||||||
|
|
||||||
|
get().setNodes((oldNodes) =>
|
||||||
|
oldNodes.map((node) => {
|
||||||
|
if (node.id === id) {
|
||||||
|
return newChange;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getNode: (id: string) => {
|
||||||
|
return get().nodes.find((node) => node.id === id);
|
||||||
|
},
|
||||||
|
onConnect: (connection: Connection) => {
|
||||||
|
set({
|
||||||
|
edges: addEdge(
|
||||||
|
{
|
||||||
|
...connection,
|
||||||
|
data: {
|
||||||
|
targetHandle: scapeJSONParse(connection.targetHandle!),
|
||||||
|
sourceHandle: scapeJSONParse(connection.sourceHandle!),
|
||||||
|
},
|
||||||
|
style: { stroke: "#555" },
|
||||||
|
className:
|
||||||
|
((scapeJSONParse(connection.targetHandle!) as targetHandleType)
|
||||||
|
.type === "Text"
|
||||||
|
? "stroke-foreground "
|
||||||
|
: "stroke-foreground ") + " stroke-connection",
|
||||||
|
animated:
|
||||||
|
(scapeJSONParse(connection.targetHandle!) as targetHandleType)
|
||||||
|
.type === "Text",
|
||||||
|
},
|
||||||
|
get().edges
|
||||||
|
),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteNode: (nodeId) => {
|
||||||
|
get().setNodes(
|
||||||
|
get().nodes.filter((node) =>
|
||||||
|
typeof nodeId === "string"
|
||||||
|
? node.id !== nodeId
|
||||||
|
: !nodeId.includes(node.id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
deleteEdge: (edgeId) => {
|
||||||
|
get().setEdges(
|
||||||
|
get().edges.filter((edge) =>
|
||||||
|
typeof edgeId === "string"
|
||||||
|
? edge.id !== edgeId
|
||||||
|
: !edgeId.includes(edge.id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
paste: (selection, position) => {
|
||||||
|
let minimumX = Infinity;
|
||||||
|
let minimumY = Infinity;
|
||||||
|
let idsMap = {};
|
||||||
|
let newNodes: Node<NodeDataType>[] = get().nodes;
|
||||||
|
let newEdges = get().edges;
|
||||||
|
selection.nodes.forEach((node: Node) => {
|
||||||
|
if (node.position.y < minimumY) {
|
||||||
|
minimumY = node.position.y;
|
||||||
|
}
|
||||||
|
if (node.position.x < minimumX) {
|
||||||
|
minimumX = node.position.x;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const insidePosition = position.paneX
|
||||||
|
? { x: position.paneX + position.x, y: position.paneY! + position.y }
|
||||||
|
: get().reactFlowInstance!.screenToFlowPosition({
|
||||||
|
x: position.x,
|
||||||
|
y: position.y,
|
||||||
|
});
|
||||||
|
|
||||||
|
selection.nodes.forEach((node: NodeType) => {
|
||||||
|
// Generate a unique node ID
|
||||||
|
let newId = getNodeId(node.data.type);
|
||||||
|
idsMap[node.id] = newId;
|
||||||
|
|
||||||
|
// Create a new node object
|
||||||
|
const newNode: NodeType = {
|
||||||
|
id: newId,
|
||||||
|
type: "genericNode",
|
||||||
|
position: {
|
||||||
|
x: insidePosition.x + node.position!.x - minimumX,
|
||||||
|
y: insidePosition.y + node.position!.y - minimumY,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
...cloneDeep(node.data),
|
||||||
|
id: newId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the new node to the list of nodes in state
|
||||||
|
newNodes = newNodes
|
||||||
|
.map((node) => ({ ...node, selected: false }))
|
||||||
|
.concat({ ...newNode, selected: false });
|
||||||
|
});
|
||||||
|
set({ nodes: newNodes });
|
||||||
|
|
||||||
|
selection.edges.forEach((edge: Edge) => {
|
||||||
|
let source = idsMap[edge.source];
|
||||||
|
let target = idsMap[edge.target];
|
||||||
|
const sourceHandleObject: sourceHandleType = scapeJSONParse(
|
||||||
|
edge.sourceHandle!
|
||||||
|
);
|
||||||
|
let sourceHandle = scapedJSONStringfy({
|
||||||
|
...sourceHandleObject,
|
||||||
|
id: source,
|
||||||
|
});
|
||||||
|
sourceHandleObject.id = source;
|
||||||
|
|
||||||
|
edge.data.sourceHandle = sourceHandleObject;
|
||||||
|
const targetHandleObject: targetHandleType = scapeJSONParse(
|
||||||
|
edge.targetHandle!
|
||||||
|
);
|
||||||
|
let targetHandle = scapedJSONStringfy({
|
||||||
|
...targetHandleObject,
|
||||||
|
id: target,
|
||||||
|
});
|
||||||
|
targetHandleObject.id = target;
|
||||||
|
edge.data.targetHandle = targetHandleObject;
|
||||||
|
let id = getHandleId(source, sourceHandle, target, targetHandle);
|
||||||
|
newEdges = addEdge(
|
||||||
|
{
|
||||||
|
source,
|
||||||
|
target,
|
||||||
|
sourceHandle,
|
||||||
|
targetHandle,
|
||||||
|
id,
|
||||||
|
data: cloneDeep(edge.data),
|
||||||
|
style: { stroke: "#555" },
|
||||||
|
className:
|
||||||
|
targetHandleObject.type === "Text"
|
||||||
|
? "stroke-gray-800 "
|
||||||
|
: "stroke-gray-900 ",
|
||||||
|
animated: targetHandleObject.type === "Text",
|
||||||
|
selected: false,
|
||||||
|
},
|
||||||
|
newEdges.map((edge) => ({ ...edge, selected: false }))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
set({ edges: newEdges });
|
||||||
|
},
|
||||||
|
isPending: false,
|
||||||
|
setPending: (pending: boolean) => {
|
||||||
|
set({ isPending: pending });
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default useFlow;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { FlowType } from "../flow";
|
import { FlowType } from "../flow";
|
||||||
|
|
||||||
export type ChatType = { flow: FlowType; };
|
export type ChatType = { flow: FlowType };
|
||||||
export type ChatMessageType = {
|
export type ChatMessageType = {
|
||||||
message: string | Object;
|
message: string | Object;
|
||||||
template?: string;
|
template?: string;
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,34 @@
|
||||||
import { XYPosition, Node, NodeChange, Edge, EdgeChange } from "reactflow";
|
import { Edge, EdgeChange, Node, NodeChange, XYPosition } from "reactflow";
|
||||||
import { tweakType } from "../components";
|
import { tweakType } from "../components";
|
||||||
import { FlowType, NodeDataType } from "../flow";
|
import { FlowType, NodeDataType } from "../flow";
|
||||||
import { Dispatch, SetStateAction } from "react";
|
|
||||||
|
|
||||||
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
|
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
|
||||||
|
|
||||||
export type FlowsContextType = {
|
export type FlowsContextType = {
|
||||||
|
//keep
|
||||||
saveFlow: (flow?: FlowType, silent?: boolean) => Promise<void>;
|
saveFlow: (flow?: FlowType, silent?: boolean) => Promise<void>;
|
||||||
tabId: string;
|
tabId: string;
|
||||||
|
//keep
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
setTabId: (index: string) => void;
|
setTabId: (index: string) => void;
|
||||||
flows: Array<FlowType>;
|
//keep
|
||||||
deleteNode: (idx: string | Array<string>) => void;
|
|
||||||
deleteEdge: (idx: string | Array<string>) => void;
|
|
||||||
removeFlow: (id: string) => void;
|
removeFlow: (id: string) => void;
|
||||||
|
//keep
|
||||||
addFlow: (
|
addFlow: (
|
||||||
newProject: boolean,
|
newProject: boolean,
|
||||||
flow?: FlowType,
|
flow?: FlowType,
|
||||||
override?: boolean,
|
override?: boolean,
|
||||||
position?: XYPosition
|
position?: XYPosition
|
||||||
) => Promise<String | undefined>;
|
) => Promise<String | undefined>;
|
||||||
incrementNodeId: () => string;
|
|
||||||
downloadFlow: (
|
downloadFlow: (
|
||||||
flow: FlowType,
|
flow: FlowType,
|
||||||
flowName: string,
|
flowName: string,
|
||||||
flowDescription?: string
|
flowDescription?: string
|
||||||
) => void;
|
) => void;
|
||||||
|
//keep
|
||||||
downloadFlows: () => void;
|
downloadFlows: () => void;
|
||||||
|
//keep
|
||||||
uploadFlows: () => void;
|
uploadFlows: () => void;
|
||||||
isBuilt: boolean;
|
|
||||||
setIsBuilt: (state: boolean) => void;
|
|
||||||
uploadFlow: ({
|
uploadFlow: ({
|
||||||
newProject,
|
newProject,
|
||||||
file,
|
file,
|
||||||
|
|
@ -41,34 +40,17 @@ export type FlowsContextType = {
|
||||||
isComponent?: boolean;
|
isComponent?: boolean;
|
||||||
position?: XYPosition;
|
position?: XYPosition;
|
||||||
}) => Promise<String | never>;
|
}) => Promise<String | never>;
|
||||||
hardReset: () => void;
|
|
||||||
getNodeId: (nodeType: string) => string;
|
|
||||||
isPending: boolean;
|
|
||||||
setPending: (pending: boolean) => void;
|
|
||||||
tabsState: FlowsState;
|
tabsState: FlowsState;
|
||||||
setTabsState: (update: FlowsState | ((oldState: FlowsState) => FlowsState)) => void;
|
setTabsState: (
|
||||||
paste: (
|
update: FlowsState | ((oldState: FlowsState) => FlowsState)
|
||||||
selection: { nodes: any; edges: any },
|
|
||||||
position: { x: number; y: number; paneX?: number; paneY?: number }
|
|
||||||
) => void;
|
) => void;
|
||||||
lastCopiedSelection: { nodes: any; edges: any } | null;
|
|
||||||
setLastCopiedSelection: (selection: { nodes: any; edges: any }) => void;
|
|
||||||
setTweak: (tweak: tweakType) => tweakType | void;
|
|
||||||
getTweak: tweakType;
|
|
||||||
saveComponent: (
|
saveComponent: (
|
||||||
component: NodeDataType,
|
component: NodeDataType,
|
||||||
override: boolean
|
override: boolean
|
||||||
) => Promise<String | undefined>;
|
) => Promise<String | undefined>;
|
||||||
deleteComponent: (key: string) => void;
|
deleteComponent: (key: string) => void;
|
||||||
version: string;
|
version: string;
|
||||||
nodes: Array<Node>;
|
flows: Array<FlowType>;
|
||||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void;
|
|
||||||
setNode: (id: string, update: Node | ((oldState: Node) => Node)) => void;
|
|
||||||
getNode: (id: string) => Node | undefined;
|
|
||||||
onNodesChange: OnChange<NodeChange>;
|
|
||||||
edges: Array<Edge>;
|
|
||||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void;
|
|
||||||
onEdgesChange: OnChange<EdgeChange>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FlowsState = {
|
export type FlowsState = {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ const template: { [char: string]: APIClassType } = {};
|
||||||
const data: { [char: string]: string } = {};
|
const data: { [char: string]: string } = {};
|
||||||
|
|
||||||
export type typesContextType = {
|
export type typesContextType = {
|
||||||
reactFlowInstance: ReactFlowInstance | null;
|
|
||||||
setReactFlowInstance: (newState: ReactFlowInstance) => void;
|
|
||||||
types: typeof types;
|
types: typeof types;
|
||||||
setTypes: (newState: {}) => void;
|
setTypes: (newState: {}) => void;
|
||||||
templates: typeof template;
|
templates: typeof template;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import {
|
||||||
updateEdgesHandleIdsType,
|
updateEdgesHandleIdsType,
|
||||||
} from "../types/utils/reactflowUtils";
|
} from "../types/utils/reactflowUtils";
|
||||||
import { getFieldTitle, toTitleCase } from "./utils";
|
import { getFieldTitle, toTitleCase } from "./utils";
|
||||||
|
const uid = new ShortUniqueId({ length: 5 });
|
||||||
|
|
||||||
export function cleanEdges(nodes: Node[], edges: Edge[]) {
|
export function cleanEdges(nodes: Node[], edges: Edge[]) {
|
||||||
let newEdges = _.cloneDeep(edges);
|
let newEdges = _.cloneDeep(edges);
|
||||||
|
|
@ -82,7 +83,7 @@ export function unselectAllNodes({ updateNodes, data }: unselectAllNodesType) {
|
||||||
export function isValidConnection(
|
export function isValidConnection(
|
||||||
{ source, target, sourceHandle, targetHandle }: Connection,
|
{ source, target, sourceHandle, targetHandle }: Connection,
|
||||||
nodes: Node[],
|
nodes: Node[],
|
||||||
edges: Edge[],
|
edges: Edge[]
|
||||||
) {
|
) {
|
||||||
const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!);
|
const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!);
|
||||||
const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!);
|
const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!);
|
||||||
|
|
@ -98,16 +99,12 @@ export function isValidConnection(
|
||||||
) {
|
) {
|
||||||
let targetNode = nodes.find((node) => node.id === target!)?.data?.node;
|
let targetNode = nodes.find((node) => node.id === target!)?.data?.node;
|
||||||
if (!targetNode) {
|
if (!targetNode) {
|
||||||
if (
|
if (!edges.find((e) => e.targetHandle === targetHandle)) {
|
||||||
!edges
|
|
||||||
.find((e) => e.targetHandle === targetHandle)
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
(!targetNode.template[targetHandleObject.fieldName].list &&
|
(!targetNode.template[targetHandleObject.fieldName].list &&
|
||||||
!edges
|
!edges.find((e) => e.targetHandle === targetHandle)) ||
|
||||||
.find((e) => e.targetHandle === targetHandle)) ||
|
|
||||||
targetNode.template[targetHandleObject.fieldName].list
|
targetNode.template[targetHandleObject.fieldName].list
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -153,7 +150,6 @@ export function updateTemplate(
|
||||||
|
|
||||||
export function updateIds(
|
export function updateIds(
|
||||||
newFlow: ReactFlowJsonObject,
|
newFlow: ReactFlowJsonObject,
|
||||||
getNodeId: (type: string) => string
|
|
||||||
) {
|
) {
|
||||||
let idsMap = {};
|
let idsMap = {};
|
||||||
|
|
||||||
|
|
@ -272,6 +268,20 @@ export function validateNodes(nodes: Node[], edges: Edge[]) {
|
||||||
return nodes.flatMap((n: NodeType) => validateNode(n, edges));
|
return nodes.flatMap((n: NodeType) => validateNode(n, edges));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateEdges(edges: Edge[]) {
|
||||||
|
if (edges)
|
||||||
|
edges.forEach((edge) => {
|
||||||
|
const targetHandleObject: targetHandleType = scapeJSONParse(
|
||||||
|
edge.targetHandle!
|
||||||
|
);
|
||||||
|
edge.className =
|
||||||
|
(targetHandleObject.type === "Text"
|
||||||
|
? "stroke-gray-800 "
|
||||||
|
: "stroke-gray-900 ") + " stroke-connection";
|
||||||
|
edge.animated = targetHandleObject.type === "Text";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export function addVersionToDuplicates(flow: FlowType, flows: FlowType[]) {
|
export function addVersionToDuplicates(flow: FlowType, flows: FlowType[]) {
|
||||||
const existingNames = flows.map((item) => item.name);
|
const existingNames = flows.map((item) => item.name);
|
||||||
let newName = flow.name;
|
let newName = flow.name;
|
||||||
|
|
@ -499,13 +509,26 @@ export function getMiddlePoint(nodes: Node[]) {
|
||||||
return { x: averageX, y: averageY };
|
return { x: averageX, y: averageY };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getNodeId(nodeType: string) {
|
||||||
|
return nodeType + "-" + uid();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHandleId(source: string, sourceHandle: string, target: string, targetHandle: string){
|
||||||
|
return "reactflow__edge-" +
|
||||||
|
source +
|
||||||
|
sourceHandle +
|
||||||
|
"-" +
|
||||||
|
target +
|
||||||
|
targetHandle;
|
||||||
|
}
|
||||||
|
|
||||||
export function generateFlow(
|
export function generateFlow(
|
||||||
selection: OnSelectionChangeParams,
|
selection: OnSelectionChangeParams,
|
||||||
nodes: Node[],
|
nodes: Node[],
|
||||||
edges: Edge[],
|
edges: Edge[],
|
||||||
name: string
|
name: string
|
||||||
): generateFlowType {
|
): generateFlowType {
|
||||||
const newFlowData = {nodes, edges, viewport: { zoom: 1, x: 0, y: 0 }};
|
const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } };
|
||||||
const uid = new ShortUniqueId({ length: 5 });
|
const uid = new ShortUniqueId({ length: 5 });
|
||||||
/* remove edges that are not connected to selected nodes on both ends
|
/* remove edges that are not connected to selected nodes on both ends
|
||||||
in future we can save this edges to when ungrouping reconect to the old nodes
|
in future we can save this edges to when ungrouping reconect to the old nodes
|
||||||
|
|
@ -539,14 +562,10 @@ export function generateFlow(
|
||||||
export function filterFlow(
|
export function filterFlow(
|
||||||
selection: OnSelectionChangeParams,
|
selection: OnSelectionChangeParams,
|
||||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
||||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void,
|
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
|
||||||
) {
|
) {
|
||||||
setNodes((nodes) =>
|
setNodes((nodes) => nodes.filter((node) => !selection.nodes.includes(node)));
|
||||||
nodes.filter((node) => !selection.nodes.includes(node))
|
setEdges((edges) => edges.filter((edge) => !selection.edges.includes(edge)));
|
||||||
);
|
|
||||||
setEdges((edges) =>
|
|
||||||
edges.filter((edge) => !selection.edges.includes(edge))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findLastNode({ nodes, edges }: findLastNodeType) {
|
export function findLastNode({ nodes, edges }: findLastNodeType) {
|
||||||
|
|
@ -572,7 +591,7 @@ export function updateFlowPosition(NewPosition: XYPosition, flow: FlowType) {
|
||||||
export function concatFlows(
|
export function concatFlows(
|
||||||
flow: FlowType,
|
flow: FlowType,
|
||||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
||||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void,
|
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
|
||||||
) {
|
) {
|
||||||
const { nodes, edges } = flow.data!;
|
const { nodes, edges } = flow.data!;
|
||||||
setNodes((old) => [...old, ...nodes]);
|
setNodes((old) => [...old, ...nodes]);
|
||||||
|
|
@ -916,16 +935,28 @@ function updateEdgesIds(edges: Edge[], idsMap: { [key: string]: string }) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function processFlowEdges(flow: FlowType) {
|
||||||
|
if (!flow.data || !flow.data.edges) return;
|
||||||
|
if (checkOldEdgesHandles(flow.data.edges)) {
|
||||||
|
const newEdges = updateEdgesHandleIds(flow.data);
|
||||||
|
flow.data.edges = newEdges;
|
||||||
|
}
|
||||||
|
//update edges colors
|
||||||
|
flow.data.edges.forEach((edge) => {
|
||||||
|
edge.className = "";
|
||||||
|
edge.style = { stroke: "#555" };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function expandGroupNode(
|
export function expandGroupNode(
|
||||||
groupNode: NodeDataType,
|
groupNode: NodeDataType,
|
||||||
getNodeId: (type: string) => string,
|
|
||||||
nodes: Node[],
|
nodes: Node[],
|
||||||
edges: Edge[],
|
edges: Edge[],
|
||||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
||||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
|
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
|
||||||
) {
|
) {
|
||||||
const { template, flow } = _.cloneDeep(groupNode.node!);
|
const { template, flow } = _.cloneDeep(groupNode.node!);
|
||||||
const idsMap = updateIds(flow!.data!, getNodeId);
|
const idsMap = updateIds(flow!.data!);
|
||||||
updateProxyIdsOnTemplate(template, idsMap);
|
updateProxyIdsOnTemplate(template, idsMap);
|
||||||
let flowEdges = edges;
|
let flowEdges = edges;
|
||||||
updateEdgesIds(flowEdges, idsMap);
|
updateEdgesIds(flowEdges, idsMap);
|
||||||
|
|
|
||||||
|
|
@ -578,4 +578,4 @@ def test_async_task_processing_vector_store(client, added_vector_store, created_
|
||||||
# Validate that the task completed successfully and the result is as expected
|
# Validate that the task completed successfully and the result is as expected
|
||||||
assert "result" in task_status_json, task_status_json
|
assert "result" in task_status_json, task_status_json
|
||||||
assert "output" in task_status_json["result"], task_status_json["result"]
|
assert "output" in task_status_json["result"], task_status_json["result"]
|
||||||
assert "Langflow" in task_status_json["result"]["output"], task_status_json["result"]
|
assert "Langflow" in task_status_json["result"]["output"], task_status_json["result"]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue