refactor: update ReactFlow to v12 (#5317)
* Added xyflow and updated imports * Fix changing node.width to node.measured.width * Updated NodeType to follow new API * Fixed note node data type * Created AllNodeType to contain note node type * Changed flow types to follow new type from reactflow 12 * Updated flowStore to work with new types * Updated flowStore and reactFlowUtils to work with custom edge type * Updated updateAllNodes to use new type * Updated PageComponent to follow new names for node dragging and edge reconnect * Made selected prop be optional * Changed reactFlowInstance to have nodes and edges type * Updated updateAllComponent to follow new types * Updated ReactFlowUtils with new types * Updated reactFlowUtils type * Updated all reactFlowUtils to be generic * Updated handleRenderComponent with Connection type * Updated node description and name with null checks for names * Added check if node is genericNode on nodeOutputField * Updated note node type * Updated nodestatus with selected null check * Updated notenode with new node type * Update NodeType imports to be AllNodeType * Fix more lint issues * Fixed react flow button css * ✨ (freeze.spec.ts): add zoomOut utility function to handle zooming out in tests for better code reusability and readability 📝 (decisionFlow.spec.ts): import zoomOut utility function to handle zooming out in tests for better code reusability and readability 📝 (zoom-out.ts): create zoomOut utility function to handle zooming out in tests for better code reusability and readability * 🐛 (generalBugs-shard-10.spec.ts): fix test to wait for the element with class "border-ring-frozen" to be visible before asserting its count * 📝 (generalBugs-shard-10.spec.ts): remove unnecessary locator click on element with id 'react-flow-id' to improve test reliability and maintainability * 📝 (SelectionMenuComponent): add data-testid attribute to differentiate error-group-node and group-node components 📝 (similarity.spec.ts): refactor dragTo calls to use targetPosition for better accuracy, replace zoom_out clicks with zoomOut function, updateOldComponents function to handle outdated components 📝 (generalBugs-shard-5.spec.ts): replace zoom_out clicks with zoomOut function, add waitForSelector for group-node before clicking, remove unnecessary mouse interactions 📝 (intComponent.spec.ts): replace zoom_out clicks with zoomOut function, click on div-generic-node component 📝 (keyPairListComponent.spec.ts): click on div-generic-node component, adjustScreenView function call 📝 (nestedComponent.spec.ts): remove unnecessary click on react-flow-id element 📝 (generalBugs-shard-7.spec.ts): replace zoom_out clicks with zoomOut function * ✨ (stop-building.spec.ts): Add new utility functions to improve code modularity and readability 🔧 (stop-building.spec.ts): Refactor drag and drop operations to use utility functions for better maintainability 🔧 (stop-building.spec.ts): Refactor zoom out operations to use utility function for consistency 🔧 (stop-building.spec.ts): Refactor component positioning operations to use utility functions for clarity 🔧 (stop-building.spec.ts): Refactor outdated components and filled API keys handling to use utility functions for reusability 🔧 (stop-building.spec.ts): Refactor fit view operation to use utility function for consistency * ✨ (generalBugs-shard-9.spec.ts): refactor test to use initialGPTsetup function for GPT setup instead of manual steps to improve code readability and maintainability * ✨ (store-shard-2.spec.ts): Increase timeout for clicking "api-key-button-store" to 200000ms for better test stability ✨ (deleteComponents.spec.ts, deleteFlows.spec.ts, store-shard-1.spec.ts, store-shard-3.spec.ts): Increase timeout for clicking "api-key-button-store" to 200000ms for better test stability ✨ (store-shard-1.spec.ts, store-shard-3.spec.ts): Remove unnecessary waitForSelector and add timeout of 200000ms for clicking "api-key-button-store" for better test stability * ✨ (fileUploadComponent.spec.ts): update dragTo method calls with targetPosition option to specify the position of the drag action * ✨ (decisionFlow.spec.ts): add explicit wait for an element to be attached before interacting with it to improve test reliability 🐛 (sticky-notes.spec.ts): fix test by adding keyboard press to simulate pressing the Escape key to close a modal before checking text length * ✅ (sticky-notes.spec.ts): update assertion to use 'toHaveCount' matcher for improved test readability and reliability * Added function to make controls horizontal * ✨ (sticky-notes.spec.ts): update selector for textMarkdown to improve test reliability and readability --------- Co-authored-by: cristhianzl <cristhian.lousa@gmail.com>
This commit is contained in:
parent
0e1f1a48e2
commit
7d6d41aa87
74 changed files with 686 additions and 760 deletions
31
src/frontend/package-lock.json
generated
31
src/frontend/package-lock.json
generated
|
|
@ -36,6 +36,7 @@
|
|||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@tanstack/react-query": "^5.49.2",
|
||||
"@types/axios": "^0.14.0",
|
||||
"@xyflow/react": "^12.3.6",
|
||||
"ace-builds": "^1.35.0",
|
||||
"ag-grid-community": "^32.0.2",
|
||||
"ag-grid-react": "^32.0.2",
|
||||
|
|
@ -6238,6 +6239,36 @@
|
|||
"integrity": "sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@xyflow/react": {
|
||||
"version": "12.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.3.6.tgz",
|
||||
"integrity": "sha512-9GS+cz8hDZahpvTrVCmySAEgKUL8oN4b2q1DluHrKtkqhAMWfH2s7kblhbM4Y4Y4SUnH2lt4drXKZ/4/Lot/2Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@xyflow/system": "0.0.47",
|
||||
"classcat": "^5.0.3",
|
||||
"zustand": "^4.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=17",
|
||||
"react-dom": ">=17"
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/system": {
|
||||
"version": "0.0.47",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.47.tgz",
|
||||
"integrity": "sha512-aUXJPIvsCFxGX70ccRG8LPsR+A8ExYXfh/noYNpqn8udKerrLdSHxMG2VsvUrQ1PGex10fOpbJwFU4A+I/Xv8w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/d3-drag": "^3.0.7",
|
||||
"@types/d3-selection": "^3.0.10",
|
||||
"@types/d3-transition": "^3.0.8",
|
||||
"@types/d3-zoom": "^3.0.8",
|
||||
"d3-drag": "^3.0.0",
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-zoom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/abab": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@tanstack/react-query": "^5.49.2",
|
||||
"@types/axios": "^0.14.0",
|
||||
"@xyflow/react": "^12.3.6",
|
||||
"ace-builds": "^1.35.0",
|
||||
"ag-grid-community": "^32.0.2",
|
||||
"ag-grid-react": "^32.0.2",
|
||||
|
|
|
|||
|
|
@ -137,6 +137,9 @@ body {
|
|||
stroke: var(--selected) !important;
|
||||
stroke-width: 2px !important;
|
||||
}
|
||||
.react-flow__controls-button svg {
|
||||
fill: none !important;
|
||||
}
|
||||
|
||||
.react-flow__edge .react-flow__edge-path {
|
||||
transition: color;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import "@xyflow/react/dist/style.css";
|
||||
import { Suspense } from "react";
|
||||
import { RouterProvider } from "react-router-dom";
|
||||
import "reactflow/dist/style.css";
|
||||
import { LoadingPage } from "./pages/LoadingPage";
|
||||
import router from "./routes";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import useFlowStore from "@/stores/flowStore";
|
||||
import { BaseEdge, EdgeProps, getBezierPath, Position } from "reactflow";
|
||||
import { BaseEdge, EdgeProps, getBezierPath, Position } from "@xyflow/react";
|
||||
|
||||
export function DefaultEdge({
|
||||
sourceHandleId,
|
||||
|
|
@ -17,7 +17,8 @@ export function DefaultEdge({
|
|||
const sourceNode = getNode(source);
|
||||
const targetNode = getNode(target);
|
||||
|
||||
const sourceXNew = (sourceNode?.position.x ?? 0) + (sourceNode?.width ?? 0);
|
||||
const sourceXNew =
|
||||
(sourceNode?.position.x ?? 0) + (sourceNode?.measured?.width ?? 0);
|
||||
const targetXNew = targetNode?.position.x ?? 0;
|
||||
|
||||
const [edgePath] = getBezierPath({
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default function NodeDescription({
|
|||
style,
|
||||
}: {
|
||||
description?: string;
|
||||
selected: boolean;
|
||||
selected?: boolean;
|
||||
nodeId: string;
|
||||
emptyPlaceholder?: string;
|
||||
placeholderClassName?: string;
|
||||
|
|
@ -28,7 +28,9 @@ export default function NodeDescription({
|
|||
style?: React.CSSProperties;
|
||||
}) {
|
||||
const [inputDescription, setInputDescription] = useState(false);
|
||||
const [nodeDescription, setNodeDescription] = useState(description);
|
||||
const [nodeDescription, setNodeDescription] = useState<string>(
|
||||
description ?? "",
|
||||
);
|
||||
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
|
||||
const setNode = useFlowStore((state) => state.setNode);
|
||||
const overflowRef = useRef<HTMLDivElement>(null);
|
||||
|
|
@ -56,7 +58,7 @@ export default function NodeDescription({
|
|||
}, [selected]);
|
||||
|
||||
useEffect(() => {
|
||||
setNodeDescription(description);
|
||||
setNodeDescription(description ?? "");
|
||||
}, [description]);
|
||||
|
||||
const MemoizedMarkdown = memo(Markdown);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export default function NodeName({
|
|||
beta,
|
||||
}: {
|
||||
display_name?: string;
|
||||
selected: boolean;
|
||||
selected?: boolean;
|
||||
nodeId: string;
|
||||
showNode: boolean;
|
||||
validationStatus: VertexBuildTypeAPI | null;
|
||||
|
|
@ -23,7 +23,7 @@ export default function NodeName({
|
|||
beta: boolean;
|
||||
}) {
|
||||
const [inputName, setInputName] = useState(false);
|
||||
const [nodeName, setNodeName] = useState(display_name);
|
||||
const [nodeName, setNodeName] = useState<string>(display_name ?? "");
|
||||
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
|
||||
const setNode = useFlowStore((state) => state.setNode);
|
||||
useEffect(() => {
|
||||
|
|
@ -33,7 +33,7 @@ export default function NodeName({
|
|||
}, [selected]);
|
||||
|
||||
useEffect(() => {
|
||||
setNodeName(display_name);
|
||||
setNodeName(display_name ?? "");
|
||||
}, [display_name]);
|
||||
|
||||
return inputName ? (
|
||||
|
|
@ -54,7 +54,7 @@ export default function NodeName({
|
|||
},
|
||||
}));
|
||||
} else {
|
||||
setNodeName(display_name);
|
||||
setNodeName(display_name ?? "");
|
||||
}
|
||||
}}
|
||||
value={nodeName}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ICON_STROKE_WIDTH } from "@/constants/constants";
|
||||
import { useUpdateNodeInternals } from "@xyflow/react";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { memo, useCallback, useEffect, useMemo, useRef } from "react";
|
||||
import { useUpdateNodeInternals } from "reactflow";
|
||||
import { default as IconComponent } from "../../../../components/common/genericIconComponent";
|
||||
import ShadTooltip from "../../../../components/common/shadTooltipComponent";
|
||||
import { Button } from "../../../../components/ui/button";
|
||||
|
|
@ -201,7 +201,8 @@ function NodeOutputField({
|
|||
const handleUpdateOutputHide = useCallback(
|
||||
(value?: boolean) => {
|
||||
setNode(data.id, (oldNode) => {
|
||||
const newNode = cloneDeep(oldNode);
|
||||
if (oldNode.type !== "genericNode") return oldNode;
|
||||
let newNode = cloneDeep(oldNode);
|
||||
newNode.data = {
|
||||
...newNode.data,
|
||||
node: {
|
||||
|
|
|
|||
|
|
@ -5,13 +5,7 @@ import useValidationStatusString from "@/CustomNodes/hooks/use-validation-status
|
|||
import ShadTooltip from "@/components/common/shadTooltipComponent";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
ICON_STROKE_WIDTH,
|
||||
RUN_TIMESTAMP_PREFIX,
|
||||
STATUS_BUILD,
|
||||
STATUS_BUILDING,
|
||||
STATUS_INACTIVE,
|
||||
} from "@/constants/constants";
|
||||
import { ICON_STROKE_WIDTH } from "@/constants/constants";
|
||||
import { BuildStatus } from "@/constants/enums";
|
||||
import { track } from "@/customization/utils/analytics";
|
||||
import { useDarkStore } from "@/stores/darkStore";
|
||||
|
|
@ -43,7 +37,7 @@ export default function NodeStatus({
|
|||
}: {
|
||||
nodeId: string;
|
||||
display_name: string;
|
||||
selected: boolean;
|
||||
selected?: boolean;
|
||||
setBorderColor: (color: string) => void;
|
||||
frozen?: boolean;
|
||||
showNode: boolean;
|
||||
|
|
@ -101,8 +95,7 @@ export default function NodeStatus({
|
|||
return cn(frozen ? frozenClass : className, updateClass);
|
||||
};
|
||||
const getNodeBorderClassName = (
|
||||
selected: boolean,
|
||||
showNode: boolean,
|
||||
selected: boolean | undefined,
|
||||
buildStatus: BuildStatus | undefined,
|
||||
validationStatus: VertexBuildTypeAPI | null,
|
||||
) => {
|
||||
|
|
@ -119,7 +112,7 @@ export default function NodeStatus({
|
|||
|
||||
useEffect(() => {
|
||||
setBorderColor(
|
||||
getNodeBorderClassName(selected, showNode, buildStatus, validationStatus),
|
||||
getNodeBorderClassName(selected, buildStatus, validationStatus),
|
||||
);
|
||||
}, [
|
||||
selected,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useDarkStore } from "@/stores/darkStore";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import { Connection, Handle, Position } from "@xyflow/react";
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Handle, Position } from "reactflow";
|
||||
import ShadTooltip from "../../../../components/common/shadTooltipComponent";
|
||||
import {
|
||||
isValidConnection,
|
||||
|
|
@ -413,7 +413,9 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
|||
type={left ? "target" : "source"}
|
||||
position={left ? Position.Left : Position.Right}
|
||||
id={myId}
|
||||
isValidConnection={validateConnection}
|
||||
isValidConnection={(connection) =>
|
||||
isValidConnection(connection as Connection, nodes, edges)
|
||||
}
|
||||
className={cn(
|
||||
`group/handle z-50 transition-all`,
|
||||
!showNode && "no-show",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import ForwardedIconComponent from "@/components/common/genericIconComponent";
|
||||
import ShadTooltip from "@/components/common/shadTooltipComponent";
|
||||
import { usePostValidateComponentCode } from "@/controllers/API/queries/nodes/use-post-validate-component-code";
|
||||
import { useUpdateNodeInternals } from "@xyflow/react";
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import { useUpdateNodeInternals } from "reactflow";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import {
|
||||
TOOLTIP_HIDDEN_OUTPUTS,
|
||||
|
|
@ -65,7 +65,7 @@ function GenericNode({
|
|||
selected,
|
||||
}: {
|
||||
data: NodeDataType;
|
||||
selected: boolean;
|
||||
selected?: boolean;
|
||||
xPos?: number;
|
||||
yPos?: number;
|
||||
}): JSX.Element {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import useAlertStore from "@/stores/alertStore";
|
|||
import useFlowStore from "@/stores/flowStore";
|
||||
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||
import { useShortcutsStore } from "@/stores/shortcuts";
|
||||
import { noteDataType } from "@/types/flow";
|
||||
import { NoteDataType } from "@/types/flow";
|
||||
import { classNames, cn, openInNewTab } from "@/utils/utils";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { memo, useCallback, useMemo } from "react";
|
||||
|
|
@ -22,7 +22,7 @@ const NoteToolbarComponent = memo(function NoteToolbarComponent({
|
|||
data,
|
||||
bgColor,
|
||||
}: {
|
||||
data: noteDataType;
|
||||
data: NoteDataType;
|
||||
bgColor: string;
|
||||
}) {
|
||||
const setNoticeData = useAlertStore((state) => state.setNoticeData);
|
||||
|
|
@ -69,21 +69,18 @@ const NoteToolbarComponent = memo(function NoteToolbarComponent({
|
|||
setLastCopiedSelection({ nodes: cloneDeep(node), edges: [] });
|
||||
break;
|
||||
case "duplicate":
|
||||
const targetNode = nodes.find((node) => node.id === data.id);
|
||||
if (targetNode) {
|
||||
paste(
|
||||
{
|
||||
nodes: [targetNode],
|
||||
edges: [],
|
||||
},
|
||||
{
|
||||
x: 50,
|
||||
y: 10,
|
||||
paneX: targetNode.position.x,
|
||||
paneY: targetNode.position.y,
|
||||
},
|
||||
);
|
||||
}
|
||||
paste(
|
||||
{
|
||||
nodes: [nodes.find((node) => node.id === data.id)!],
|
||||
edges: [],
|
||||
},
|
||||
{
|
||||
x: 50,
|
||||
y: 10,
|
||||
paneX: nodes.find((node) => node.id === data.id)?.position.x,
|
||||
paneY: nodes.find((node) => node.id === data.id)?.position.y,
|
||||
},
|
||||
);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,18 +5,18 @@ import {
|
|||
NOTE_NODE_MIN_HEIGHT,
|
||||
NOTE_NODE_MIN_WIDTH,
|
||||
} from "@/constants/constants";
|
||||
import { noteDataType } from "@/types/flow";
|
||||
import { NoteDataType } from "@/types/flow";
|
||||
import { cn } from "@/utils/utils";
|
||||
import { NodeResizer } from "@xyflow/react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { NodeResizer } from "reactflow";
|
||||
import NodeDescription from "../GenericNode/components/NodeDescription";
|
||||
import NoteToolbarComponent from "./NoteToolbarComponent";
|
||||
function NoteNode({
|
||||
data,
|
||||
selected,
|
||||
}: {
|
||||
data: noteDataType;
|
||||
selected: boolean;
|
||||
data: NoteDataType;
|
||||
selected?: boolean;
|
||||
}) {
|
||||
const bgColor =
|
||||
Object.keys(COLOR_OPTIONS).find(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { APIClassType } from "@/types/api";
|
||||
import { EdgeType } from "@/types/flow";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { Edge } from "reactflow";
|
||||
|
||||
export function processNodeAdvancedFields(
|
||||
resData: APIClassType,
|
||||
edges: Edge[],
|
||||
edges: EdgeType[],
|
||||
nodeId: string,
|
||||
) {
|
||||
let newNode = cloneDeep(resData);
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ import useAlertStore from "@/stores/alertStore";
|
|||
import useFlowStore from "@/stores/flowStore";
|
||||
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||
import { APIClassType, InputFieldType } from "@/types/api";
|
||||
import { NodeType } from "@/types/flow";
|
||||
import { AllNodeType } from "@/types/flow";
|
||||
import { useUpdateNodeInternals } from "@xyflow/react";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useUpdateNodeInternals } from "reactflow";
|
||||
import { mutateTemplate } from "../helpers/mutate-template";
|
||||
|
||||
export type handleOnNewValueType = (
|
||||
|
|
@ -29,7 +29,7 @@ const useHandleOnNewValue = ({
|
|||
name: string;
|
||||
setNode?: (
|
||||
id: string,
|
||||
update: NodeType | ((oldState: NodeType) => NodeType),
|
||||
update: AllNodeType | ((oldState: AllNodeType) => AllNodeType),
|
||||
) => void;
|
||||
}) => {
|
||||
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import useFlowStore from "@/stores/flowStore";
|
||||
import { NodeType } from "@/types/flow";
|
||||
import { AllNodeType } from "@/types/flow";
|
||||
import { useUpdateNodeInternals } from "@xyflow/react";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { useUpdateNodeInternals } from "reactflow";
|
||||
|
||||
const useHandleNodeClass = (
|
||||
nodeId: string,
|
||||
setMyNode?: (
|
||||
id: string,
|
||||
update: NodeType | ((oldState: NodeType) => NodeType),
|
||||
update: AllNodeType | ((oldState: AllNodeType) => AllNodeType),
|
||||
) => void,
|
||||
) => {
|
||||
const setNode = setMyNode ?? useFlowStore((state) => state.setNode);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { AllNodeType } from "@/types/flow";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { useCallback } from "react";
|
||||
import { APIClassType } from "../../types/api";
|
||||
import { NodeType } from "../../types/flow";
|
||||
|
||||
export type UpdateNodesType = {
|
||||
nodeId: string;
|
||||
|
|
@ -12,7 +12,9 @@ export type UpdateNodesType = {
|
|||
};
|
||||
|
||||
const useUpdateAllNodes = (
|
||||
setNodes: (callback: (oldNodes: NodeType[]) => NodeType[]) => void,
|
||||
setNodes: (
|
||||
update: AllNodeType[] | ((oldState: AllNodeType[]) => AllNodeType[]),
|
||||
) => void,
|
||||
updateNodeInternals: (nodeId: string) => void,
|
||||
) => {
|
||||
const updateAllNodes = useCallback(
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import useSaveFlow from "@/hooks/flows/use-save-flow";
|
|||
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import { cn } from "@/utils/utils";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { useEffect } from "react";
|
||||
import {
|
||||
ControlButton,
|
||||
Panel,
|
||||
|
|
@ -13,7 +11,9 @@ import {
|
|||
useStore,
|
||||
useStoreApi,
|
||||
type ReactFlowState,
|
||||
} from "reactflow";
|
||||
} from "@xyflow/react";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { useEffect } from "react";
|
||||
import { shallow } from "zustand/shallow";
|
||||
|
||||
type CustomControlButtonProps = {
|
||||
|
|
@ -106,7 +106,7 @@ const CanvasControls = ({ children }) => {
|
|||
return (
|
||||
<Panel
|
||||
data-testid="canvas_controls"
|
||||
className="react-flow__controls !m-2 flex gap-1.5 rounded-md border border-secondary-hover bg-background fill-foreground stroke-foreground p-1.5 text-primary shadow [&>button]:border-0 [&>button]:bg-background hover:[&>button]:bg-accent"
|
||||
className="react-flow__controls !m-2 flex !flex-row gap-1.5 rounded-md border border-secondary-hover bg-background fill-foreground stroke-foreground p-1.5 text-primary shadow [&>button]:border-0 [&>button]:bg-background hover:[&>button]:bg-accent"
|
||||
position="bottom-left"
|
||||
>
|
||||
{/* Zoom In */}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import AccordionComponent from "@/components/common/accordionComponent";
|
|||
import ShadTooltip from "@/components/common/shadTooltipComponent";
|
||||
import { EditNodeComponent } from "@/modals/editNodeModal/components/editNodeComponent";
|
||||
import { APIClassType } from "@/types/api";
|
||||
import { NodeType } from "@/types/flow";
|
||||
import { AllNodeType } from "@/types/flow";
|
||||
import { customStringify } from "@/utils/reactflowUtils";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ export function TweakComponent({
|
|||
node,
|
||||
}: {
|
||||
open: boolean;
|
||||
node: NodeType;
|
||||
node: AllNodeType;
|
||||
}) {
|
||||
const [nodeClass, setNodeClass] = useState<APIClassType | undefined>(
|
||||
node.data?.node,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { useTweaksStore } from "@/stores/tweaksStore";
|
||||
import { NodeType } from "@/types/flow";
|
||||
import { AllNodeType } from "@/types/flow";
|
||||
import { TweakComponent } from "../tweakComponent";
|
||||
|
||||
export function TweaksComponent({ open }: { open: boolean }) {
|
||||
const nodes = useTweaksStore((state) => state.nodes);
|
||||
return (
|
||||
<div className="h-full w-full overflow-y-auto overflow-x-hidden rounded-lg bg-muted custom-scroll">
|
||||
{nodes?.map((node: NodeType, i) => (
|
||||
{nodes?.map((node: AllNodeType, i) => (
|
||||
<div className="px-3" key={i}>
|
||||
<TweakComponent open={open} node={node} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { AllNodeType } from "@/types/flow";
|
||||
import "ag-grid-community/styles/ag-grid.css"; // Mandatory CSS required by the grid
|
||||
import "ag-grid-community/styles/ag-theme-balham.css"; // Optional Theme applied to the grid
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
|
|
@ -8,7 +9,6 @@ import {
|
|||
} from "../../../constants/constants";
|
||||
import { useDarkStore } from "../../../stores/darkStore";
|
||||
import { VertexBuildTypeAPI } from "../../../types/api";
|
||||
import { NodeType } from "../../../types/flow";
|
||||
import ForwardedIconComponent from "../../common/genericIconComponent";
|
||||
import Loading from "../../ui/loading";
|
||||
import TableComponent from "../parameterRenderComponent/components/tableComponent";
|
||||
|
|
@ -18,7 +18,7 @@ function CsvOutputComponent({
|
|||
csvNode,
|
||||
flowPool,
|
||||
}: {
|
||||
csvNode: NodeType;
|
||||
csvNode: AllNodeType;
|
||||
flowPool: VertexBuildTypeAPI;
|
||||
}) {
|
||||
const csvNodeArtifacts = flowPool?.data?.artifacts?.repr;
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import {
|
|||
ENABLE_LANGFLOW_STORE,
|
||||
} from "@/customization/feature-flags";
|
||||
import { track } from "@/customization/utils/analytics";
|
||||
import { Panel } from "@xyflow/react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import { Panel } from "reactflow";
|
||||
import ApiModal from "../../../modals/apiModal";
|
||||
import ShareModal from "../../../modals/shareModal";
|
||||
import useFlowStore from "../../../stores/flowStore";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import useHandleOnNewValue from "@/CustomNodes/hooks/use-handle-new-value";
|
||||
import ShadTooltip from "@/components/common/shadTooltipComponent";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import { APIClassType } from "@/types/api";
|
||||
import { isTargetHandleConnected } from "@/utils/reactflowUtils";
|
||||
import { CustomCellRendererProps } from "ag-grid-react";
|
||||
import ToggleShadComponent from "../../../toggleShadComponent";
|
||||
|
|
@ -20,7 +21,7 @@ export default function TableAdvancedToggleCellRender({
|
|||
);
|
||||
|
||||
const { handleOnNewValue } = useHandleOnNewValue({
|
||||
node: node?.data.node,
|
||||
node: node?.data.node as APIClassType,
|
||||
nodeId,
|
||||
name: parameterId,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import useHandleNodeClass from "@/CustomNodes/hooks/use-handle-node-class";
|
|||
import { ParameterRenderComponent } from "@/components/core/parameterRenderComponent";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import { useTweaksStore } from "@/stores/tweaksStore";
|
||||
import { APIClassType } from "@/types/api";
|
||||
import { isTargetHandleConnected } from "@/utils/reactflowUtils";
|
||||
import { CustomCellRendererProps } from "ag-grid-react";
|
||||
|
||||
|
|
@ -25,7 +26,7 @@ export default function TableNodeCellRender({
|
|||
);
|
||||
|
||||
const { handleOnNewValue } = useHandleOnNewValue({
|
||||
node: node?.data.node,
|
||||
node: node?.data.node as APIClassType,
|
||||
nodeId,
|
||||
name: parameterId,
|
||||
setNode: isTweaks ? setNode : undefined,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { GradientWrapper } from "@/components/common/GradientWrapper";
|
||||
import { CustomWrapper } from "@/customization/custom-wrapper";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { ReactFlowProvider } from "@xyflow/react";
|
||||
import { ReactNode } from "react";
|
||||
import { ReactFlowProvider } from "reactflow";
|
||||
import { TooltipProvider } from "../components/ui/tooltip";
|
||||
import { ApiInterceptor } from "../controllers/API/api";
|
||||
import { AuthProvider } from "./authContext";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Edge, Node, ReactFlowJsonObject } from "@xyflow/react";
|
||||
import { AxiosRequestConfig, AxiosResponse } from "axios";
|
||||
import { Edge, Node, ReactFlowJsonObject } from "reactflow";
|
||||
import { BASE_URL_API } from "../../constants/constants";
|
||||
import { api } from "../../controllers/API/api";
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useMutationFunctionType } from "@/types/api";
|
||||
import { UseMutationResult } from "@tanstack/react-query";
|
||||
import { ReactFlowJsonObject } from "reactflow";
|
||||
import { ReactFlowJsonObject } from "@xyflow/react";
|
||||
import { api } from "../../api";
|
||||
import { getURL } from "../../helpers/constants";
|
||||
import { UseRequestProcessor } from "../../services/request-processor";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useFolderStore } from "@/stores/foldersStore";
|
||||
import { useMutationFunctionType } from "@/types/api";
|
||||
import { UseMutationResult } from "@tanstack/react-query";
|
||||
import { ReactFlowJsonObject } from "reactflow";
|
||||
import { ReactFlowJsonObject } from "@xyflow/react";
|
||||
import { api } from "../../api";
|
||||
import { getURL } from "../../helpers/constants";
|
||||
import { UseRequestProcessor } from "../../services/request-processor";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { useDarkStore } from "@/stores/darkStore";
|
||||
import { useQueryFunctionType } from "@/types/api";
|
||||
import { api } from "../../api";
|
||||
import { getURL } from "../../helpers/constants";
|
||||
|
|
@ -24,7 +23,7 @@ interface IApiQueryResponse {
|
|||
export const useGetStarterProjectsQuery: useQueryFunctionType<
|
||||
undefined,
|
||||
IApiQueryResponse
|
||||
> = (_, options) => {
|
||||
> = (options) => {
|
||||
const { query } = UseRequestProcessor();
|
||||
|
||||
const getStarterProjectsFn = async () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useMutationFunctionType } from "@/types/api";
|
||||
import { ReactFlowJsonObject } from "@xyflow/react";
|
||||
import { AxiosRequestConfig } from "axios";
|
||||
import { ReactFlowJsonObject } from "reactflow";
|
||||
import { api } from "../../api";
|
||||
import { getURL } from "../../helpers/constants";
|
||||
import { UseRequestProcessor } from "../../services/request-processor";
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
|||
import useFlowStore from "@/stores/flowStore";
|
||||
import { FlowType } from "@/types/flow";
|
||||
import { customStringify } from "@/utils/reactflowUtils";
|
||||
import { ReactFlowJsonObject } from "reactflow";
|
||||
import { ReactFlowJsonObject } from "@xyflow/react";
|
||||
|
||||
const useSaveFlow = () => {
|
||||
const flows = useFlowsManagerStore((state) => state.flows);
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import { NODE_WIDTH } from "@/constants/constants";
|
|||
import { track } from "@/customization/utils/analytics";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import { APIClassType } from "@/types/api";
|
||||
import { NodeType } from "@/types/flow";
|
||||
import { AllNodeType } from "@/types/flow";
|
||||
import { getNodeId } from "@/utils/reactflowUtils";
|
||||
import { getNodeRenderType } from "@/utils/utils";
|
||||
import { useStoreApi } from "@xyflow/react";
|
||||
import { useCallback } from "react";
|
||||
import { useStoreApi } from "reactflow";
|
||||
|
||||
export function useAddComponent() {
|
||||
const store = useStoreApi();
|
||||
|
|
@ -50,7 +50,7 @@ export function useAddComponent() {
|
|||
|
||||
const newId = getNodeId(type);
|
||||
|
||||
const newNode: NodeType = {
|
||||
const newNode: AllNodeType = {
|
||||
id: newId,
|
||||
type: getNodeRenderType("genericnode"),
|
||||
position: { x: 0, y: 0 },
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import useHandleNewValue from "@/CustomNodes/hooks/use-handle-new-value";
|
||||
import { NodeType } from "@/types/flow";
|
||||
import { AllNodeType } from "@/types/flow";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { useState } from "react";
|
||||
import ImageViewer from "../../../../components/common/ImageViewer";
|
||||
|
|
@ -35,7 +35,9 @@ export default function IOFieldView({
|
|||
const nodes = useFlowStore((state) => state.nodes);
|
||||
const setNode = useFlowStore((state) => state.setNode);
|
||||
const flowPool = useFlowStore((state) => state.flowPool);
|
||||
const node: NodeType | undefined = nodes.find((node) => node.id === fieldId);
|
||||
const node: AllNodeType | undefined = nodes.find(
|
||||
(node) => node.id === fieldId,
|
||||
);
|
||||
const flowPoolNode = (flowPool[node!.id] ?? [])[
|
||||
(flowPool[node!.id]?.length ?? 1) - 1
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
import AccordionComponent from "@/components/common/accordionComponent";
|
||||
import {
|
||||
useDeleteMessages,
|
||||
useGetMessagesQuery,
|
||||
} from "@/controllers/API/queries/messages";
|
||||
import { useUtilityStore } from "@/stores/utilityStore";
|
||||
import { someFlowTemplateFields } from "@/utils/reactflowUtils";
|
||||
import { useEffect, useState } from "react";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import AccordionComponent from "../../components/accordionComponent";
|
||||
import IconComponent from "../../components/common/genericIconComponent";
|
||||
import ShadTooltip from "../../components/common/shadTooltipComponent";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
|
|
@ -24,7 +22,7 @@ import useFlowStore from "../../stores/flowStore";
|
|||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||
import { useMessagesStore } from "../../stores/messagesStore";
|
||||
import { IOModalPropsType } from "../../types/components";
|
||||
import { NodeType } from "../../types/flow";
|
||||
import { AllNodeType } from "../../types/flow";
|
||||
import { cn } from "../../utils/utils";
|
||||
import BaseModal from "../baseModal";
|
||||
import IOFieldView from "./components/IOFieldView";
|
||||
|
|
@ -168,7 +166,7 @@ export default function IOModal({
|
|||
// refetch();
|
||||
setLockChat(false);
|
||||
if (chatInput) {
|
||||
setNode(chatInput.id, (node: NodeType) => {
|
||||
setNode(chatInput.id, (node: AllNodeType) => {
|
||||
const newNode = { ...node };
|
||||
|
||||
newNode.data.node!.template["input_value"].value = chatValue;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { NodeType } from "@/types/flow";
|
||||
import { AllNodeType } from "@/types/flow";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { LANGFLOW_SUPPORTED_TYPES } from "../../../constants/constants";
|
||||
|
||||
export const getNodesWithDefaultValue = (nodes: NodeType[]) => {
|
||||
const filteredNodes: NodeType[] = [];
|
||||
export const getNodesWithDefaultValue = (nodes: AllNodeType[]) => {
|
||||
const filteredNodes: AllNodeType[] = [];
|
||||
|
||||
nodes.forEach((node) => {
|
||||
if (node?.data?.node?.template && node?.type === "genericNode") {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import useFlowStore from "@/stores/flowStore";
|
||||
import { ConnectionLineComponentProps } from "reactflow";
|
||||
import { ConnectionLineComponentProps } from "@xyflow/react";
|
||||
|
||||
const ConnectionLineComponent = ({
|
||||
fromX,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,17 @@ import useUploadFlow from "@/hooks/flows/use-upload-flow";
|
|||
import { useAddComponent } from "@/hooks/useAddComponent";
|
||||
import { nodeColorsName } from "@/utils/styleUtils";
|
||||
import { cn, isSupportedNodeTypes } from "@/utils/utils";
|
||||
import {
|
||||
Background,
|
||||
Connection,
|
||||
Edge,
|
||||
OnNodeDrag,
|
||||
OnSelectionChangeParams,
|
||||
Panel,
|
||||
ReactFlow,
|
||||
reconnectEdge,
|
||||
SelectionDragHandler,
|
||||
} from "@xyflow/react";
|
||||
import _, { cloneDeep } from "lodash";
|
||||
import {
|
||||
KeyboardEvent,
|
||||
|
|
@ -30,16 +41,6 @@ import {
|
|||
useState,
|
||||
} from "react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import ReactFlow, {
|
||||
Background,
|
||||
Connection,
|
||||
Edge,
|
||||
NodeDragHandler,
|
||||
OnSelectionChangeParams,
|
||||
Panel,
|
||||
SelectionDragHandler,
|
||||
updateEdge,
|
||||
} from "reactflow";
|
||||
import GenericNode from "../../../../CustomNodes/GenericNode";
|
||||
import {
|
||||
INVALID_SELECTION_ERROR_ALERT,
|
||||
|
|
@ -53,7 +54,7 @@ import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
|
|||
import { useShortcutsStore } from "../../../../stores/shortcuts";
|
||||
import { useTypesStore } from "../../../../stores/typesStore";
|
||||
import { APIClassType } from "../../../../types/api";
|
||||
import { NodeType } from "../../../../types/flow";
|
||||
import { AllNodeType, EdgeType, NoteNodeType } from "../../../../types/flow";
|
||||
import {
|
||||
generateFlow,
|
||||
generateNodeFromFlow,
|
||||
|
|
@ -323,14 +324,14 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
[takeSnapshot, onConnect],
|
||||
);
|
||||
|
||||
const onNodeDragStart: NodeDragHandler = useCallback(() => {
|
||||
const onNodeDragStart: OnNodeDrag = useCallback(() => {
|
||||
// 👇 make dragging a node undoable
|
||||
|
||||
takeSnapshot();
|
||||
// 👉 you can place your event handlers here
|
||||
}, [takeSnapshot]);
|
||||
|
||||
const onNodeDragStop: NodeDragHandler = useCallback(() => {
|
||||
const onNodeDragStop: OnNodeDrag = useCallback(() => {
|
||||
// 👇 make moving the canvas undoable
|
||||
autoSaveFlow();
|
||||
updateCurrentFlow({ nodes });
|
||||
|
|
@ -405,12 +406,14 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
}, []);
|
||||
|
||||
const onEdgeUpdate = useCallback(
|
||||
(oldEdge: Edge, newConnection: Connection) => {
|
||||
(oldEdge: EdgeType, newConnection: Connection) => {
|
||||
if (isValidConnection(newConnection, nodes, edges)) {
|
||||
edgeUpdateSuccessful.current = true;
|
||||
oldEdge.data.targetHandle = scapeJSONParse(newConnection.targetHandle!);
|
||||
oldEdge.data.sourceHandle = scapeJSONParse(newConnection.sourceHandle!);
|
||||
setEdges((els) => updateEdge(oldEdge, newConnection, els));
|
||||
oldEdge.data = {
|
||||
targetHandle: scapeJSONParse(newConnection.targetHandle!),
|
||||
sourceHandle: scapeJSONParse(newConnection.sourceHandle!),
|
||||
};
|
||||
setEdges((els) => reconnectEdge(oldEdge, newConnection, els));
|
||||
}
|
||||
},
|
||||
[setEdges],
|
||||
|
|
@ -472,7 +475,7 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
};
|
||||
const newId = getNodeId(data.type);
|
||||
|
||||
const newNode: NodeType = {
|
||||
const newNode: NoteNodeType = {
|
||||
id: newId,
|
||||
type: "noteNode",
|
||||
position: position || { x: 0, y: 0 },
|
||||
|
|
@ -521,7 +524,7 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
<div className="h-full w-full bg-canvas" ref={reactFlowWrapper}>
|
||||
{showCanvas ? (
|
||||
<div id="react-flow-id" className="h-full w-full bg-canvas">
|
||||
<ReactFlow
|
||||
<ReactFlow<AllNodeType, EdgeType>
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onNodesChange={onNodesChange}
|
||||
|
|
@ -530,9 +533,9 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
disableKeyboardA11y={true}
|
||||
onInit={setReactFlowInstance}
|
||||
nodeTypes={nodeTypes}
|
||||
onEdgeUpdate={onEdgeUpdate}
|
||||
onEdgeUpdateStart={onEdgeUpdateStart}
|
||||
onEdgeUpdateEnd={onEdgeUpdateEnd}
|
||||
onReconnect={onEdgeUpdate}
|
||||
onReconnectStart={onEdgeUpdateStart}
|
||||
onReconnectEnd={onEdgeUpdateEnd}
|
||||
onNodeDragStart={onNodeDragStart}
|
||||
onSelectionDragStart={onSelectionDragStart}
|
||||
onSelectionEnd={onSelectionEnd}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { NodeToolbar } from "@xyflow/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import { NodeToolbar } from "reactflow";
|
||||
import ShadTooltip from "../../../../components/common/shadTooltipComponent";
|
||||
import { Button } from "../../../../components/ui/button";
|
||||
import { GradientGroup } from "../../../../icons/GradientSparkles";
|
||||
|
|
@ -80,6 +80,7 @@ export default function SelectionMenu({
|
|||
}`}
|
||||
onClick={onClick}
|
||||
disabled={disable}
|
||||
data-testid="error-group-node"
|
||||
>
|
||||
<GradientGroup
|
||||
strokeWidth={1.5}
|
||||
|
|
@ -100,6 +101,7 @@ export default function SelectionMenu({
|
|||
}`}
|
||||
onClick={onClick}
|
||||
disabled={disable}
|
||||
data-testid="group-node"
|
||||
>
|
||||
<GradientGroup
|
||||
strokeWidth={1.5}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
|||
import useFlowStore from "@/stores/flowStore";
|
||||
import { useTypesStore } from "@/stores/typesStore";
|
||||
import { cn } from "@/utils/utils";
|
||||
import { useUpdateNodeInternals } from "@xyflow/react";
|
||||
import { useState } from "react";
|
||||
import { useUpdateNodeInternals } from "reactflow";
|
||||
|
||||
export default function UpdateAllComponents() {
|
||||
const { componentsToUpdate, nodes, edges, setNodes } = useFlowStore();
|
||||
|
|
@ -36,7 +36,7 @@ export default function UpdateAllComponents() {
|
|||
|
||||
const updatePromises = componentsToUpdate.map((nodeId) => {
|
||||
const node = nodes.find((n) => n.id === nodeId);
|
||||
if (!node) return Promise.resolve();
|
||||
if (!node || node.type !== "genericNode") return Promise.resolve();
|
||||
|
||||
const thisNodeTemplate = templates[node.data.type]?.template;
|
||||
if (!thisNodeTemplate?.code) return Promise.resolve();
|
||||
|
|
@ -46,7 +46,7 @@ export default function UpdateAllComponents() {
|
|||
return new Promise((resolve) => {
|
||||
validateComponentCode({
|
||||
code: currentCode,
|
||||
frontend_node: node.data.node,
|
||||
frontend_node: node.data.node!,
|
||||
})
|
||||
.then(({ data: resData, type }) => {
|
||||
if (resData && type) {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ import { usePostTemplateValue } from "@/controllers/API/queries/nodes/use-post-t
|
|||
import { usePostRetrieveVertexOrder } from "@/controllers/API/queries/vertex";
|
||||
import useAddFlow from "@/hooks/flows/use-add-flow";
|
||||
import { APIClassType } from "@/types/api";
|
||||
import { useUpdateNodeInternals } from "@xyflow/react";
|
||||
import _, { cloneDeep } from "lodash";
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useUpdateNodeInternals } from "reactflow";
|
||||
import IconComponent from "../../../../components/common/genericIconComponent";
|
||||
import {
|
||||
Select,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ export const useGetTemplateStyle = (
|
|||
flowData: FlowType,
|
||||
): { getIcon: () => string } => {
|
||||
const getIcon = () => {
|
||||
if (flowData.is_component) {
|
||||
if (
|
||||
flowData.is_component &&
|
||||
flowData.data?.nodes[0].type === "genericNode"
|
||||
) {
|
||||
const dataType = flowData.data?.nodes[0].data.type;
|
||||
const isGroup = !!flowData.data?.nodes[0].data.node?.flow;
|
||||
const icon = flowData.data?.nodes[0].data.node?.icon;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,11 @@ export default function EditShortcutButton({
|
|||
}: {
|
||||
children: JSX.Element;
|
||||
shortcut: string[];
|
||||
defaultShortcuts: Array<{ name: string; shortcut: string }>;
|
||||
defaultShortcuts: Array<{
|
||||
name: string;
|
||||
shortcut: string;
|
||||
display_name: string;
|
||||
}>;
|
||||
open: boolean;
|
||||
setOpen: (bool: boolean) => void;
|
||||
disable?: boolean;
|
||||
|
|
@ -64,10 +68,15 @@ export default function EditShortcutButton({
|
|||
if (s.name === shortcut[0]) {
|
||||
return {
|
||||
name: s.name,
|
||||
display_name: s.display_name,
|
||||
shortcut: fixCombination.join("").toLowerCase(),
|
||||
};
|
||||
}
|
||||
return { name: s.name, shortcut: s.shortcut };
|
||||
return {
|
||||
name: s.name,
|
||||
display_name: s.display_name,
|
||||
shortcut: s.shortcut,
|
||||
};
|
||||
});
|
||||
const shortcutName = toCamelCase(shortcut[0]);
|
||||
setUniqueShortcut(shortcutName, fixCombination.join("").toLowerCase());
|
||||
|
|
|
|||
|
|
@ -4,16 +4,15 @@ import {
|
|||
} from "@/constants/constants";
|
||||
import { track } from "@/customization/utils/analytics";
|
||||
import { brokenEdgeMessage } from "@/utils/utils";
|
||||
import { cloneDeep, zip } from "lodash";
|
||||
import {
|
||||
Edge,
|
||||
EdgeChange,
|
||||
Node,
|
||||
NodeChange,
|
||||
addEdge,
|
||||
applyEdgeChanges,
|
||||
applyNodeChanges,
|
||||
} from "reactflow";
|
||||
} from "@xyflow/react";
|
||||
import { cloneDeep, zip } from "lodash";
|
||||
import { create } from "zustand";
|
||||
import {
|
||||
FLOW_BUILD_SUCCESS_ALERT,
|
||||
|
|
@ -23,8 +22,9 @@ import { BuildStatus } from "../constants/enums";
|
|||
import { VertexBuildTypeAPI } from "../types/api";
|
||||
import { ChatInputType, ChatOutputType } from "../types/chat";
|
||||
import {
|
||||
AllNodeType,
|
||||
EdgeType,
|
||||
NodeDataType,
|
||||
NodeType,
|
||||
sourceHandleType,
|
||||
targetHandleType,
|
||||
} from "../types/flow";
|
||||
|
|
@ -68,16 +68,19 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
let outdatedNodes: string[] = [];
|
||||
const templates = useTypesStore.getState().templates;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const currentCode = templates[nodes[i].data?.type]?.template?.code?.value;
|
||||
const thisNodesCode = nodes[i].data?.node!.template?.code?.value;
|
||||
if (
|
||||
currentCode &&
|
||||
thisNodesCode &&
|
||||
currentCode !== thisNodesCode &&
|
||||
!nodes[i].data?.node?.edited &&
|
||||
!componentsToIgnoreUpdate.includes(nodes[i].data?.type)
|
||||
) {
|
||||
outdatedNodes.push(nodes[i].id);
|
||||
let node = nodes[i];
|
||||
if (node.type === "genericNode") {
|
||||
const currentCode = templates[node.data?.type]?.template?.code?.value;
|
||||
const thisNodesCode = node.data?.node!.template?.code?.value;
|
||||
if (
|
||||
currentCode &&
|
||||
thisNodesCode &&
|
||||
currentCode !== thisNodesCode &&
|
||||
!node.data?.node?.edited &&
|
||||
!componentsToIgnoreUpdate.includes(node.data?.type)
|
||||
) {
|
||||
outdatedNodes.push(node.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
set({ componentsToUpdate: outdatedNodes });
|
||||
|
|
@ -122,10 +125,13 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
set({ flowPool });
|
||||
},
|
||||
updateToolMode: (nodeId: string, toolMode: boolean) => {
|
||||
get().setNode(nodeId, (node) => ({
|
||||
...node,
|
||||
data: { ...node.data, node: { ...node.data.node, tool_mode: toolMode } },
|
||||
}));
|
||||
get().setNode(nodeId, (node) => {
|
||||
let newNode = cloneDeep(node);
|
||||
if (newNode.type === "genericNode") {
|
||||
newNode.data.node!.tool_mode = toolMode;
|
||||
}
|
||||
return newNode;
|
||||
});
|
||||
},
|
||||
updateFreezeStatus: (nodeIds: string[], freeze: boolean) => {
|
||||
get().setNodes((oldNodes) => {
|
||||
|
|
@ -223,12 +229,12 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
setReactFlowInstance: (newState) => {
|
||||
set({ reactFlowInstance: newState });
|
||||
},
|
||||
onNodesChange: (changes: NodeChange[]) => {
|
||||
onNodesChange: (changes: NodeChange<AllNodeType>[]) => {
|
||||
set({
|
||||
nodes: applyNodeChanges(changes, get().nodes),
|
||||
});
|
||||
},
|
||||
onEdgesChange: (changes: EdgeChange[]) => {
|
||||
onEdgesChange: (changes: EdgeChange<EdgeType>[]) => {
|
||||
set({
|
||||
edges: applyEdgeChanges(changes, get().edges),
|
||||
});
|
||||
|
|
@ -264,7 +270,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
},
|
||||
setNode: (
|
||||
id: string,
|
||||
change: Node | ((oldState: Node) => Node),
|
||||
change: AllNodeType | ((oldState: AllNodeType) => AllNodeType),
|
||||
isUserChange: boolean = true,
|
||||
callback?: () => void,
|
||||
) => {
|
||||
|
|
@ -305,8 +311,8 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
},
|
||||
deleteNode: (nodeId) => {
|
||||
const { filteredNodes, deletedNode } = get().nodes.reduce<{
|
||||
filteredNodes: Node[];
|
||||
deletedNode: Node | null;
|
||||
filteredNodes: AllNodeType[];
|
||||
deletedNode: AllNodeType | null;
|
||||
}>(
|
||||
(acc, node) => {
|
||||
const isMatch =
|
||||
|
|
@ -362,7 +368,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
let minimumX = Infinity;
|
||||
let minimumY = Infinity;
|
||||
let idsMap = {};
|
||||
let newNodes: Node<NodeDataType>[] = get().nodes;
|
||||
let newNodes: AllNodeType[] = get().nodes;
|
||||
let newEdges = get().edges;
|
||||
selection.nodes.forEach((node: Node) => {
|
||||
if (node.position.y < minimumY) {
|
||||
|
|
@ -380,15 +386,15 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
y: position.y,
|
||||
});
|
||||
|
||||
selection.nodes.forEach((node: NodeType) => {
|
||||
selection.nodes.forEach((node: AllNodeType) => {
|
||||
// Generate a unique node ID
|
||||
let newId = getNodeId(node.data.type);
|
||||
idsMap[node.id] = newId;
|
||||
|
||||
// Create a new node object
|
||||
const newNode: NodeType = {
|
||||
// Create a new node object with the correct type
|
||||
const newNode = {
|
||||
id: newId,
|
||||
type: node.type,
|
||||
type: node.type as "genericNode" | "noteNode",
|
||||
position: {
|
||||
x: insidePosition.x + node.position!.x - minimumX,
|
||||
y: insidePosition.y + node.position!.y - minimumY,
|
||||
|
|
@ -397,7 +403,8 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
...cloneDeep(node.data),
|
||||
id: newId,
|
||||
},
|
||||
};
|
||||
} as AllNodeType;
|
||||
|
||||
updateGroupRecursion(
|
||||
newNode,
|
||||
selection.edges,
|
||||
|
|
@ -412,7 +419,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
});
|
||||
get().setNodes(newNodes);
|
||||
|
||||
selection.edges.forEach((edge: Edge) => {
|
||||
selection.edges.forEach((edge: EdgeType) => {
|
||||
let source = idsMap[edge.source];
|
||||
let target = idsMap[edge.target];
|
||||
const sourceHandleObject: sourceHandleType = scapeJSONParse(
|
||||
|
|
@ -424,7 +431,6 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
});
|
||||
sourceHandleObject.id = source;
|
||||
|
||||
edge.data.sourceHandle = sourceHandleObject;
|
||||
const targetHandleObject: targetHandleType = scapeJSONParse(
|
||||
edge.targetHandle!,
|
||||
);
|
||||
|
|
@ -433,7 +439,12 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
id: target,
|
||||
});
|
||||
targetHandleObject.id = target;
|
||||
edge.data.targetHandle = targetHandleObject;
|
||||
|
||||
edge.data = {
|
||||
sourceHandle: sourceHandleObject,
|
||||
targetHandle: targetHandleObject,
|
||||
};
|
||||
|
||||
let id = getHandleId(source, sourceHandle, target, targetHandle);
|
||||
newEdges = addEdge(
|
||||
{
|
||||
|
|
@ -516,7 +527,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
// isIoOut = outputTypes.has(sourceType);
|
||||
// }
|
||||
|
||||
let newEdges: Edge[] = [];
|
||||
let newEdges: EdgeType[] = [];
|
||||
get().setEdges((oldEdges) => {
|
||||
newEdges = addEdge(
|
||||
{
|
||||
|
|
@ -733,7 +744,10 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
|
||||
const edges = get().edges;
|
||||
const newEdges = edges.map((edge) => {
|
||||
if (idList.includes(edge.data.targetHandle.id)) {
|
||||
if (
|
||||
edge.data?.targetHandle &&
|
||||
idList.includes(edge.data.targetHandle.id ?? "")
|
||||
) {
|
||||
edge.className = "ran";
|
||||
}
|
||||
return edge;
|
||||
|
|
@ -759,7 +773,10 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
updateEdgesRunningByNodes: (ids: string[], running: boolean) => {
|
||||
const edges = get().edges;
|
||||
const newEdges = edges.map((edge) => {
|
||||
if (ids.includes(edge.data.sourceHandle.id)) {
|
||||
if (
|
||||
edge.data?.sourceHandle &&
|
||||
ids.includes(edge.data.sourceHandle.id ?? "")
|
||||
) {
|
||||
edge.animated = running;
|
||||
edge.className = running ? "running" : "";
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
UseQueryOptions,
|
||||
UseQueryResult,
|
||||
} from "@tanstack/react-query";
|
||||
import { Edge, Node, Viewport } from "reactflow";
|
||||
import { Edge, Node, Viewport } from "@xyflow/react";
|
||||
import { ChatInputType, ChatOutputType } from "../chat";
|
||||
import { FlowType } from "../flow";
|
||||
//kind and class are just representative names to represent the actual structure of the object received by the API
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { ReactFlowJsonObject } from "@xyflow/react";
|
||||
import { ReactElement, ReactNode } from "react";
|
||||
import { ReactFlowJsonObject } from "reactflow";
|
||||
import { InputOutput } from "../../constants/enums";
|
||||
import {
|
||||
APIClassType,
|
||||
|
|
@ -8,7 +8,12 @@ import {
|
|||
OutputFieldProxyType,
|
||||
} from "../api";
|
||||
import { ChatMessageType } from "../chat";
|
||||
import { FlowStyleType, FlowType, NodeDataType, NodeType } from "../flow/index";
|
||||
import {
|
||||
AllNodeType,
|
||||
FlowStyleType,
|
||||
FlowType,
|
||||
NodeDataType,
|
||||
} from "../flow/index";
|
||||
import { sourceHandleType, targetHandleType } from "./../flow/index";
|
||||
export type InputComponentType = {
|
||||
name?: string;
|
||||
|
|
@ -692,11 +697,11 @@ export type tabsArrayType = {
|
|||
|
||||
export type codeTabsPropsType = {
|
||||
open?: boolean;
|
||||
tabs: Array<tabsArrayType>;
|
||||
tabs: tabsArrayType[];
|
||||
activeTab: string;
|
||||
setActiveTab: (value: string) => void;
|
||||
isMessage?: boolean;
|
||||
tweaksNodes?: Array<NodeType>;
|
||||
tweaksNodes?: AllNodeType[];
|
||||
activeTweaks?: boolean;
|
||||
setActiveTweaks?: (value: boolean) => void;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ReactFlowJsonObject, XYPosition } from "reactflow";
|
||||
import { Edge, Node, ReactFlowJsonObject } from "@xyflow/react";
|
||||
import { BuildStatus } from "../../constants/enums";
|
||||
import { APIClassType } from "../api/index";
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ export type PaginatedFlowsType = {
|
|||
export type FlowType = {
|
||||
name: string;
|
||||
id: string;
|
||||
data: ReactFlowJsonObject | null;
|
||||
data: ReactFlowJsonObject<AllNodeType, EdgeType> | null;
|
||||
description: string;
|
||||
endpoint_name?: string | null;
|
||||
style?: FlowStyleType;
|
||||
|
|
@ -33,38 +33,46 @@ export type FlowType = {
|
|||
locked?: boolean | null;
|
||||
};
|
||||
|
||||
export type NodeType = {
|
||||
id: string;
|
||||
type?: string;
|
||||
position: XYPosition;
|
||||
data: NodeDataType;
|
||||
selected?: boolean;
|
||||
};
|
||||
export type GenericNodeType = Node<NodeDataType, "genericNode">;
|
||||
export type NoteNodeType = Node<NoteDataType, "noteNode">;
|
||||
|
||||
export interface noteClassType
|
||||
extends Pick<APIClassType, "description" | "display_name" | "documentation"> {
|
||||
export type AllNodeType = GenericNodeType | NoteNodeType;
|
||||
export type SetNodeType<T = "genericNode" | "noteNode"> =
|
||||
T extends "genericNode" ? GenericNodeType : NoteNodeType;
|
||||
|
||||
export type noteClassType = Pick<
|
||||
APIClassType,
|
||||
"description" | "display_name" | "documentation" | "tool_mode" | "frozen"
|
||||
> & {
|
||||
template: {
|
||||
backgroundColor: string;
|
||||
backgroundColor?: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export interface noteDataType
|
||||
extends Pick<NodeDataType, "showNode" | "type" | "id"> {
|
||||
export type NoteDataType = {
|
||||
showNode?: boolean;
|
||||
type: string;
|
||||
node?: noteClassType;
|
||||
node: noteClassType;
|
||||
id: string;
|
||||
}
|
||||
};
|
||||
export type NodeDataType = {
|
||||
showNode?: boolean;
|
||||
type: string;
|
||||
node?: APIClassType;
|
||||
node: APIClassType;
|
||||
id: string;
|
||||
output_types?: string[];
|
||||
selected_output_type?: string;
|
||||
buildStatus?: BuildStatus;
|
||||
};
|
||||
|
||||
export type EdgeType = Edge<EdgeDataType, "default">;
|
||||
|
||||
export type EdgeDataType = {
|
||||
sourceHandle: sourceHandleType;
|
||||
targetHandle: targetHandleType;
|
||||
};
|
||||
|
||||
// FlowStyleType is the type of the style object that is used to style the
|
||||
// Flow card with an emoji and a color.
|
||||
export type FlowStyleType = {
|
||||
|
|
@ -83,6 +91,7 @@ export type TweaksType = Array<
|
|||
|
||||
// right side
|
||||
export type sourceHandleType = {
|
||||
baseClasses?: string[];
|
||||
dataType: string;
|
||||
id: string;
|
||||
output_types: string[];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { XYPosition } from "reactflow";
|
||||
import { XYPosition } from "@xyflow/react";
|
||||
import { FlowType, NodeDataType } from "../flow";
|
||||
|
||||
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { Edge } from "reactflow";
|
||||
import { FlowType, NodeType } from "../flow";
|
||||
import { Edge } from "@xyflow/react";
|
||||
import { AllNodeType, EdgeType, FlowType } from "../flow";
|
||||
|
||||
export type addEscapedHandleIdsToEdgesType = {
|
||||
edges: Edge[];
|
||||
edges: EdgeType[];
|
||||
};
|
||||
|
||||
export type updateEdgesHandleIdsType = {
|
||||
nodes: NodeType[];
|
||||
edges: Edge[];
|
||||
nodes: AllNodeType[];
|
||||
edges: EdgeType[];
|
||||
};
|
||||
|
||||
export type generateFlowType = { newFlow: FlowType; removedEdges: Edge[] };
|
||||
|
||||
export type findLastNodeType = {
|
||||
nodes: NodeType[];
|
||||
edges: Edge[];
|
||||
nodes: AllNodeType[];
|
||||
edges: EdgeType[];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import { FlowType } from "@/types/flow";
|
||||
import { AllNodeType, EdgeType, FlowType } from "@/types/flow";
|
||||
import {
|
||||
Connection,
|
||||
Edge,
|
||||
Node,
|
||||
OnEdgesChange,
|
||||
OnNodesChange,
|
||||
ReactFlowInstance,
|
||||
Viewport,
|
||||
} from "reactflow";
|
||||
} from "@xyflow/react";
|
||||
import { BuildStatus } from "../../../constants/enums";
|
||||
import { VertexBuildTypeAPI } from "../../api";
|
||||
import { ChatInputType, ChatOutputType } from "../../chat";
|
||||
|
|
@ -60,7 +59,7 @@ export type FlowStoreType = {
|
|||
setComponentsToUpdate: (
|
||||
update: string[] | ((oldState: string[]) => string[]),
|
||||
) => void;
|
||||
updateComponentsToUpdate: (nodes: Node[]) => void;
|
||||
updateComponentsToUpdate: (nodes: AllNodeType[]) => void;
|
||||
onFlowPage: boolean;
|
||||
setOnFlowPage: (onFlowPage: boolean) => void;
|
||||
flowPool: FlowPoolType;
|
||||
|
|
@ -90,8 +89,10 @@ export type FlowStoreType = {
|
|||
setIsBuilding: (isBuilding: boolean) => void;
|
||||
setPending: (isPending: boolean) => void;
|
||||
resetFlow: (flow: FlowType | undefined) => void;
|
||||
reactFlowInstance: ReactFlowInstance | null;
|
||||
setReactFlowInstance: (newState: ReactFlowInstance) => void;
|
||||
reactFlowInstance: ReactFlowInstance<AllNodeType, EdgeType> | null;
|
||||
setReactFlowInstance: (
|
||||
newState: ReactFlowInstance<AllNodeType, EdgeType>,
|
||||
) => void;
|
||||
flowState: FlowState | undefined;
|
||||
setFlowState: (
|
||||
state:
|
||||
|
|
@ -99,19 +100,23 @@ export type FlowStoreType = {
|
|||
| undefined
|
||||
| ((oldState: FlowState | undefined) => FlowState),
|
||||
) => void;
|
||||
nodes: Node[];
|
||||
edges: Edge[];
|
||||
onNodesChange: OnNodesChange;
|
||||
onEdgesChange: OnEdgesChange;
|
||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void;
|
||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void;
|
||||
nodes: AllNodeType[];
|
||||
edges: EdgeType[];
|
||||
onNodesChange: OnNodesChange<AllNodeType>;
|
||||
onEdgesChange: OnEdgesChange<EdgeType>;
|
||||
setNodes: (
|
||||
update: AllNodeType[] | ((oldState: AllNodeType[]) => AllNodeType[]),
|
||||
) => void;
|
||||
setEdges: (
|
||||
update: EdgeType[] | ((oldState: EdgeType[]) => EdgeType[]),
|
||||
) => void;
|
||||
setNode: (
|
||||
id: string,
|
||||
update: Node | ((oldState: Node) => Node),
|
||||
update: AllNodeType | ((oldState: AllNodeType) => AllNodeType),
|
||||
isUserChange?: boolean,
|
||||
callback?: () => void,
|
||||
) => void;
|
||||
getNode: (id: string) => Node | undefined;
|
||||
getNode: (id: string) => AllNodeType | undefined;
|
||||
deleteNode: (nodeId: string | Array<string>) => void;
|
||||
deleteEdge: (edgeId: string | Array<string>) => void;
|
||||
paste: (
|
||||
|
|
@ -145,7 +150,7 @@ export type FlowStoreType = {
|
|||
silent?: boolean;
|
||||
session?: string;
|
||||
}) => Promise<void>;
|
||||
getFlow: () => { nodes: Node[]; edges: Edge[]; viewport: Viewport };
|
||||
getFlow: () => { nodes: Node[]; edges: EdgeType[]; viewport: Viewport };
|
||||
updateVerticesBuild: (
|
||||
vertices: {
|
||||
verticesIds: string[];
|
||||
|
|
@ -183,8 +188,8 @@ export type FlowStoreType = {
|
|||
edges,
|
||||
viewport,
|
||||
}: {
|
||||
nodes?: Node[];
|
||||
edges?: Edge[];
|
||||
nodes?: AllNodeType[];
|
||||
edges?: EdgeType[];
|
||||
viewport?: Viewport;
|
||||
}) => void;
|
||||
handleDragging:
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import { FlowType, NodeType } from "@/types/flow";
|
||||
import { AllNodeType, FlowType } from "@/types/flow";
|
||||
import { GetCodesType } from "@/types/tweaks";
|
||||
import { tabsArrayType } from "../../components";
|
||||
|
||||
export type TweaksStoreType = {
|
||||
activeTweaks: boolean;
|
||||
setActiveTweaks: (activeTweaks: boolean) => void;
|
||||
nodes: NodeType[];
|
||||
nodes: AllNodeType[];
|
||||
setNodes: (
|
||||
update: NodeType[] | ((oldState: NodeType[]) => NodeType[]),
|
||||
update: AllNodeType[] | ((oldState: AllNodeType[]) => AllNodeType[]),
|
||||
skipSave?: boolean,
|
||||
) => void;
|
||||
setNode: (
|
||||
id: string,
|
||||
update: NodeType | ((oldState: NodeType) => NodeType),
|
||||
update: AllNodeType | ((oldState: AllNodeType) => AllNodeType),
|
||||
) => void;
|
||||
getCodes: GetCodesType;
|
||||
getNode: (id: string) => NodeType | undefined;
|
||||
getNode: (id: string) => AllNodeType | undefined;
|
||||
tabs: tabsArrayType[];
|
||||
initialSetup: (
|
||||
autoLogin: boolean,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { BASE_URL_API } from "@/constants/constants";
|
||||
import { performStreamingRequest } from "@/controllers/API/api";
|
||||
import { useMessagesStore } from "@/stores/messagesStore";
|
||||
import { Edge, Node } from "@xyflow/react";
|
||||
import { AxiosError } from "axios";
|
||||
import { flushSync } from "react-dom";
|
||||
import { Edge, Node } from "reactflow";
|
||||
import { BuildStatus } from "../constants/enums";
|
||||
import { getVerticesOrder, postBuildVertex } from "../controllers/API";
|
||||
import useAlertStore from "../stores/alertStore";
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { NODE_HEIGHT, NODE_WIDTH } from "@/constants/constants";
|
||||
import { NodeType } from "@/types/flow";
|
||||
import { AllNodeType, EdgeType } from "@/types/flow";
|
||||
import ELK, { ElkNode } from "elkjs/lib/elk.bundled.js";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { Edge } from "reactflow";
|
||||
|
||||
const layoutOptions = {
|
||||
"elk.algorithm": "layered",
|
||||
|
|
@ -11,7 +10,7 @@ const layoutOptions = {
|
|||
"elk.layered.spacing.edgeNodeBetweenLayers": "40",
|
||||
"elk.spacing.nodeNode": "40",
|
||||
"elk.layered.nodePlacement.strategy": "NETWORK_SIMPLEX",
|
||||
"elk.separateConnectedComponents": true,
|
||||
"elk.separateConnectedComponents": "true",
|
||||
"elk.layered.crossingMinimization.strategy": "LAYER_SWEEP",
|
||||
"elk.spacing.componentComponent": `${NODE_WIDTH}`,
|
||||
"elk.layered.considerModelOrder.strategy": "NODES_AND_EDGES",
|
||||
|
|
@ -19,7 +18,10 @@ const layoutOptions = {
|
|||
const elk = new ELK();
|
||||
|
||||
// uses elkjs to give each node a layouted position
|
||||
export const getLayoutedNodes = async (nodes: NodeType[], edges: Edge[]) => {
|
||||
export const getLayoutedNodes = async (
|
||||
nodes: AllNodeType[],
|
||||
edges: EdgeType[],
|
||||
): Promise<AllNodeType[]> => {
|
||||
const graph = {
|
||||
id: "root",
|
||||
layoutOptions,
|
||||
|
|
@ -72,7 +74,6 @@ export const getLayoutedNodes = async (nodes: NodeType[], edges: Edge[]) => {
|
|||
x: layoutedNode?.x ?? 0,
|
||||
y: layoutedNode?.y ?? 0,
|
||||
},
|
||||
type: "genericNode",
|
||||
};
|
||||
});
|
||||
return layoutedNodes;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import {
|
|||
getLeftHandleId,
|
||||
getRightHandleId,
|
||||
} from "@/CustomNodes/utils/get-handle-id";
|
||||
import { cloneDeep } from "lodash";
|
||||
import {
|
||||
Connection,
|
||||
Edge,
|
||||
|
|
@ -10,7 +9,8 @@ import {
|
|||
OnSelectionChangeParams,
|
||||
ReactFlowJsonObject,
|
||||
XYPosition,
|
||||
} from "reactflow";
|
||||
} from "@xyflow/react";
|
||||
import { cloneDeep } from "lodash";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import getFieldTitle from "../CustomNodes/utils/get-field-title";
|
||||
import {
|
||||
|
|
@ -31,9 +31,10 @@ import {
|
|||
OutputFieldType,
|
||||
} from "../types/api";
|
||||
import {
|
||||
AllNodeType,
|
||||
EdgeType,
|
||||
FlowType,
|
||||
NodeDataType,
|
||||
NodeType,
|
||||
sourceHandleType,
|
||||
targetHandleType,
|
||||
} from "../types/flow";
|
||||
|
|
@ -51,7 +52,7 @@ export function checkChatInput(nodes: Node[]) {
|
|||
return nodes.some((node) => node.data.type === "ChatInput");
|
||||
}
|
||||
|
||||
export function cleanEdges(nodes: NodeType[], edges: Edge[]) {
|
||||
export function cleanEdges(nodes: AllNodeType[], edges: EdgeType[]) {
|
||||
let newEdges = cloneDeep(edges);
|
||||
edges.forEach((edge) => {
|
||||
// check if the source and target node still exists
|
||||
|
|
@ -83,31 +84,33 @@ export function cleanEdges(nodes: NodeType[], edges: Edge[]) {
|
|||
if (sourceHandle) {
|
||||
const parsedSourceHandle = scapeJSONParse(sourceHandle);
|
||||
const name = parsedSourceHandle.name;
|
||||
const output = sourceNode.data.node!.outputs?.find(
|
||||
(output) => output.name === name,
|
||||
);
|
||||
if (output) {
|
||||
const outputTypes =
|
||||
output!.types.length === 1 ? output!.types : [output!.selected!];
|
||||
if (sourceNode.type == "genericNode") {
|
||||
const output = sourceNode.data.node!.outputs?.find(
|
||||
(output) => output.name === name,
|
||||
);
|
||||
if (output) {
|
||||
const outputTypes =
|
||||
output!.types.length === 1 ? output!.types : [output!.selected!];
|
||||
|
||||
const id: sourceHandleType = {
|
||||
id: sourceNode.data.id,
|
||||
name: name,
|
||||
output_types: outputTypes,
|
||||
dataType: sourceNode.data.type,
|
||||
};
|
||||
if (scapedJSONStringfy(id) !== sourceHandle) {
|
||||
const id: sourceHandleType = {
|
||||
id: sourceNode.data.id,
|
||||
name: name,
|
||||
output_types: outputTypes,
|
||||
dataType: sourceNode.data.type,
|
||||
};
|
||||
if (scapedJSONStringfy(id) !== sourceHandle) {
|
||||
newEdges = newEdges.filter((e) => e.id !== edge.id);
|
||||
}
|
||||
} else {
|
||||
newEdges = newEdges.filter((e) => e.id !== edge.id);
|
||||
}
|
||||
} else {
|
||||
newEdges = newEdges.filter((e) => e.id !== edge.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
return newEdges;
|
||||
}
|
||||
|
||||
export function detectBrokenEdgesEdges(nodes: NodeType[], edges: Edge[]) {
|
||||
export function detectBrokenEdgesEdges(nodes: AllNodeType[], edges: Edge[]) {
|
||||
function generateAlertObject(sourceNode, targetNode, edge) {
|
||||
const targetHandleObject: targetHandleType = scapeJSONParse(
|
||||
edge.targetHandle,
|
||||
|
|
@ -175,26 +178,28 @@ export function detectBrokenEdgesEdges(nodes: NodeType[], edges: Edge[]) {
|
|||
if (sourceHandle) {
|
||||
const parsedSourceHandle = scapeJSONParse(sourceHandle);
|
||||
const name = parsedSourceHandle.name;
|
||||
const output = sourceNode.data.node!.outputs?.find(
|
||||
(output) => output.name === name,
|
||||
);
|
||||
if (output) {
|
||||
const outputTypes =
|
||||
output!.types.length === 1 ? output!.types : [output!.selected!];
|
||||
if (sourceNode.type == "genericNode") {
|
||||
const output = sourceNode.data.node!.outputs?.find(
|
||||
(output) => output.name === name,
|
||||
);
|
||||
if (output) {
|
||||
const outputTypes =
|
||||
output!.types.length === 1 ? output!.types : [output!.selected!];
|
||||
|
||||
const id: sourceHandleType = {
|
||||
id: sourceNode.data.id,
|
||||
name: name,
|
||||
output_types: outputTypes,
|
||||
dataType: sourceNode.data.type,
|
||||
};
|
||||
if (scapedJSONStringfy(id) !== sourceHandle) {
|
||||
const id: sourceHandleType = {
|
||||
id: sourceNode.data.id,
|
||||
name: name,
|
||||
output_types: outputTypes,
|
||||
dataType: sourceNode.data.type,
|
||||
};
|
||||
if (scapedJSONStringfy(id) !== sourceHandle) {
|
||||
newEdges = newEdges.filter((e) => e.id !== edge.id);
|
||||
BrokenEdges.push(generateAlertObject(sourceNode, targetNode, edge));
|
||||
}
|
||||
} else {
|
||||
newEdges = newEdges.filter((e) => e.id !== edge.id);
|
||||
BrokenEdges.push(generateAlertObject(sourceNode, targetNode, edge));
|
||||
}
|
||||
} else {
|
||||
newEdges = newEdges.filter((e) => e.id !== edge.id);
|
||||
BrokenEdges.push(generateAlertObject(sourceNode, targetNode, edge));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -212,8 +217,8 @@ export function unselectAllNodesEdges(nodes: Node[], edges: Edge[]) {
|
|||
|
||||
export function isValidConnection(
|
||||
{ source, target, sourceHandle, targetHandle }: Connection,
|
||||
nodes: Node[],
|
||||
edges: Edge[],
|
||||
nodes: AllNodeType[],
|
||||
edges: EdgeType[],
|
||||
) {
|
||||
if (source === target) {
|
||||
return false;
|
||||
|
|
@ -249,9 +254,10 @@ export function isValidConnection(
|
|||
export function removeApiKeys(flow: FlowType): FlowType {
|
||||
let cleanFLow = cloneDeep(flow);
|
||||
cleanFLow.data!.nodes.forEach((node) => {
|
||||
for (const key in node.data.node.template) {
|
||||
if (node.data.node.template[key].password) {
|
||||
node.data.node.template[key].value = "";
|
||||
if (node.type !== "genericNode") return;
|
||||
for (const key in node.data.node!.template) {
|
||||
if (node.data.node!.template[key].password) {
|
||||
node.data.node!.template[key].value = "";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -309,14 +315,14 @@ export const processFlows = (DbData: FlowType[], skipUpdate = true) => {
|
|||
return { data: savedComponents, flows: DbData };
|
||||
};
|
||||
|
||||
export const needsLayout = (nodes: NodeType[]) => {
|
||||
export const needsLayout = (nodes: AllNodeType[]) => {
|
||||
return nodes.some((node) => !node.position);
|
||||
};
|
||||
|
||||
export async function processDataFromFlow(
|
||||
flow: FlowType,
|
||||
refreshIds = true,
|
||||
): Promise<ReactFlowJsonObject | null> {
|
||||
): Promise<ReactFlowJsonObject<AllNodeType, EdgeType> | null> {
|
||||
let data = flow?.data ? flow.data : null;
|
||||
if (data) {
|
||||
processFlowEdges(flow);
|
||||
|
|
@ -336,13 +342,13 @@ export async function processDataFromFlow(
|
|||
}
|
||||
|
||||
export function updateIds(
|
||||
{ edges, nodes }: { edges: Edge[]; nodes: Node[] },
|
||||
selection?: { edges: Edge[]; nodes: Node[] },
|
||||
{ edges, nodes }: { edges: EdgeType[]; nodes: AllNodeType[] },
|
||||
selection?: OnSelectionChangeParams,
|
||||
) {
|
||||
let idsMap = {};
|
||||
const selectionIds = selection?.nodes.map((n) => n.id);
|
||||
if (nodes) {
|
||||
nodes.forEach((node: NodeType) => {
|
||||
nodes.forEach((node: AllNodeType) => {
|
||||
// Generate a unique node ID
|
||||
let newId = getNodeId(node.data.type);
|
||||
if (selection && !selectionIds?.includes(node.id)) {
|
||||
|
|
@ -353,15 +359,17 @@ export function updateIds(
|
|||
node.data.id = newId;
|
||||
// Add the new node to the list of nodes in state
|
||||
});
|
||||
selection?.nodes.forEach((sNode: NodeType) => {
|
||||
let newId = idsMap[sNode.id];
|
||||
sNode.id = newId;
|
||||
sNode.data.id = newId;
|
||||
selection?.nodes.forEach((sNode: Node) => {
|
||||
if (sNode.type === "genericNode") {
|
||||
let newId = idsMap[sNode.id];
|
||||
sNode.id = newId;
|
||||
sNode.data.id = newId;
|
||||
}
|
||||
});
|
||||
}
|
||||
const concatedEdges = [...edges, ...(selection?.edges ?? [])];
|
||||
const concatedEdges = [...edges, ...((selection?.edges as EdgeType[]) ?? [])];
|
||||
if (concatedEdges)
|
||||
concatedEdges.forEach((edge: Edge) => {
|
||||
concatedEdges.forEach((edge: EdgeType) => {
|
||||
edge.source = idsMap[edge.source];
|
||||
edge.target = idsMap[edge.target];
|
||||
|
||||
|
|
@ -396,7 +404,7 @@ export function updateIds(
|
|||
return idsMap;
|
||||
}
|
||||
|
||||
export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
||||
export function validateNode(node: AllNodeType, edges: Edge[]): Array<string> {
|
||||
if (!node.data?.node?.template || !Object.keys(node.data.node.template)) {
|
||||
return [
|
||||
"We've noticed a potential issue with a Component in the flow. Please review it and, if necessary, submit a bug report with your exported flow file. Thank you for your help!",
|
||||
|
|
@ -412,6 +420,7 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
|||
|
||||
return Object.keys(template).reduce((errors: Array<string>, t) => {
|
||||
if (
|
||||
node.type === "genericNode" &&
|
||||
template[t].required &&
|
||||
!(template[t].tool_mode && node?.data?.node?.tool_mode) &&
|
||||
template[t].show &&
|
||||
|
|
@ -457,8 +466,8 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
|||
}
|
||||
|
||||
export function validateNodes(
|
||||
nodes: Node[],
|
||||
edges: Edge[],
|
||||
nodes: AllNodeType[],
|
||||
edges: EdgeType[],
|
||||
): // this returns an array of tuples with the node id and the errors
|
||||
Array<{ id: string; errors: Array<string> }> {
|
||||
if (nodes.length === 0) {
|
||||
|
|
@ -479,7 +488,7 @@ Array<{ id: string; errors: Array<string> }> {
|
|||
return nodeMap.filter((n) => n.errors?.length);
|
||||
}
|
||||
|
||||
export function updateEdges(edges: Edge[]) {
|
||||
export function updateEdges(edges: EdgeType[]) {
|
||||
if (edges)
|
||||
edges.forEach((edge) => {
|
||||
const targetHandleObject: targetHandleType = scapeJSONParse(
|
||||
|
|
@ -506,20 +515,24 @@ export function addVersionToDuplicates(flow: FlowType, flows: FlowType[]) {
|
|||
|
||||
export function addEscapedHandleIdsToEdges({
|
||||
edges,
|
||||
}: addEscapedHandleIdsToEdgesType): Edge[] {
|
||||
}: addEscapedHandleIdsToEdgesType): EdgeType[] {
|
||||
let newEdges = cloneDeep(edges);
|
||||
newEdges.forEach((edge) => {
|
||||
let escapedSourceHandle = edge.sourceHandle;
|
||||
let escapedTargetHandle = edge.targetHandle;
|
||||
if (!escapedSourceHandle) {
|
||||
let sourceHandle = edge.data?.sourceHandle;
|
||||
escapedSourceHandle = getRightHandleId(sourceHandle);
|
||||
edge.sourceHandle = escapedSourceHandle;
|
||||
if (sourceHandle) {
|
||||
escapedSourceHandle = getRightHandleId(sourceHandle);
|
||||
edge.sourceHandle = escapedSourceHandle;
|
||||
}
|
||||
}
|
||||
if (!escapedTargetHandle) {
|
||||
let targetHandle = edge.data?.targetHandle;
|
||||
escapedTargetHandle = getLeftHandleId(targetHandle);
|
||||
edge.targetHandle = escapedTargetHandle;
|
||||
if (targetHandle) {
|
||||
escapedTargetHandle = getLeftHandleId(targetHandle);
|
||||
edge.targetHandle = escapedTargetHandle;
|
||||
}
|
||||
}
|
||||
});
|
||||
return newEdges;
|
||||
|
|
@ -527,7 +540,7 @@ export function addEscapedHandleIdsToEdges({
|
|||
export function updateEdgesHandleIds({
|
||||
edges,
|
||||
nodes,
|
||||
}: updateEdgesHandleIdsType): Edge[] {
|
||||
}: updateEdgesHandleIdsType): EdgeType[] {
|
||||
let newEdges = cloneDeep(edges);
|
||||
newEdges.forEach((edge) => {
|
||||
const sourceNodeId = edge.source;
|
||||
|
|
@ -549,7 +562,7 @@ export function updateEdgesHandleIds({
|
|||
inputTypes: targetNode.data.node!.template[field].input_types,
|
||||
};
|
||||
}
|
||||
if (source && sourceNode) {
|
||||
if (source && sourceNode && sourceNode.type === "genericNode") {
|
||||
const output_types =
|
||||
sourceNode.data.node!.output_types ??
|
||||
sourceNode.data.node!.base_classes!;
|
||||
|
|
@ -580,61 +593,64 @@ export function updateNewOutput({ nodes, edges }: updateEdgesHandleIdsType) {
|
|||
let newTargetHandle: targetHandleType = scapeJSONParse(edge.targetHandle);
|
||||
const id = newSourceHandle.id;
|
||||
const sourceNodeIndex = newNodes.findIndex((node) => node.id === id);
|
||||
let sourceNode: NodeType | undefined = undefined;
|
||||
let sourceNode: AllNodeType | undefined = undefined;
|
||||
if (sourceNodeIndex !== -1) {
|
||||
sourceNode = newNodes[sourceNodeIndex];
|
||||
}
|
||||
|
||||
let intersection;
|
||||
//@ts-ignore
|
||||
if (newSourceHandle.baseClasses) {
|
||||
if (!newSourceHandle.output_types) {
|
||||
if (sourceNode?.data.node!.output_types) {
|
||||
newSourceHandle.output_types = sourceNode?.data.node!.output_types;
|
||||
} else {
|
||||
//@ts-ignore
|
||||
newSourceHandle.output_types = newSourceHandle.baseClasses;
|
||||
if (sourceNode?.type === "genericNode") {
|
||||
let intersection;
|
||||
if (newSourceHandle.baseClasses) {
|
||||
if (!newSourceHandle.output_types) {
|
||||
if (sourceNode?.data.node!.output_types) {
|
||||
newSourceHandle.output_types =
|
||||
sourceNode?.data.node!.output_types;
|
||||
} else {
|
||||
newSourceHandle.output_types = newSourceHandle.baseClasses;
|
||||
}
|
||||
}
|
||||
delete newSourceHandle.baseClasses;
|
||||
}
|
||||
if (
|
||||
newTargetHandle.inputTypes &&
|
||||
newTargetHandle.inputTypes.length > 0
|
||||
) {
|
||||
intersection = newSourceHandle.output_types.filter((type) =>
|
||||
newTargetHandle.inputTypes!.includes(type),
|
||||
);
|
||||
} else {
|
||||
intersection = newSourceHandle.output_types.filter(
|
||||
(type) => type === newTargetHandle.type,
|
||||
);
|
||||
}
|
||||
const selected = intersection[0];
|
||||
newSourceHandle.name = newSourceHandle.output_types.join(" | ");
|
||||
newSourceHandle.output_types = [selected];
|
||||
if (sourceNode) {
|
||||
if (!sourceNode.data.node?.outputs) {
|
||||
sourceNode.data.node!.outputs = [];
|
||||
}
|
||||
const types =
|
||||
sourceNode.data.node!.output_types ??
|
||||
sourceNode.data.node!.base_classes!;
|
||||
if (
|
||||
!sourceNode.data.node!.outputs.some(
|
||||
(output) => output.selected === selected,
|
||||
)
|
||||
) {
|
||||
sourceNode.data.node!.outputs.push({
|
||||
types,
|
||||
selected: selected,
|
||||
name: types.join(" | "),
|
||||
display_name: types.join(" | "),
|
||||
});
|
||||
}
|
||||
}
|
||||
//@ts-ignore
|
||||
delete newSourceHandle.baseClasses;
|
||||
}
|
||||
if (newTargetHandle.inputTypes && newTargetHandle.inputTypes.length > 0) {
|
||||
//conjuction subtraction
|
||||
intersection = newSourceHandle.output_types.filter((type) =>
|
||||
newTargetHandle.inputTypes!.includes(type),
|
||||
);
|
||||
} else {
|
||||
intersection = newSourceHandle.output_types.filter(
|
||||
(type) => type === newTargetHandle.type,
|
||||
);
|
||||
}
|
||||
const selected = intersection[0];
|
||||
newSourceHandle.name = newSourceHandle.output_types.join(" | ");
|
||||
newSourceHandle.output_types = [selected];
|
||||
if (sourceNode) {
|
||||
if (!sourceNode.data.node?.outputs) {
|
||||
sourceNode.data.node!.outputs = [];
|
||||
}
|
||||
const types =
|
||||
sourceNode.data.node!.output_types ??
|
||||
sourceNode.data.node!.base_classes!;
|
||||
if (
|
||||
!sourceNode.data.node!.outputs.some(
|
||||
(output) => output.selected === selected,
|
||||
)
|
||||
) {
|
||||
sourceNode.data.node!.outputs.push({
|
||||
types,
|
||||
selected: selected,
|
||||
name: types.join(" | "),
|
||||
display_name: types.join(" | "),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
edge.sourceHandle = scapedJSONStringfy(newSourceHandle);
|
||||
edge.data.sourceHandle = newSourceHandle;
|
||||
edge.sourceHandle = scapedJSONStringfy(newSourceHandle);
|
||||
if (edge.data) {
|
||||
edge.data.sourceHandle = newSourceHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return { nodes: newNodes, edges: newEdges };
|
||||
|
|
@ -684,8 +700,8 @@ export function handleOnlyIntegerInput(
|
|||
|
||||
export function getConnectedNodes(
|
||||
edge: Edge,
|
||||
nodes: Array<NodeType>,
|
||||
): Array<NodeType> {
|
||||
nodes: Array<AllNodeType>,
|
||||
): Array<AllNodeType> {
|
||||
const sourceId = edge.source;
|
||||
const targetId = edge.target;
|
||||
return nodes.filter((node) => node.id === targetId || node.id === sourceId);
|
||||
|
|
@ -796,10 +812,10 @@ export function checkEdgeWithoutEscapedHandleIds(edges: Edge[]): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
export function checkOldNodesOutput(nodes: NodeType[]): boolean {
|
||||
export function checkOldNodesOutput(nodes: AllNodeType[]): boolean {
|
||||
return nodes.some(
|
||||
(node) =>
|
||||
node.data.node?.outputs === undefined && node.type === "genericNode",
|
||||
node.type === "genericNode" && node.data.node?.outputs === undefined,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -860,8 +876,8 @@ export function getHandleId(
|
|||
|
||||
export function generateFlow(
|
||||
selection: OnSelectionChangeParams,
|
||||
nodes: Node[],
|
||||
edges: Edge[],
|
||||
nodes: AllNodeType[],
|
||||
edges: EdgeType[],
|
||||
name: string,
|
||||
): generateFlowType {
|
||||
const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } };
|
||||
|
|
@ -872,7 +888,7 @@ export function generateFlow(
|
|||
selection.nodes.some((node) => node.id === edge.target) &&
|
||||
selection.nodes.some((node) => node.id === edge.source),
|
||||
);
|
||||
newFlowData.nodes = selection.nodes;
|
||||
newFlowData.nodes = selection.nodes as AllNodeType[];
|
||||
|
||||
const newFlow: FlowType = {
|
||||
data: newFlowData,
|
||||
|
|
@ -896,8 +912,11 @@ export function generateFlow(
|
|||
};
|
||||
}
|
||||
|
||||
export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) {
|
||||
if (!groupNode.data.node!.flow) return [];
|
||||
export function reconnectEdges(
|
||||
groupNode: AllNodeType,
|
||||
excludedEdges: EdgeType[],
|
||||
) {
|
||||
if (groupNode.type !== "genericNode" || !groupNode.data.node!.flow) return [];
|
||||
let newEdges = cloneDeep(excludedEdges);
|
||||
const { nodes, edges } = groupNode.data.node!.flow!.data!;
|
||||
const lastNode = findLastNode(groupNode.data.node!.flow!.data!);
|
||||
|
|
@ -905,26 +924,32 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) {
|
|||
(e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id),
|
||||
);
|
||||
newEdges.forEach((edge) => {
|
||||
const newSourceHandle: sourceHandleType = scapeJSONParse(
|
||||
edge.sourceHandle!,
|
||||
);
|
||||
const newTargetHandle: targetHandleType = scapeJSONParse(
|
||||
edge.targetHandle!,
|
||||
);
|
||||
if (lastNode && edge.source === lastNode.id) {
|
||||
edge.source = groupNode.id;
|
||||
let newSourceHandle: sourceHandleType = scapeJSONParse(
|
||||
edge.sourceHandle!,
|
||||
);
|
||||
newSourceHandle.id = groupNode.id;
|
||||
edge.sourceHandle = scapedJSONStringfy(newSourceHandle);
|
||||
edge.data.sourceHandle = newSourceHandle;
|
||||
}
|
||||
if (nodes.some((node) => node.id === edge.target)) {
|
||||
const targetNode = nodes.find((node) => node.id === edge.target)!;
|
||||
const targetHandle: targetHandleType = scapeJSONParse(edge.targetHandle!);
|
||||
const proxy = { id: targetNode.id, field: targetHandle.fieldName };
|
||||
let newTargetHandle: targetHandleType = cloneDeep(targetHandle);
|
||||
const proxy = { id: targetNode.id, field: newTargetHandle.fieldName };
|
||||
newTargetHandle.id = groupNode.id;
|
||||
newTargetHandle.proxy = proxy;
|
||||
edge.target = groupNode.id;
|
||||
newTargetHandle.fieldName = targetHandle.fieldName + "_" + targetNode.id;
|
||||
newTargetHandle.fieldName =
|
||||
newTargetHandle.fieldName + "_" + targetNode.id;
|
||||
edge.targetHandle = scapedJSONStringfy(newTargetHandle);
|
||||
edge.data.targetHandle = newTargetHandle;
|
||||
}
|
||||
if (newSourceHandle && newTargetHandle) {
|
||||
edge.data = {
|
||||
sourceHandle: newSourceHandle,
|
||||
targetHandle: newTargetHandle,
|
||||
};
|
||||
}
|
||||
});
|
||||
return newEdges;
|
||||
|
|
@ -1058,7 +1083,7 @@ export function mergeNodeTemplates({
|
|||
nodes,
|
||||
edges,
|
||||
}: {
|
||||
nodes: NodeType[];
|
||||
nodes: AllNodeType[];
|
||||
edges: Edge[];
|
||||
}): APITemplateType {
|
||||
/* this function receives a flow and iterate throw each node
|
||||
|
|
@ -1072,10 +1097,13 @@ export function mergeNodeTemplates({
|
|||
Object.keys(nodeTemplate)
|
||||
.filter((field_name) => field_name.charAt(0) !== "_")
|
||||
.forEach((key) => {
|
||||
if (!isTargetHandleConnected(edges, key, nodeTemplate[key], node.id)) {
|
||||
if (
|
||||
node.type === "genericNode" &&
|
||||
!isTargetHandleConnected(edges, key, nodeTemplate[key], node.id)
|
||||
) {
|
||||
template[key + "_" + node.id] = nodeTemplate[key];
|
||||
template[key + "_" + node.id].proxy = { id: node.id, field: key };
|
||||
if (node.type === "groupNode") {
|
||||
if (node.data.type === "GroupNode") {
|
||||
template[key + "_" + node.id].display_name =
|
||||
node.data.node!.flow!.name + " - " + nodeTemplate[key].name;
|
||||
} else {
|
||||
|
|
@ -1152,13 +1180,13 @@ export function generateNodeTemplate(Flow: FlowType) {
|
|||
export function generateNodeFromFlow(
|
||||
flow: FlowType,
|
||||
getNodeId: (type: string) => string,
|
||||
): NodeType {
|
||||
): AllNodeType {
|
||||
const { nodes } = flow.data!;
|
||||
const outputNode = cloneDeep(findLastNode(flow.data!));
|
||||
const position = getMiddlePoint(nodes);
|
||||
let data = cloneDeep(flow);
|
||||
const id = getNodeId("groupComponent");
|
||||
const newGroupNode: NodeType = {
|
||||
const newGroupNode: AllNodeType = {
|
||||
data: {
|
||||
id,
|
||||
type: "GroupNode",
|
||||
|
|
@ -1181,8 +1209,8 @@ export function generateNodeFromFlow(
|
|||
function generateNodeOutputs(flow: FlowType) {
|
||||
const { nodes, edges } = flow.data!;
|
||||
const outputs: Array<OutputFieldType> = [];
|
||||
nodes.forEach((node: NodeType) => {
|
||||
if (node.data.node?.outputs) {
|
||||
nodes.forEach((node: AllNodeType) => {
|
||||
if (node.type === "genericNode" && node.data.node?.outputs) {
|
||||
const nodeOutputs = node.data.node.outputs;
|
||||
nodeOutputs.forEach((output) => {
|
||||
//filter outputs that are not connected
|
||||
|
|
@ -1190,7 +1218,8 @@ function generateNodeOutputs(flow: FlowType) {
|
|||
!edges.some(
|
||||
(edge) =>
|
||||
edge.source === node.id &&
|
||||
(edge.data.sourceHandle as sourceHandleType).name === output.name,
|
||||
(edge.data?.sourceHandle as sourceHandleType).name ===
|
||||
output.name,
|
||||
)
|
||||
) {
|
||||
outputs.push(
|
||||
|
|
@ -1213,44 +1242,6 @@ function generateNodeOutputs(flow: FlowType) {
|
|||
return outputs;
|
||||
}
|
||||
|
||||
export function connectedInputNodesOnHandle(
|
||||
nodeId: string,
|
||||
handleId: string,
|
||||
{ nodes, edges }: { nodes: NodeType[]; edges: Edge[] },
|
||||
) {
|
||||
const connectedNodes: Array<{ name: string; id: string; isGroup: boolean }> =
|
||||
[];
|
||||
// return the nodes connected to the input handle of the node
|
||||
const TargetEdges = edges.filter((e) => e.target === nodeId);
|
||||
TargetEdges.forEach((edge) => {
|
||||
if (edge.targetHandle === handleId) {
|
||||
const sourceNode = nodes.find((n) => n.id === edge.source);
|
||||
if (sourceNode) {
|
||||
if (sourceNode.type === "groupNode") {
|
||||
let lastNode = findLastNode(sourceNode.data.node!.flow!.data!);
|
||||
while (lastNode && lastNode.type === "groupNode") {
|
||||
lastNode = findLastNode(lastNode.data.node!.flow!.data!);
|
||||
}
|
||||
if (lastNode) {
|
||||
connectedNodes.push({
|
||||
name: sourceNode.data.node!.flow!.name,
|
||||
id: lastNode.id,
|
||||
isGroup: true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
connectedNodes.push({
|
||||
name: sourceNode.data.type,
|
||||
id: sourceNode.id,
|
||||
isGroup: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return connectedNodes;
|
||||
}
|
||||
|
||||
export function updateProxyIdsOnTemplate(
|
||||
template: APITemplateType,
|
||||
idsMap: { [key: string]: string },
|
||||
|
|
@ -1275,15 +1266,15 @@ export function updateProxyIdsOnOutputs(
|
|||
}
|
||||
|
||||
export function updateEdgesIds(
|
||||
edges: Edge[],
|
||||
edges: EdgeType[],
|
||||
idsMap: { [key: string]: string },
|
||||
) {
|
||||
edges.forEach((edge) => {
|
||||
let targetHandle: targetHandleType = edge.data.targetHandle;
|
||||
let targetHandle: targetHandleType = edge.data!.targetHandle;
|
||||
if (targetHandle.proxy && idsMap[targetHandle.proxy!.id]) {
|
||||
targetHandle.proxy!.id = idsMap[targetHandle.proxy!.id];
|
||||
}
|
||||
edge.data.targetHandle = targetHandle;
|
||||
edge.data!.targetHandle = targetHandle;
|
||||
edge.targetHandle = scapedJSONStringfy(targetHandle);
|
||||
});
|
||||
}
|
||||
|
|
@ -1312,17 +1303,21 @@ export function expandGroupNode(
|
|||
id: string,
|
||||
flow: FlowType,
|
||||
template: APITemplateType,
|
||||
nodes: Node[],
|
||||
edges: Edge[],
|
||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void,
|
||||
nodes: AllNodeType[],
|
||||
edges: EdgeType[],
|
||||
setNodes: (
|
||||
update: AllNodeType[] | ((oldState: AllNodeType[]) => AllNodeType[]),
|
||||
) => void,
|
||||
setEdges: (
|
||||
update: EdgeType[] | ((oldState: EdgeType[]) => EdgeType[]),
|
||||
) => void,
|
||||
outputs?: OutputFieldType[],
|
||||
) {
|
||||
const idsMap = updateIds(flow!.data!);
|
||||
updateProxyIdsOnTemplate(template, idsMap);
|
||||
let flowEdges = edges;
|
||||
updateEdgesIds(flowEdges, idsMap);
|
||||
const gNodes: NodeType[] = cloneDeep(flow?.data?.nodes!);
|
||||
const gNodes: AllNodeType[] = cloneDeep(flow?.data?.nodes!);
|
||||
const gEdges = cloneDeep(flow!.data!.edges);
|
||||
// //redirect edges to correct proxy node
|
||||
// let updatedEdges: Edge[] = [];
|
||||
|
|
@ -1406,13 +1401,16 @@ export function expandGroupNode(
|
|||
outputs?.forEach((output) => {
|
||||
let nodeIndex = gNodes.findIndex((n) => n.id === output.proxy!.id);
|
||||
if (nodeIndex !== -1) {
|
||||
if (gNodes[nodeIndex].data.node?.outputs) {
|
||||
const nodeOutputIndex = gNodes[nodeIndex].data.node!.outputs!.findIndex(
|
||||
(o) => o.name === output.proxy?.name,
|
||||
);
|
||||
if (nodeOutputIndex !== -1 && output.selected) {
|
||||
gNodes[nodeIndex].data.node!.outputs![nodeOutputIndex].selected =
|
||||
output.selected;
|
||||
const node = gNodes[nodeIndex];
|
||||
if (node.type === "genericNode") {
|
||||
if (node.data.node?.outputs) {
|
||||
const nodeOutputIndex = node.data.node!.outputs!.findIndex(
|
||||
(o) => o.name === output.proxy?.name,
|
||||
);
|
||||
if (nodeOutputIndex !== -1 && output.selected) {
|
||||
node.data.node!.outputs![nodeOutputIndex].selected =
|
||||
output.selected;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1432,7 +1430,7 @@ export function getGroupStatus(
|
|||
) {
|
||||
let status = { valid: true, params: SUCCESS_BUILD };
|
||||
const { nodes } = flow.data!;
|
||||
const ids = nodes.map((n: NodeType) => n.data.id);
|
||||
const ids = nodes.map((n: AllNodeType) => n.data.id);
|
||||
ids.forEach((id) => {
|
||||
if (!ssData[id]) {
|
||||
status = ssData[id];
|
||||
|
|
@ -1487,28 +1485,32 @@ export function updateComponentNameAndType(
|
|||
) {}
|
||||
|
||||
export function removeFileNameFromComponents(flow: FlowType) {
|
||||
flow.data!.nodes.forEach((node: NodeType) => {
|
||||
Object.keys(node.data.node!.template).forEach((field) => {
|
||||
if (node.data.node?.template[field].type === "file") {
|
||||
node.data.node!.template[field].value = "";
|
||||
flow.data!.nodes.forEach((node: AllNodeType) => {
|
||||
if (node.type === "genericNode") {
|
||||
Object.keys(node.data.node!.template).forEach((field) => {
|
||||
if (node.data.node?.template[field].type === "file") {
|
||||
node.data.node!.template[field].value = "";
|
||||
}
|
||||
});
|
||||
if (node.data.node?.flow) {
|
||||
removeFileNameFromComponents(node.data.node.flow);
|
||||
}
|
||||
});
|
||||
if (node.data.node?.flow) {
|
||||
removeFileNameFromComponents(node.data.node.flow);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function removeGlobalVariableFromComponents(flow: FlowType) {
|
||||
flow.data!.nodes.forEach((node: NodeType) => {
|
||||
Object.keys(node.data.node!.template).forEach((field) => {
|
||||
if (node.data?.node?.template[field]?.load_from_db) {
|
||||
node.data.node!.template[field].value = "";
|
||||
node.data.node!.template[field].load_from_db = false;
|
||||
flow.data!.nodes.forEach((node: AllNodeType) => {
|
||||
if (node.type === "genericNode") {
|
||||
Object.keys(node.data.node!.template).forEach((field) => {
|
||||
if (node.data?.node?.template[field]?.load_from_db) {
|
||||
node.data.node!.template[field].value = "";
|
||||
node.data.node!.template[field].load_from_db = false;
|
||||
}
|
||||
});
|
||||
if (node.data.node?.flow) {
|
||||
removeGlobalVariableFromComponents(node.data.node.flow);
|
||||
}
|
||||
});
|
||||
if (node.data.node?.flow) {
|
||||
removeGlobalVariableFromComponents(node.data.node.flow);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1592,7 +1594,7 @@ export function getRandomDescription(): string {
|
|||
}
|
||||
|
||||
export const createNewFlow = (
|
||||
flowData: ReactFlowJsonObject,
|
||||
flowData: ReactFlowJsonObject<AllNodeType, EdgeType>,
|
||||
folderId: string,
|
||||
flow?: FlowType,
|
||||
) => {
|
||||
|
|
@ -1626,8 +1628,8 @@ export function isOutputType(type: string): boolean {
|
|||
}
|
||||
|
||||
export function updateGroupRecursion(
|
||||
groupNode: NodeType,
|
||||
edges: Edge[],
|
||||
groupNode: AllNodeType,
|
||||
edges: EdgeType[],
|
||||
unavailableFields:
|
||||
| {
|
||||
[name: string]: string;
|
||||
|
|
@ -1635,28 +1637,32 @@ export function updateGroupRecursion(
|
|||
| undefined,
|
||||
globalVariablesEntries: string[] | undefined,
|
||||
) {
|
||||
updateGlobalVariables(
|
||||
groupNode.data.node,
|
||||
unavailableFields,
|
||||
globalVariablesEntries,
|
||||
);
|
||||
if (groupNode.data.node?.flow) {
|
||||
groupNode.data.node.flow.data!.nodes.forEach((node) => {
|
||||
if (node.data.node?.flow) {
|
||||
updateGroupRecursion(
|
||||
node,
|
||||
node.data.node.flow.data!.edges,
|
||||
unavailableFields,
|
||||
globalVariablesEntries,
|
||||
);
|
||||
}
|
||||
});
|
||||
let newFlow = groupNode.data.node!.flow;
|
||||
const idsMap = updateIds(newFlow.data!);
|
||||
updateProxyIdsOnTemplate(groupNode.data.node!.template, idsMap);
|
||||
updateProxyIdsOnOutputs(groupNode.data.node.outputs, idsMap);
|
||||
let flowEdges = edges;
|
||||
updateEdgesIds(flowEdges, idsMap);
|
||||
if (groupNode.type === "genericNode") {
|
||||
updateGlobalVariables(
|
||||
groupNode.data.node,
|
||||
unavailableFields,
|
||||
globalVariablesEntries,
|
||||
);
|
||||
if (groupNode.data.node?.flow) {
|
||||
groupNode.data.node.flow.data!.nodes.forEach((node) => {
|
||||
if (node.type === "genericNode") {
|
||||
if (node.data.node?.flow) {
|
||||
updateGroupRecursion(
|
||||
node,
|
||||
node.data.node.flow.data!.edges,
|
||||
unavailableFields,
|
||||
globalVariablesEntries,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
let newFlow = groupNode.data.node!.flow;
|
||||
const idsMap = updateIds(newFlow.data!);
|
||||
updateProxyIdsOnTemplate(groupNode.data.node!.template, idsMap);
|
||||
updateProxyIdsOnOutputs(groupNode.data.node.outputs, idsMap);
|
||||
let flowEdges = edges;
|
||||
updateEdgesIds(flowEdges, idsMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
export function updateGlobalVariables(
|
||||
|
|
@ -1699,10 +1705,10 @@ export function getGroupOutputNodeId(
|
|||
p_name: string,
|
||||
p_node_id: string,
|
||||
) {
|
||||
let node: NodeType | undefined = flow.data?.nodes.find(
|
||||
let node: AllNodeType | undefined = flow.data?.nodes.find(
|
||||
(n) => n.id === p_node_id,
|
||||
);
|
||||
if (!node) return;
|
||||
if (!node || node.type !== "genericNode") return;
|
||||
if (node.data.node?.flow) {
|
||||
let output = node.data.node.outputs?.find((o) => o.name === p_name);
|
||||
if (output && output.proxy) {
|
||||
|
|
@ -1727,7 +1733,7 @@ export function checkOldComponents({ nodes }: { nodes: any[] }) {
|
|||
}
|
||||
|
||||
export function someFlowTemplateFields(
|
||||
{ nodes }: { nodes: NodeType[] },
|
||||
{ nodes }: { nodes: AllNodeType[] },
|
||||
validateFn: (field: InputFieldType) => boolean,
|
||||
): boolean {
|
||||
return nodes.some((node) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Node } from "@xyflow/react";
|
||||
import { cloneDeep, uniqueId } from "lodash";
|
||||
import { Node } from "reactflow";
|
||||
import { FlowType, NodeDataType } from "../types/flow";
|
||||
import { isInputNode, isOutputNode } from "./reactflowUtils";
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
nodeGroupedObjType,
|
||||
tweakType,
|
||||
} from "../types/components";
|
||||
import { NodeDataType, NodeType } from "../types/flow";
|
||||
import { AllNodeType, NodeDataType } from "../types/flow";
|
||||
import { FlowState } from "../types/tabs";
|
||||
import { isErrorLog } from "../types/utils/typeCheckingUtils";
|
||||
import { parseString } from "./stringManipulation";
|
||||
|
|
@ -243,7 +243,7 @@ export function groupByFamily(
|
|||
data: APIDataType,
|
||||
baseClasses: string,
|
||||
left: boolean,
|
||||
flow?: NodeType[],
|
||||
flow?: AllNodeType[],
|
||||
): groupedObjType[] {
|
||||
const baseClassesSet = new Set(baseClasses.split("\n"));
|
||||
let arrOfPossibleInputs: Array<{
|
||||
|
|
@ -278,7 +278,12 @@ export function groupByFamily(
|
|||
// se existir o flow
|
||||
for (const node of flow) {
|
||||
// para cada node do flow
|
||||
if (node!.data!.node!.flow || !node!.data!.node!.template) break; // não faz nada se o node for um group
|
||||
if (
|
||||
node!.type !== "genericNode" ||
|
||||
!node!.data!.node!.flow ||
|
||||
!node!.data!.node!.template
|
||||
)
|
||||
break; // não faz nada se o node for um group
|
||||
const nodeData = node.data;
|
||||
|
||||
const foundNode = checkedNodes.get(nodeData.type); // verifica se o tipo do node já foi checado
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||
import { zoomOut } from "../../utils/zoom-out";
|
||||
|
||||
test(
|
||||
"user must be able to freeze a component",
|
||||
|
|
@ -18,23 +19,14 @@ test(
|
|||
timeout: 1000,
|
||||
});
|
||||
|
||||
await zoomOut(page, 3);
|
||||
|
||||
await page
|
||||
.getByTestId("inputsText Input")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-800, 300);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 100, y: 100 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
//second component
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
await page.getByTestId("sidebar-search-input").fill("url");
|
||||
await page.waitForSelector('[data-testid="dataURL"]', {
|
||||
|
|
@ -43,19 +35,10 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("dataURL")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-800, 300);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 300, y: 300 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
//third component
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
|
|
@ -66,19 +49,10 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("processingSplit Text")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-800, 300);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 350, y: 100 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
//fourth component
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
|
|
@ -89,18 +63,11 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("processingParse Data")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-800, 300);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 50, y: 300 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
await page.getByTestId("zoom_out").click();
|
||||
|
||||
//fifth component
|
||||
|
||||
|
|
@ -112,18 +79,11 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("outputsChat Output")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-800, 300);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 600, y: 200 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
await page.getByTestId("fit_view").click();
|
||||
|
||||
let outdatedComponents = await page
|
||||
.getByTestId("icon-AlertTriangle")
|
||||
|
|
@ -144,6 +104,7 @@ test(
|
|||
}
|
||||
|
||||
await page.getByTestId("fit_view").click();
|
||||
await zoomOut(page, 2);
|
||||
|
||||
//connection 1
|
||||
const urlOutput = await page
|
||||
|
|
@ -169,8 +130,6 @@ test(
|
|||
await splitTextInput.hover();
|
||||
await page.mouse.up();
|
||||
|
||||
await page.getByTestId("fit_view").click();
|
||||
|
||||
//connection 3
|
||||
const splitTextOutput = await page
|
||||
.getByTestId("handle-splittext-shownode-chunks-right")
|
||||
|
|
@ -195,8 +154,6 @@ test(
|
|||
await chatOutputInput.hover();
|
||||
await page.mouse.up();
|
||||
|
||||
await page.getByTestId("fit_view").click();
|
||||
|
||||
await page
|
||||
.getByTestId("textarea_str_input_value")
|
||||
.first()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { test } from "@playwright/test";
|
||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||
|
||||
import { removeOldApiKeys } from "../../utils/remove-old-api-keys";
|
||||
import { updateOldComponents } from "../../utils/update-old-components";
|
||||
import { zoomOut } from "../../utils/zoom-out";
|
||||
// TODO: fix this test
|
||||
test(
|
||||
"user must be able to stop a building",
|
||||
|
|
@ -16,18 +18,11 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("inputsText Input")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-800, 300);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 0, y: 0 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
await zoomOut(page, 3);
|
||||
|
||||
//second component
|
||||
|
||||
|
|
@ -36,19 +31,10 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("dataURL")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-800, 300);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 100, y: 200 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
//third component
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
|
|
@ -56,19 +42,10 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("processingSplit Text")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-800, 300);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 300, y: 300 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
//fourth component
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
|
|
@ -76,19 +53,10 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("processingParse Data")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-800, 300);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 100, y: 400 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
//fifth component
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
|
|
@ -96,37 +64,17 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("outputsChat Output")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-800, 300);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 600, y: 300 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
let outdatedComponents = await page
|
||||
.getByTestId("icon-AlertTriangle")
|
||||
.count();
|
||||
|
||||
while (outdatedComponents > 0) {
|
||||
await page.getByTestId("icon-AlertTriangle").first().click();
|
||||
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
|
||||
}
|
||||
|
||||
let filledApiKey = await page.getByTestId("remove-icon-badge").count();
|
||||
while (filledApiKey > 0) {
|
||||
await page.getByTestId("remove-icon-badge").first().click();
|
||||
await page.waitForTimeout(1000);
|
||||
filledApiKey = await page.getByTestId("remove-icon-badge").count();
|
||||
}
|
||||
await updateOldComponents(page);
|
||||
await removeOldApiKeys(page);
|
||||
|
||||
await page.getByTestId("fit_view").click();
|
||||
|
||||
await zoomOut(page, 2);
|
||||
|
||||
//connection 1
|
||||
const urlOutput = await page
|
||||
.getByTestId("handle-url-shownode-data-right")
|
||||
|
|
@ -151,8 +99,6 @@ test(
|
|||
await splitTextInput.hover();
|
||||
await page.mouse.up();
|
||||
|
||||
await page.getByTestId("fit_view").click();
|
||||
|
||||
//connection 3
|
||||
const splitTextOutput = await page
|
||||
.getByTestId("handle-splittext-shownode-chunks-right")
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ test(
|
|||
await page.getByTestId("button-store").click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await page.getByTestId("api-key-button-store").click();
|
||||
await page.getByTestId("api-key-button-store").click({
|
||||
timeout: 200000,
|
||||
});
|
||||
|
||||
await page
|
||||
.getByPlaceholder("Insert your API Key")
|
||||
|
|
@ -83,7 +85,9 @@ test("should share component with share button", async ({ page }) => {
|
|||
await page.getByTestId("button-store").click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await page.getByTestId("api-key-button-store").click();
|
||||
await page.getByTestId("api-key-button-store").click({
|
||||
timeout: 200000,
|
||||
});
|
||||
|
||||
await page
|
||||
.getByPlaceholder("Insert your API Key")
|
||||
|
|
|
|||
|
|
@ -2,12 +2,7 @@ import { Page, test } from "@playwright/test";
|
|||
import * as dotenv from "dotenv";
|
||||
import path from "path";
|
||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||
|
||||
async function zoomOut(page: Page, times: number = 4) {
|
||||
for (let i = 0; i < times; i++) {
|
||||
await page.getByTestId("zoom_out").click();
|
||||
}
|
||||
}
|
||||
import { zoomOut } from "../../utils/zoom-out";
|
||||
|
||||
test(
|
||||
"should create a flow with decision",
|
||||
|
|
@ -57,6 +52,11 @@ test(
|
|||
targetPosition: { x: 100, y: 100 },
|
||||
});
|
||||
|
||||
await page.waitForSelector('[data-testid="input-list-plus-btn_texts-0"]', {
|
||||
timeout: 3000,
|
||||
state: "attached",
|
||||
});
|
||||
|
||||
await page.getByTestId("input-list-plus-btn_texts-0").first().click();
|
||||
await page.getByTestId("input-list-plus-btn_texts-0").first().click();
|
||||
await page.getByTestId("input-list-plus-btn_texts-0").first().click();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||
import { updateOldComponents } from "../../utils/update-old-components";
|
||||
import { zoomOut } from "../../utils/zoom-out";
|
||||
|
||||
test(
|
||||
"user must be able to check similarity between embedding texts",
|
||||
|
|
@ -23,18 +25,11 @@ test(
|
|||
|
||||
await page
|
||||
.getByText("OpenAI Embeddings", { exact: true })
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-50, 50);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 0, y: 0 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
await zoomOut(page, 5);
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
await page.getByTestId("sidebar-search-input").fill("text embedder");
|
||||
|
|
@ -44,36 +39,18 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("embeddingsText Embedder")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-50, 50);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 100, y: 400 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
//fourth component
|
||||
|
||||
await page
|
||||
.getByTestId("embeddingsText Embedder")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-50, 50);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 300, y: 400 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
//fifth component
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
|
|
@ -84,19 +61,10 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("embeddingsEmbedding Similarity")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-50, 50);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 350, y: 100 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
//sisxth component
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
|
|
@ -107,19 +75,10 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("processingParse Data")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-50, 50);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 50, y: 100 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
//seventh component
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
|
|
@ -130,19 +89,10 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("outputsText Output")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-50, 50);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 500, y: 100 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
await page.getByTestId("sidebar-search-input").fill("filter data");
|
||||
await page.waitForSelector("text=Filter Data", {
|
||||
|
|
@ -151,33 +101,11 @@ test(
|
|||
|
||||
await page
|
||||
.getByTestId("processingFilter Data")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page
|
||||
.locator('//*[@id="react-flow-id"]')
|
||||
.hover()
|
||||
.then(async () => {
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(-50, 50);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 600, y: 200 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
let outdatedComponents = await page
|
||||
.getByTestId("icon-AlertTriangle")
|
||||
.count();
|
||||
|
||||
while (outdatedComponents > 0) {
|
||||
await page.getByTestId("icon-AlertTriangle").first().click();
|
||||
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
|
||||
}
|
||||
|
||||
let filledApiKey = await page.getByTestId("remove-icon-badge").count();
|
||||
while (filledApiKey > 0) {
|
||||
await page.getByTestId("remove-icon-badge").first().click();
|
||||
filledApiKey = await page.getByTestId("remove-icon-badge").count();
|
||||
}
|
||||
await updateOldComponents(page);
|
||||
|
||||
await page.getByTestId("fit_view").click();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||
import { zoomOut } from "../../utils/zoom-out";
|
||||
|
||||
test(
|
||||
"should be able to see output preview from grouped components and connect components with a single click",
|
||||
|
|
@ -23,10 +24,7 @@ test(
|
|||
.getByTestId("inputsText Input")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {});
|
||||
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await zoomOut(page, 4);
|
||||
|
||||
await page
|
||||
.getByTestId("inputsText Input")
|
||||
|
|
@ -156,18 +154,21 @@ test(
|
|||
.nth(1);
|
||||
await elementCombineTextInput1.click();
|
||||
|
||||
await page.getByTitle("fit view").click();
|
||||
|
||||
await zoomOut(page, 2);
|
||||
|
||||
await page
|
||||
.getByTestId("title-Combine Text")
|
||||
.first()
|
||||
.click({ modifiers: ["Control"] });
|
||||
await page
|
||||
.getByTestId("title-delimiter")
|
||||
.last()
|
||||
.click({ modifiers: ["Control"] });
|
||||
|
||||
await page.getByRole("button", { name: "Group" }).click();
|
||||
await page.waitForSelector('[data-testid="group-node"]', {
|
||||
timeout: 3000,
|
||||
state: "visible",
|
||||
});
|
||||
|
||||
await page.getByTitle("fit view").click();
|
||||
await page.getByTestId("group-node").click();
|
||||
|
||||
//connection 2
|
||||
const elementTextOutput0 = page
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { expect, test } from "@playwright/test";
|
|||
import * as dotenv from "dotenv";
|
||||
import path from "path";
|
||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||
|
||||
import { initialGPTsetup } from "../../utils/initialGPTsetup";
|
||||
test(
|
||||
"memory should work as expect",
|
||||
{ tag: ["@release"] },
|
||||
|
|
@ -67,37 +67,13 @@ test(
|
|||
await page
|
||||
.getByTestId("helpersMessage History")
|
||||
.first()
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 300, y: 500 },
|
||||
});
|
||||
|
||||
await page.mouse.up();
|
||||
await page.mouse.down();
|
||||
|
||||
await page.getByTestId("fit_view").click();
|
||||
|
||||
let outdatedComponents = await page
|
||||
.getByTestId("icon-AlertTriangle")
|
||||
.count();
|
||||
|
||||
while (outdatedComponents > 0) {
|
||||
await page.getByTestId("icon-AlertTriangle").first().click();
|
||||
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
|
||||
}
|
||||
|
||||
let filledApiKey = await page.getByTestId("remove-icon-badge").count();
|
||||
while (filledApiKey > 0) {
|
||||
await page.getByTestId("remove-icon-badge").first().click();
|
||||
filledApiKey = await page.getByTestId("remove-icon-badge").count();
|
||||
}
|
||||
|
||||
const apiKeyInput = page.getByTestId("popover-anchor-input-api_key");
|
||||
const isApiKeyInputVisible = await apiKeyInput.isVisible();
|
||||
|
||||
if (isApiKeyInputVisible) {
|
||||
await apiKeyInput.fill(process.env.OPENAI_API_KEY ?? "");
|
||||
}
|
||||
|
||||
await page.getByTestId("dropdown_str_model_name").click();
|
||||
await page.getByTestId("gpt-4o-1-option").click();
|
||||
await initialGPTsetup(page, {
|
||||
skipAdjustScreenView: true,
|
||||
});
|
||||
|
||||
const prompt = `
|
||||
{context}
|
||||
|
|
|
|||
|
|
@ -44,9 +44,10 @@ test(
|
|||
await page
|
||||
.getByTestId("outputsChat Output")
|
||||
.first()
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
await page.mouse.up();
|
||||
await page.mouse.down();
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 0, y: 0 },
|
||||
});
|
||||
|
||||
await adjustScreenView(page);
|
||||
|
||||
await page.getByTestId("sidebar-search-input").click();
|
||||
|
|
@ -54,11 +55,9 @@ test(
|
|||
await page
|
||||
.getByTestId("processingParse Data")
|
||||
.first()
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.mouse.up();
|
||||
await page.mouse.down();
|
||||
await adjustScreenView(page);
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
|
||||
targetPosition: { x: 300, y: 400 },
|
||||
});
|
||||
|
||||
let visibleElementHandle;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||
import { zoomOut } from "../../utils/zoom-out";
|
||||
|
||||
test("IntComponent", { tag: ["@release", "@workspace"] }, async ({ page }) => {
|
||||
await awaitBootstrapTest(page);
|
||||
|
|
@ -19,16 +20,11 @@ test("IntComponent", { tag: ["@release", "@workspace"] }, async ({ page }) => {
|
|||
.getByTestId("modelsOpenAI")
|
||||
.first()
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
await page.mouse.up();
|
||||
await page.mouse.down();
|
||||
await page.waitForSelector('[data-testid="fit_view"]', {
|
||||
timeout: 100000,
|
||||
});
|
||||
|
||||
await page.getByTestId("fit_view").click();
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await zoomOut(page, 2);
|
||||
|
||||
await page.getByTestId("div-generic-node").click();
|
||||
|
||||
await page.getByTestId("more-options-modal").click();
|
||||
await page.getByTestId("advanced-button-modal").click();
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ test(
|
|||
await page
|
||||
.getByTestId("modelsAmazon Bedrock")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
await page.mouse.up();
|
||||
await page.mouse.down();
|
||||
|
||||
await adjustScreenView(page);
|
||||
|
||||
await page.getByTestId("div-generic-node").click();
|
||||
|
||||
await page.getByTestId("more-options-modal").click();
|
||||
await page.getByTestId("advanced-button-modal").click();
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ test(
|
|||
.getByTestId("dataAPI Request")
|
||||
.first()
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
await page.click('//*[@id="react-flow-id"]');
|
||||
|
||||
await adjustScreenView(page);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ test(
|
|||
await page.waitForTimeout(1000);
|
||||
await page.getByTestId("button-store").click();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByTestId("api-key-button-store").click();
|
||||
await page.getByTestId("api-key-button-store").click({
|
||||
timeout: 200000,
|
||||
});
|
||||
await page
|
||||
.getByPlaceholder("Insert your API Key")
|
||||
.fill(process.env.STORE_API_KEY ?? "");
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ test(
|
|||
await page.getByTestId("button-store").click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await page.getByTestId("api-key-button-store").click();
|
||||
await page.getByTestId("api-key-button-store").click({
|
||||
timeout: 200000,
|
||||
});
|
||||
|
||||
await page
|
||||
.getByPlaceholder("Insert your API Key")
|
||||
|
|
|
|||
|
|
@ -60,10 +60,13 @@ The future of AI is both exciting and uncertain. As the technology continues to
|
|||
await page.locator(".generic-node-desc-text").last().dblclick();
|
||||
await page.getByTestId("textarea").fill(noteText);
|
||||
|
||||
expect(await page.getByText("2500/2500")).toBeVisible();
|
||||
expect(page.getByText("2500/2500")).toHaveCount(1);
|
||||
|
||||
await targetElement.click();
|
||||
const textMarkdown = await page.locator(".markdown").innerText();
|
||||
await page.keyboard.press("Escape");
|
||||
const textMarkdown = await page
|
||||
.getByTestId("generic-node-desc")
|
||||
.innerText();
|
||||
|
||||
const textLength = textMarkdown.length;
|
||||
const noteTextLength = noteText.length;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ test.skip(
|
|||
await page.waitForTimeout(1000);
|
||||
await page.getByTestId("button-store").click();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByTestId("api-key-button-store").click();
|
||||
await page.getByTestId("api-key-button-store").click({
|
||||
timeout: 200000,
|
||||
});
|
||||
await page
|
||||
.getByPlaceholder("Insert your API Key")
|
||||
.fill(process.env.STORE_API_KEY ?? "");
|
||||
|
|
@ -100,7 +102,9 @@ test.skip(
|
|||
await page.getByTestId("button-store").click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await page.getByTestId("api-key-button-store").click();
|
||||
await page.getByTestId("api-key-button-store").click({
|
||||
timeout: 200000,
|
||||
});
|
||||
|
||||
await page
|
||||
.getByPlaceholder("Insert your API Key")
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ test(
|
|||
|
||||
await page.getByTestId("button-store").click();
|
||||
|
||||
await page.getByTestId("api-key-button-store").click();
|
||||
await page.getByTestId("api-key-button-store").click({
|
||||
timeout: 200000,
|
||||
});
|
||||
|
||||
await page
|
||||
.getByPlaceholder("Insert your API Key")
|
||||
|
|
@ -58,10 +60,10 @@ test("should filter by type", { tag: ["@release"] }, async ({ page }) => {
|
|||
}
|
||||
await page.goto("/");
|
||||
await page.getByTestId("button-store").click();
|
||||
await page.waitForSelector('[data-testid="api-key-button-store"]', {
|
||||
timeout: 100000,
|
||||
await page.getByTestId("api-key-button-store").click({
|
||||
timeout: 200000,
|
||||
});
|
||||
await page.getByTestId("api-key-button-store").click();
|
||||
|
||||
await page
|
||||
.getByPlaceholder("Insert your API Key")
|
||||
.fill(process.env.STORE_API_KEY ?? "");
|
||||
|
|
|
|||
|
|
@ -71,13 +71,14 @@ test(
|
|||
await page.getByText("Close").last().click();
|
||||
|
||||
await page.getByText("Prompt", { exact: true }).click();
|
||||
|
||||
await page.getByTestId("more-options-modal").click();
|
||||
|
||||
await page.getByText("Freeze", { exact: true }).last().click();
|
||||
|
||||
await page.locator('//*[@id="react-flow-id"]').click();
|
||||
await page.waitForSelector(".border-ring-frozen", { timeout: 3000 });
|
||||
|
||||
expect(page.getByTestId("icon-Snowflake").first()).toBeVisible();
|
||||
expect(page.locator(".border-ring-frozen")).toHaveCount(1);
|
||||
|
||||
await page.locator('//*[@id="react-flow-id"]').click();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||
|
||||
import { zoomOut } from "../../utils/zoom-out";
|
||||
// TODO: This test might not be needed anymore
|
||||
test(
|
||||
"should be able to select all with ctrl + A on advanced modal",
|
||||
|
|
@ -35,8 +35,7 @@ test(
|
|||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
|
||||
await page.getByTestId("fit_view").click();
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await page.getByTestId("zoom_out").click();
|
||||
await zoomOut(page, 3);
|
||||
|
||||
await page.waitForSelector('[data-testid="div-generic-node"]', {
|
||||
timeout: 5000,
|
||||
|
|
|
|||
7
src/frontend/tests/utils/zoom-out.ts
Normal file
7
src/frontend/tests/utils/zoom-out.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { Page } from "@playwright/test";
|
||||
|
||||
export async function zoomOut(page: Page, times: number = 4) {
|
||||
for (let i = 0; i < times; i++) {
|
||||
await page.getByTestId("zoom_out").click();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue