refactor: Optimize GenericNode and other nearby components to improve performance especially on larger flows (#8053)
* Improve render preformance for nodes * update component optimization * [autofix.ci] apply automated fixes * shard increase * nodeoutput check * restore --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Carlos Coelho <80289056+carlosrcoelho@users.noreply.github.com>
This commit is contained in:
parent
fe9aa9ecb3
commit
4b580d1569
8 changed files with 245 additions and 243 deletions
|
|
@ -9,6 +9,7 @@ import {
|
|||
import useAuthStore from "@/stores/authStore";
|
||||
import { cn } from "@/utils/utils";
|
||||
import { useEffect, useMemo, useRef } from "react";
|
||||
import { useShallow } from "zustand/react/shallow";
|
||||
import { default as IconComponent } from "../../../../components/common/genericIconComponent";
|
||||
import ShadTooltip from "../../../../components/common/shadTooltipComponent";
|
||||
import {
|
||||
|
|
@ -20,7 +21,6 @@ import {
|
|||
import useFlowStore from "../../../../stores/flowStore";
|
||||
import { useTypesStore } from "../../../../stores/typesStore";
|
||||
import { NodeInputFieldComponentType } from "../../../../types/components";
|
||||
import { scapedJSONStringfy } from "../../../../utils/reactflowUtils";
|
||||
import useFetchDataOnMount from "../../../hooks/use-fetch-data-on-mount";
|
||||
import useHandleOnNewValue from "../../../hooks/use-handle-new-value";
|
||||
import NodeInputInfo from "../NodeInputInfo";
|
||||
|
|
@ -44,10 +44,13 @@ export default function NodeInputField({
|
|||
isToolMode = false,
|
||||
}: NodeInputFieldComponentType): JSX.Element {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const nodes = useFlowStore((state) => state.nodes);
|
||||
const edges = useFlowStore((state) => state.edges);
|
||||
const isAuth = useAuthStore((state) => state.isAuthenticated);
|
||||
const currentFlow = useFlowStore((state) => state.currentFlow);
|
||||
const { currentFlowId, currentFlowName } = useFlowStore(
|
||||
useShallow((state) => ({
|
||||
currentFlowId: state.currentFlow?.id,
|
||||
currentFlowName: state.currentFlow?.name,
|
||||
})),
|
||||
);
|
||||
const myData = useTypesStore((state) => state.data);
|
||||
const postTemplateValue = usePostTemplateValue({
|
||||
node: data.node!,
|
||||
|
|
@ -56,11 +59,6 @@ export default function NodeInputField({
|
|||
});
|
||||
const setFilterEdge = useFlowStore((state) => state.setFilterEdge);
|
||||
const { handleNodeClass } = useHandleNodeClass(data.id);
|
||||
let disabled =
|
||||
edges.some(
|
||||
(edge) =>
|
||||
edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id),
|
||||
) || isToolMode;
|
||||
|
||||
const { handleOnNewValue } = useHandleOnNewValue({
|
||||
node: data.node!,
|
||||
|
|
@ -74,9 +72,9 @@ export default function NodeInputField({
|
|||
|
||||
const nodeInformationMetadata: NodeInfoType = useMemo(() => {
|
||||
return {
|
||||
flowId: currentFlow?.id ?? "",
|
||||
flowId: currentFlowId ?? "",
|
||||
nodeType: data?.type?.toLowerCase() ?? "",
|
||||
flowName: currentFlow?.name ?? "",
|
||||
flowName: currentFlowName ?? "",
|
||||
isAuth,
|
||||
variableName: name,
|
||||
};
|
||||
|
|
@ -107,12 +105,10 @@ export default function NodeInputField({
|
|||
const Handle = (
|
||||
<HandleRenderComponent
|
||||
left={true}
|
||||
nodes={nodes}
|
||||
tooltipTitle={tooltipTitle}
|
||||
proxy={proxy}
|
||||
id={id}
|
||||
title={title}
|
||||
edges={edges}
|
||||
myData={myData}
|
||||
colors={colors}
|
||||
setFilterEdge={setFilterEdge}
|
||||
|
|
@ -207,12 +203,12 @@ export default function NodeInputField({
|
|||
handleOnNewValue={handleOnNewValue}
|
||||
name={name}
|
||||
nodeId={data.id}
|
||||
inputId={id}
|
||||
templateData={data.node?.template[name]!}
|
||||
templateValue={data.node?.template[name].value ?? ""}
|
||||
editNode={false}
|
||||
handleNodeClass={handleNodeClass}
|
||||
nodeClass={data.node!}
|
||||
disabled={disabled}
|
||||
placeholder={
|
||||
isToolMode
|
||||
? DEFAULT_TOOLSET_PLACEHOLDER
|
||||
|
|
@ -220,6 +216,7 @@ export default function NodeInputField({
|
|||
}
|
||||
isToolMode={isToolMode}
|
||||
nodeInformationMetadata={nodeInformationMetadata}
|
||||
proxy={proxy}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
// NodeOutputs.tsx
|
||||
import { OutputParameter } from ".";
|
||||
|
||||
export default function NodeOutputs({
|
||||
outputs,
|
||||
keyPrefix,
|
||||
data,
|
||||
types,
|
||||
selected,
|
||||
showNode,
|
||||
isToolMode,
|
||||
showHiddenOutputs,
|
||||
}) {
|
||||
if (!outputs?.length) return null;
|
||||
|
||||
return outputs?.map((output, idx) => (
|
||||
<OutputParameter
|
||||
key={`${keyPrefix}-${output.name}-${idx}`}
|
||||
output={output}
|
||||
idx={
|
||||
data.node!.outputs?.findIndex((out) => out.name === output.name) ?? idx
|
||||
}
|
||||
lastOutput={idx === outputs.length - 1}
|
||||
data={data}
|
||||
types={types}
|
||||
selected={selected}
|
||||
showNode={showNode}
|
||||
isToolMode={isToolMode}
|
||||
showHiddenOutputs={showHiddenOutputs}
|
||||
hidden={
|
||||
keyPrefix === "hidden"
|
||||
? showHiddenOutputs
|
||||
? output.hidden
|
||||
: true
|
||||
: false
|
||||
}
|
||||
/>
|
||||
));
|
||||
}
|
||||
|
|
@ -177,7 +177,6 @@ function NodeOutputField({
|
|||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
|
||||
// Use selective store subscriptions
|
||||
const nodes = useFlowStore((state) => state.nodes);
|
||||
const edges = useFlowStore((state) => state.edges);
|
||||
const setNode = useFlowStore((state) => state.setNode);
|
||||
const setFilterEdge = useFlowStore((state) => state.setFilterEdge);
|
||||
|
|
@ -316,11 +315,9 @@ function NodeOutputField({
|
|||
return (
|
||||
<HandleRenderComponent
|
||||
left={true}
|
||||
nodes={nodes}
|
||||
tooltipTitle={tooltipTitle}
|
||||
id={id}
|
||||
title={title}
|
||||
edges={edges}
|
||||
nodeId={data.id}
|
||||
myData={myData}
|
||||
colors={colors}
|
||||
|
|
@ -332,11 +329,9 @@ function NodeOutputField({
|
|||
);
|
||||
}
|
||||
}, [
|
||||
nodes,
|
||||
tooltipTitle,
|
||||
id,
|
||||
title,
|
||||
edges,
|
||||
data.id,
|
||||
myData,
|
||||
colors,
|
||||
|
|
@ -350,11 +345,9 @@ function NodeOutputField({
|
|||
() => (
|
||||
<HandleRenderComponent
|
||||
left={false}
|
||||
nodes={nodes}
|
||||
tooltipTitle={tooltipTitle}
|
||||
id={id}
|
||||
title={title}
|
||||
edges={edges}
|
||||
nodeId={data.id}
|
||||
myData={myData}
|
||||
colors={colors}
|
||||
|
|
@ -365,11 +358,9 @@ function NodeOutputField({
|
|||
/>
|
||||
),
|
||||
[
|
||||
nodes,
|
||||
tooltipTitle,
|
||||
id,
|
||||
title,
|
||||
edges,
|
||||
data.id,
|
||||
myData,
|
||||
colors,
|
||||
|
|
|
|||
|
|
@ -151,12 +151,10 @@ const HandleContent = memo(function HandleContent({
|
|||
|
||||
const HandleRenderComponent = memo(function HandleRenderComponent({
|
||||
left,
|
||||
nodes,
|
||||
tooltipTitle = "",
|
||||
proxy,
|
||||
id,
|
||||
title,
|
||||
edges,
|
||||
myData,
|
||||
colors,
|
||||
setFilterEdge,
|
||||
|
|
@ -166,12 +164,10 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
|||
colorName,
|
||||
}: {
|
||||
left: boolean;
|
||||
nodes: any;
|
||||
tooltipTitle?: string;
|
||||
proxy?: any;
|
||||
id: any;
|
||||
title: string;
|
||||
edges: any;
|
||||
myData: any;
|
||||
colors: string[];
|
||||
setFilterEdge: (edges: any) => void;
|
||||
|
|
@ -209,20 +205,17 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
|||
[id, proxy],
|
||||
);
|
||||
|
||||
const getConnection = useCallback(
|
||||
(semiConnection: {
|
||||
source?: string;
|
||||
sourceHandle?: string;
|
||||
target?: string;
|
||||
targetHandle?: string;
|
||||
}) => ({
|
||||
source: semiConnection.source ?? nodeId,
|
||||
sourceHandle: semiConnection.sourceHandle ?? myId,
|
||||
target: semiConnection.target ?? nodeId,
|
||||
targetHandle: semiConnection.targetHandle ?? myId,
|
||||
}),
|
||||
[nodeId, myId],
|
||||
);
|
||||
const getConnection = (semiConnection: {
|
||||
source?: string;
|
||||
sourceHandle?: string;
|
||||
target?: string;
|
||||
targetHandle?: string;
|
||||
}) => ({
|
||||
source: semiConnection.source ?? nodeId,
|
||||
sourceHandle: semiConnection.sourceHandle ?? myId,
|
||||
target: semiConnection.target ?? nodeId,
|
||||
targetHandle: semiConnection.targetHandle ?? myId,
|
||||
});
|
||||
|
||||
const {
|
||||
sameNode,
|
||||
|
|
@ -255,25 +248,26 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
|||
handleDragging &&
|
||||
(left ? handleDragging.source : handleDragging.target) &&
|
||||
!ownDraggingHandle
|
||||
? isValidConnection(getConnection(handleDragging), nodes, edges)
|
||||
? isValidConnection(getConnection(handleDragging))
|
||||
: false;
|
||||
|
||||
const filterOpenHandle =
|
||||
filterType &&
|
||||
(left ? filterType.source : filterType.target) &&
|
||||
!ownFilterHandle
|
||||
? isValidConnection(getConnection(filterType), nodes, edges)
|
||||
? isValidConnection(getConnection(filterType))
|
||||
: false;
|
||||
|
||||
const openHandle = filterOpenHandle || draggingOpenHandle;
|
||||
const filterPresent = handleDragging || filterType;
|
||||
|
||||
const connectedEdge = edges.find(
|
||||
(edge) => edge.target === nodeId && edge.targetHandle === myId,
|
||||
);
|
||||
const connectedColor =
|
||||
nodeColorsName[connectedEdge?.data?.sourceHandle?.output_types[0]] ||
|
||||
"gray";
|
||||
const connectedEdge = useFlowStore
|
||||
.getState()
|
||||
.edges.find(
|
||||
(edge) => edge.target === nodeId && edge.targetHandle === myId,
|
||||
);
|
||||
const outputType = connectedEdge?.data?.sourceHandle?.output_types?.[0];
|
||||
const connectedColor = outputType ? nodeColorsName[outputType] : "gray";
|
||||
|
||||
const isNullHandle =
|
||||
filterPresent && !(openHandle || ownDraggingHandle || ownFilterHandle);
|
||||
|
|
@ -341,9 +335,6 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
|||
filterType,
|
||||
nodeId,
|
||||
myId,
|
||||
nodes,
|
||||
edges,
|
||||
getConnection,
|
||||
dark,
|
||||
colors,
|
||||
colorName,
|
||||
|
|
@ -365,6 +356,7 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
|||
);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
const nodes = useFlowStore.getState().nodes;
|
||||
setFilterEdge(groupByFamily(myData, tooltipTitle!, left, nodes!));
|
||||
setFilterType(currentFilter);
|
||||
if (filterOpenHandle && filterType) {
|
||||
|
|
@ -376,14 +368,12 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
|||
myData,
|
||||
tooltipTitle,
|
||||
left,
|
||||
nodes,
|
||||
setFilterEdge,
|
||||
setFilterType,
|
||||
currentFilter,
|
||||
filterOpenHandle,
|
||||
filterType,
|
||||
onConnect,
|
||||
getConnection,
|
||||
]);
|
||||
|
||||
const handleMouseEnter = useCallback(() => setIsHovered(true), []);
|
||||
|
|
@ -396,8 +386,8 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
|||
|
||||
// Memoize the validation function
|
||||
const validateConnection = useCallback(
|
||||
(connection: any) => isValidConnection(connection, nodes, edges),
|
||||
[nodes, edges],
|
||||
(connection: any) => isValidConnection(connection),
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
@ -424,7 +414,7 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
|||
position={left ? Position.Left : Position.Right}
|
||||
id={myId}
|
||||
isValidConnection={(connection) =>
|
||||
isValidConnection(connection as Connection, nodes, edges)
|
||||
isValidConnection(connection as Connection)
|
||||
}
|
||||
className={cn(
|
||||
`group/handle z-50 transition-all`,
|
||||
|
|
|
|||
|
|
@ -24,25 +24,24 @@ import { useShortcutsStore } from "../../stores/shortcuts";
|
|||
import { useTypesStore } from "../../stores/typesStore";
|
||||
import { VertexBuildTypeAPI } from "../../types/api";
|
||||
import { NodeDataType } from "../../types/flow";
|
||||
import { checkHasToolMode } from "../../utils/reactflowUtils";
|
||||
import { classNames, cn } from "../../utils/utils";
|
||||
import { processNodeAdvancedFields } from "../helpers/process-node-advanced-fields";
|
||||
import useUpdateNodeCode from "../hooks/use-update-node-code";
|
||||
import NodeDescription from "./components/NodeDescription";
|
||||
import NodeName from "./components/NodeName";
|
||||
import { OutputParameter } from "./components/NodeOutputParameter";
|
||||
import NodeOutputs from "./components/NodeOutputParameter/NodeOutputs";
|
||||
import NodeStatus from "./components/NodeStatus";
|
||||
import NodeUpdateComponent from "./components/NodeUpdateComponent";
|
||||
import RenderInputParameters from "./components/RenderInputParameters";
|
||||
import { NodeIcon } from "./components/nodeIcon";
|
||||
import { useBuildStatus } from "./hooks/use-get-build-status";
|
||||
|
||||
const MemoizedOutputParameter = memo(OutputParameter);
|
||||
const MemoizedRenderInputParameters = memo(RenderInputParameters);
|
||||
const MemoizedNodeIcon = memo(NodeIcon);
|
||||
const MemoizedNodeName = memo(NodeName);
|
||||
const MemoizedNodeStatus = memo(CustomNodeStatus);
|
||||
const MemoizedNodeDescription = memo(NodeDescription);
|
||||
const MemoizedNodeOutputs = memo(NodeOutputs);
|
||||
|
||||
const HiddenOutputsButton = memo(
|
||||
({
|
||||
|
|
@ -104,10 +103,10 @@ function GenericNode({
|
|||
|
||||
const showNode = data.showNode ?? true;
|
||||
|
||||
const getValidationStatus = (data) => {
|
||||
const getValidationStatus = useCallback((data) => {
|
||||
setValidationStatus(data);
|
||||
return null;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const { mutate: validateComponentCode } = usePostValidateComponentCode();
|
||||
|
||||
|
|
@ -246,45 +245,18 @@ function GenericNode({
|
|||
callback: toggleEditNameDescription,
|
||||
});
|
||||
|
||||
const renderOutputs = useCallback(
|
||||
(outputs, key?: string) => {
|
||||
return outputs?.map((output, idx) => (
|
||||
<MemoizedOutputParameter
|
||||
key={`${key}-${output.name}-${idx}`}
|
||||
output={output}
|
||||
idx={
|
||||
data.node!.outputs?.findIndex((out) => out.name === output.name) ??
|
||||
idx
|
||||
}
|
||||
lastOutput={idx === outputs.length - 1}
|
||||
data={data}
|
||||
types={types}
|
||||
selected={selected}
|
||||
showNode={showNode}
|
||||
isToolMode={isToolMode}
|
||||
showHiddenOutputs={showHiddenOutputs}
|
||||
hidden={
|
||||
key === "hidden"
|
||||
? showHiddenOutputs
|
||||
? output.hidden
|
||||
: true
|
||||
: false
|
||||
}
|
||||
/>
|
||||
));
|
||||
},
|
||||
[data, types, selected, showNode, isToolMode, showHiddenOutputs],
|
||||
);
|
||||
|
||||
const { shownOutputs, hiddenOutputs } = useMemo(
|
||||
() => ({
|
||||
shownOutputs:
|
||||
data.node?.outputs?.filter((output) => !output.hidden) ?? [],
|
||||
hiddenOutputs:
|
||||
data.node?.outputs?.filter((output) => output.hidden) ?? [],
|
||||
}),
|
||||
[data.node?.outputs],
|
||||
);
|
||||
const { shownOutputs, hiddenOutputs } = useMemo(() => {
|
||||
const shownOutputs: typeof data.node.outputs = [];
|
||||
const hiddenOutputs: typeof data.node.outputs = [];
|
||||
(data.node?.outputs ?? []).forEach((output) => {
|
||||
if (output.hidden) {
|
||||
hiddenOutputs.push(output);
|
||||
} else {
|
||||
shownOutputs.push(output);
|
||||
}
|
||||
});
|
||||
return { shownOutputs, hiddenOutputs };
|
||||
}, [data.node?.outputs]);
|
||||
|
||||
const [hasChangedNodeDescription, setHasChangedNodeDescription] =
|
||||
useState(false);
|
||||
|
|
@ -391,114 +363,26 @@ function GenericNode({
|
|||
toggleEditNameDescription,
|
||||
selectedNodesCount,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hiddenOutputs && hiddenOutputs.length === 0) {
|
||||
setShowHiddenOutputs(false);
|
||||
}
|
||||
}, [hiddenOutputs]);
|
||||
|
||||
const renderNodeIcon = useCallback(() => {
|
||||
return (
|
||||
<MemoizedNodeIcon
|
||||
dataType={data.type}
|
||||
showNode={showNode}
|
||||
icon={data.node?.icon}
|
||||
isGroup={!!data.node?.flow}
|
||||
/>
|
||||
);
|
||||
}, [data.type, showNode, data.node?.icon, data.node?.flow]);
|
||||
const handleToggleHiddenOutputs = useCallback(
|
||||
() => setShowHiddenOutputs((prev) => !prev),
|
||||
[],
|
||||
);
|
||||
|
||||
const renderNodeName = useCallback(() => {
|
||||
return (
|
||||
<MemoizedNodeName
|
||||
display_name={data.node?.display_name}
|
||||
nodeId={data.id}
|
||||
selected={selected}
|
||||
showNode={showNode}
|
||||
validationStatus={validationStatus}
|
||||
isOutdated={isOutdated}
|
||||
beta={data.node?.beta || false}
|
||||
editNameDescription={editNameDescription}
|
||||
toggleEditNameDescription={toggleEditNameDescription}
|
||||
setHasChangedNodeDescription={setHasChangedNodeDescription}
|
||||
/>
|
||||
);
|
||||
}, [
|
||||
data.node?.display_name,
|
||||
data.id,
|
||||
selected,
|
||||
showNode,
|
||||
validationStatus,
|
||||
isOutdated,
|
||||
data.node?.beta,
|
||||
editNameDescription,
|
||||
toggleEditNameDescription,
|
||||
setHasChangedNodeDescription,
|
||||
]);
|
||||
|
||||
const renderNodeStatus = useCallback(() => {
|
||||
return (
|
||||
<MemoizedNodeStatus
|
||||
data={data}
|
||||
frozen={data.node?.frozen}
|
||||
showNode={showNode}
|
||||
display_name={data.node?.display_name!}
|
||||
nodeId={data.id}
|
||||
selected={selected}
|
||||
setBorderColor={setBorderColor}
|
||||
buildStatus={buildStatus}
|
||||
dismissAll={dismissAll}
|
||||
isOutdated={isOutdated}
|
||||
isUserEdited={isUserEdited}
|
||||
isBreakingChange={hasBreakingChange}
|
||||
getValidationStatus={getValidationStatus}
|
||||
/>
|
||||
);
|
||||
}, [
|
||||
data,
|
||||
showNode,
|
||||
selected,
|
||||
buildStatus,
|
||||
isOutdated,
|
||||
isUserEdited,
|
||||
getValidationStatus,
|
||||
dismissAll,
|
||||
handleUpdateCode,
|
||||
]);
|
||||
|
||||
const renderDescription = useCallback(() => {
|
||||
return (
|
||||
<MemoizedNodeDescription
|
||||
description={data.node?.description}
|
||||
mdClassName={"dark:prose-invert"}
|
||||
nodeId={data.id}
|
||||
selected={selected}
|
||||
editNameDescription={editNameDescription}
|
||||
setEditNameDescription={set}
|
||||
setHasChangedNodeDescription={setHasChangedNodeDescription}
|
||||
/>
|
||||
);
|
||||
}, [
|
||||
data.node?.description,
|
||||
data.id,
|
||||
selected,
|
||||
editNameDescription,
|
||||
toggleEditNameDescription,
|
||||
setHasChangedNodeDescription,
|
||||
]);
|
||||
|
||||
const renderInputParameters = useCallback(() => {
|
||||
return (
|
||||
<MemoizedRenderInputParameters
|
||||
data={data}
|
||||
types={types}
|
||||
isToolMode={isToolMode}
|
||||
showNode={showNode}
|
||||
shownOutputs={shownOutputs}
|
||||
showHiddenOutputs={showHiddenOutputs}
|
||||
/>
|
||||
);
|
||||
}, [data, types, isToolMode, showNode, shownOutputs, showHiddenOutputs]);
|
||||
const memoizedOnUpdateNode = useCallback(
|
||||
() => handleUpdateCode(true),
|
||||
[handleUpdateCode],
|
||||
);
|
||||
const memoizedSetDismissAll = useCallback(
|
||||
() => addDismissedNodes([data.id]),
|
||||
[addDismissedNodes, data.id],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={cn(shouldShowUpdateComponent ? "relative -mt-10" : "")}>
|
||||
|
|
@ -510,20 +394,22 @@ function GenericNode({
|
|||
!hasOutputs && "pb-4",
|
||||
)}
|
||||
>
|
||||
<UpdateComponentModal
|
||||
open={openUpdateModal}
|
||||
setOpen={setOpenUpdateModal}
|
||||
onUpdateNode={() => handleUpdateCode(true)}
|
||||
components={componentUpdate ? [componentUpdate] : []}
|
||||
/>
|
||||
{openUpdateModal && (
|
||||
<UpdateComponentModal
|
||||
open={openUpdateModal}
|
||||
setOpen={setOpenUpdateModal}
|
||||
onUpdateNode={memoizedOnUpdateNode}
|
||||
components={componentUpdate ? [componentUpdate] : []}
|
||||
/>
|
||||
)}
|
||||
{memoizedNodeToolbarComponent}
|
||||
{shouldShowUpdateComponent && (
|
||||
<NodeUpdateComponent
|
||||
hasBreakingChange={hasBreakingChange}
|
||||
showNode={showNode}
|
||||
handleUpdateCode={() => handleUpdateCode()}
|
||||
handleUpdateCode={handleUpdateCode}
|
||||
loadingUpdate={loadingUpdate}
|
||||
setDismissAll={() => addDismissedNodes([data.id])}
|
||||
setDismissAll={memoizedSetDismissAll}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
|
|
@ -546,28 +432,92 @@ function GenericNode({
|
|||
className={"generic-node-title-arrangement"}
|
||||
data-testid="generic-node-title-arrangement"
|
||||
>
|
||||
{renderNodeIcon()}
|
||||
<MemoizedNodeIcon
|
||||
dataType={data.type}
|
||||
showNode={showNode}
|
||||
icon={data.node?.icon}
|
||||
isGroup={!!data.node?.flow}
|
||||
/>
|
||||
<div className="generic-node-tooltip-div truncate">
|
||||
{renderNodeName()}
|
||||
<MemoizedNodeName
|
||||
display_name={data.node?.display_name}
|
||||
nodeId={data.id}
|
||||
selected={selected}
|
||||
showNode={showNode}
|
||||
validationStatus={validationStatus}
|
||||
isOutdated={isOutdated}
|
||||
beta={data.node?.beta || false}
|
||||
editNameDescription={editNameDescription}
|
||||
toggleEditNameDescription={toggleEditNameDescription}
|
||||
setHasChangedNodeDescription={setHasChangedNodeDescription}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div data-testid={`${showNode ? "show" : "hide"}-node-content`}>
|
||||
{!showNode && (
|
||||
<>
|
||||
{renderInputParameters()}
|
||||
{shownOutputs.length > 0 &&
|
||||
renderOutputs(shownOutputs, "render-outputs")}
|
||||
<MemoizedRenderInputParameters
|
||||
data={data}
|
||||
types={types}
|
||||
isToolMode={isToolMode}
|
||||
showNode={showNode}
|
||||
shownOutputs={shownOutputs}
|
||||
showHiddenOutputs={showHiddenOutputs}
|
||||
/>
|
||||
<MemoizedNodeOutputs
|
||||
outputs={shownOutputs}
|
||||
keyPrefix="render-outputs"
|
||||
data={data}
|
||||
types={types}
|
||||
selected={selected}
|
||||
showNode={showNode}
|
||||
isToolMode={isToolMode}
|
||||
showHiddenOutputs={showHiddenOutputs}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{renderNodeStatus()}
|
||||
<MemoizedNodeStatus
|
||||
data={data}
|
||||
frozen={data.node?.frozen}
|
||||
showNode={showNode}
|
||||
display_name={data.node?.display_name!}
|
||||
nodeId={data.id}
|
||||
selected={selected}
|
||||
setBorderColor={setBorderColor}
|
||||
buildStatus={buildStatus}
|
||||
dismissAll={dismissAll}
|
||||
isOutdated={isOutdated}
|
||||
isUserEdited={isUserEdited}
|
||||
isBreakingChange={hasBreakingChange}
|
||||
getValidationStatus={getValidationStatus}
|
||||
/>
|
||||
</div>
|
||||
{showNode && <div>{renderDescription()}</div>}
|
||||
{showNode && (
|
||||
<div>
|
||||
<MemoizedNodeDescription
|
||||
description={data.node?.description}
|
||||
mdClassName={"dark:prose-invert"}
|
||||
nodeId={data.id}
|
||||
selected={selected}
|
||||
editNameDescription={editNameDescription}
|
||||
setEditNameDescription={set}
|
||||
setHasChangedNodeDescription={setHasChangedNodeDescription}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{showNode && (
|
||||
<div className="nopan nodelete nodrag noflow relative cursor-auto">
|
||||
<>
|
||||
{renderInputParameters()}
|
||||
<MemoizedRenderInputParameters
|
||||
data={data}
|
||||
types={types}
|
||||
isToolMode={isToolMode}
|
||||
showNode={showNode}
|
||||
shownOutputs={shownOutputs}
|
||||
showHiddenOutputs={showHiddenOutputs}
|
||||
/>
|
||||
<div
|
||||
className={classNames(
|
||||
Object.keys(data.node!.template).length < 1 ? "hidden" : "",
|
||||
|
|
@ -576,15 +526,33 @@ function GenericNode({
|
|||
>
|
||||
{" "}
|
||||
</div>
|
||||
{!showHiddenOutputs &&
|
||||
shownOutputs &&
|
||||
renderOutputs(shownOutputs, "shown")}
|
||||
{!showHiddenOutputs && shownOutputs && (
|
||||
<MemoizedNodeOutputs
|
||||
outputs={shownOutputs}
|
||||
keyPrefix="shown"
|
||||
data={data}
|
||||
types={types}
|
||||
selected={selected}
|
||||
showNode={showNode}
|
||||
isToolMode={isToolMode}
|
||||
showHiddenOutputs={showHiddenOutputs}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
className={cn(showHiddenOutputs ? "" : "h-0 overflow-hidden")}
|
||||
>
|
||||
<div className="block">
|
||||
{renderOutputs(data.node!.outputs, "hidden")}
|
||||
<MemoizedNodeOutputs
|
||||
outputs={data.node!.outputs}
|
||||
keyPrefix="hidden"
|
||||
data={data}
|
||||
types={types}
|
||||
selected={selected}
|
||||
showNode={showNode}
|
||||
isToolMode={isToolMode}
|
||||
showHiddenOutputs={showHiddenOutputs}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{hiddenOutputs && hiddenOutputs.length > 0 && (
|
||||
|
|
@ -606,7 +574,7 @@ function GenericNode({
|
|||
>
|
||||
<HiddenOutputsButton
|
||||
showHiddenOutputs={showHiddenOutputs}
|
||||
onClick={() => setShowHiddenOutputs(!showHiddenOutputs)}
|
||||
onClick={handleToggleHiddenOutputs}
|
||||
/>
|
||||
</div>
|
||||
</ShadTooltip>
|
||||
|
|
|
|||
|
|
@ -1,36 +1,50 @@
|
|||
import { ParameterRenderComponent } from "@/components/core/parameterRenderComponent";
|
||||
import { NodeInfoType } from "@/components/core/parameterRenderComponent/types";
|
||||
import { handleOnNewValueType } from "@/CustomNodes/hooks/use-handle-new-value";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import { APIClassType, InputFieldType } from "@/types/api";
|
||||
import { targetHandleType } from "@/types/flow";
|
||||
import { scapedJSONStringfy } from "@/utils/reactflowUtils";
|
||||
import { cn } from "@/utils/utils";
|
||||
|
||||
export function CustomParameterComponent({
|
||||
handleOnNewValue,
|
||||
name,
|
||||
nodeId,
|
||||
inputId,
|
||||
templateData,
|
||||
templateValue,
|
||||
editNode,
|
||||
handleNodeClass,
|
||||
nodeClass,
|
||||
disabled,
|
||||
placeholder,
|
||||
isToolMode,
|
||||
isToolMode = false,
|
||||
nodeInformationMetadata,
|
||||
proxy,
|
||||
}: {
|
||||
handleOnNewValue: handleOnNewValueType;
|
||||
name: string;
|
||||
nodeId: string;
|
||||
inputId: targetHandleType;
|
||||
templateData: Partial<InputFieldType>;
|
||||
templateValue: any;
|
||||
editNode: boolean;
|
||||
handleNodeClass: (value: any, code?: string, type?: string) => void;
|
||||
nodeClass: APIClassType;
|
||||
disabled: boolean;
|
||||
placeholder?: string;
|
||||
isToolMode?: boolean;
|
||||
nodeInformationMetadata?: NodeInfoType;
|
||||
proxy: { field: string; id: string } | undefined;
|
||||
}) {
|
||||
const edges = useFlowStore((state) => state.edges);
|
||||
|
||||
let disabled =
|
||||
edges.some(
|
||||
(edge) =>
|
||||
edge.targetHandle ===
|
||||
scapedJSONStringfy(proxy ? { ...inputId, proxy } : inputId),
|
||||
) || isToolMode;
|
||||
|
||||
return (
|
||||
<ParameterRenderComponent
|
||||
handleOnNewValue={handleOnNewValue}
|
||||
|
|
|
|||
|
|
@ -79,8 +79,6 @@ const NodeToolbarComponent = memo(
|
|||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
|
||||
const paste = useFlowStore((state) => state.paste);
|
||||
const nodes = useFlowStore((state) => state.nodes);
|
||||
const edges = useFlowStore((state) => state.edges);
|
||||
const setNodes = useFlowStore((state) => state.setNodes);
|
||||
const setEdges = useFlowStore((state) => state.setEdges);
|
||||
const getNodePosition = useFlowStore((state) => state.getNodePosition);
|
||||
|
|
@ -200,8 +198,6 @@ const NodeToolbarComponent = memo(
|
|||
data.id,
|
||||
updateFlowPosition(getNodePosition(data.id), data.node?.flow!),
|
||||
data.node!.template,
|
||||
nodes,
|
||||
edges,
|
||||
setNodes,
|
||||
setEdges,
|
||||
data.node?.outputs,
|
||||
|
|
@ -213,8 +209,6 @@ const NodeToolbarComponent = memo(
|
|||
data.node?.flow,
|
||||
data.node?.template,
|
||||
data.node?.outputs,
|
||||
nodes,
|
||||
edges,
|
||||
setNodes,
|
||||
setEdges,
|
||||
takeSnapshot,
|
||||
|
|
@ -307,6 +301,7 @@ const NodeToolbarComponent = memo(
|
|||
|
||||
const handleSelectChange = useCallback(
|
||||
(event) => {
|
||||
let nodes;
|
||||
setSelectedValue(event);
|
||||
|
||||
switch (event) {
|
||||
|
|
@ -356,10 +351,12 @@ const NodeToolbarComponent = memo(
|
|||
updateNode();
|
||||
break;
|
||||
case "copy":
|
||||
nodes = useFlowStore.getState().nodes;
|
||||
const node = nodes.filter((node) => node.id === data.id);
|
||||
setLastCopiedSelection({ nodes: _.cloneDeep(node), edges: [] });
|
||||
break;
|
||||
case "duplicate":
|
||||
nodes = useFlowStore.getState().nodes;
|
||||
paste(
|
||||
{
|
||||
nodes: [nodes.find((node) => node.id === data.id)!],
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {
|
|||
} from "@/CustomNodes/utils/get-handle-id";
|
||||
import { INCOMPLETE_LOOP_ERROR_ALERT } from "@/constants/alerts_constants";
|
||||
import { customDownloadFlow } from "@/customization/utils/custom-reactFlowUtils";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import {
|
||||
Connection,
|
||||
Edge,
|
||||
|
|
@ -320,12 +321,16 @@ export function unselectAllNodesEdges(nodes: Node[], edges: Edge[]) {
|
|||
|
||||
export function isValidConnection(
|
||||
{ source, target, sourceHandle, targetHandle }: Connection,
|
||||
nodes: AllNodeType[],
|
||||
edges: EdgeType[],
|
||||
nodes?: AllNodeType[],
|
||||
edges?: EdgeType[],
|
||||
): boolean {
|
||||
if (source === target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const nodesArray = nodes || useFlowStore.getState().nodes;
|
||||
const edgesArray = edges || useFlowStore.getState().edges;
|
||||
|
||||
const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!);
|
||||
const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!);
|
||||
if (
|
||||
|
|
@ -345,20 +350,20 @@ export function isValidConnection(
|
|||
t === targetHandleObject.type,
|
||||
)
|
||||
) {
|
||||
let targetNode = nodes.find((node) => node.id === target!)?.data?.node;
|
||||
let targetNode = nodesArray.find((node) => node.id === target!)?.data?.node;
|
||||
if (!targetNode) {
|
||||
if (!edges.find((e) => e.targetHandle === targetHandle)) {
|
||||
if (!edgesArray.find((e) => e.targetHandle === targetHandle)) {
|
||||
return true;
|
||||
}
|
||||
} else if (
|
||||
targetHandleObject.output_types &&
|
||||
!edges.find((e) => e.targetHandle === targetHandle)
|
||||
!edgesArray.find((e) => e.targetHandle === targetHandle)
|
||||
) {
|
||||
return true;
|
||||
} else if (
|
||||
!targetHandleObject.output_types &&
|
||||
((!targetNode.template[targetHandleObject.fieldName].list &&
|
||||
!edges.find((e) => e.targetHandle === targetHandle)) ||
|
||||
!edgesArray.find((e) => e.targetHandle === targetHandle)) ||
|
||||
targetNode.template[targetHandleObject.fieldName].list)
|
||||
) {
|
||||
return true;
|
||||
|
|
@ -1476,8 +1481,6 @@ export function expandGroupNode(
|
|||
id: string,
|
||||
flow: FlowType,
|
||||
template: APITemplateType,
|
||||
nodes: AllNodeType[],
|
||||
edges: EdgeType[],
|
||||
setNodes: (
|
||||
update: AllNodeType[] | ((oldState: AllNodeType[]) => AllNodeType[]),
|
||||
) => void,
|
||||
|
|
@ -1488,7 +1491,7 @@ export function expandGroupNode(
|
|||
) {
|
||||
const idsMap = updateIds(flow!.data!);
|
||||
updateProxyIdsOnTemplate(template, idsMap);
|
||||
let flowEdges = edges;
|
||||
let flowEdges = useFlowStore.getState().edges;
|
||||
updateEdgesIds(flowEdges, idsMap);
|
||||
const gNodes: AllNodeType[] = cloneDeep(flow?.data?.nodes!);
|
||||
const gEdges = cloneDeep(flow!.data!.edges);
|
||||
|
|
@ -1588,9 +1591,12 @@ export function expandGroupNode(
|
|||
}
|
||||
}
|
||||
});
|
||||
const filteredNodes = [...nodes.filter((n) => n.id !== id), ...gNodes];
|
||||
const filteredNodes = [
|
||||
...useFlowStore.getState().nodes.filter((n) => n.id !== id),
|
||||
...gNodes,
|
||||
];
|
||||
const filteredEdges = [
|
||||
...edges.filter((e) => e.target !== id && e.source !== id),
|
||||
...flowEdges.filter((e) => e.target !== id && e.source !== id),
|
||||
...gEdges,
|
||||
];
|
||||
setNodes(filteredNodes);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue