📝 (handleRenderComponent/index.tsx): Add useShallow import for zustand/react/shallow to optimize re-renders
📝 (handleRenderComponent/index.tsx): Introduce isLocked state to handle locked flow functionality 📝 (handleRenderComponent/index.tsx): Update tooltip visibility based on isLocked state 📝 (handleRenderComponent/index.tsx): Update handle style based on isLocked state 📝 (PageComponent/index.tsx): Add useShallow import for zustand/react/shallow to optimize re-renders 📝 (PageComponent/index.tsx): Introduce isLocked state to handle locked flow functionality 📝 (PageComponent/index.tsx): Prevent edge click actions when flow is locked 📝 (PageComponent/index.tsx): Disable edge actions when flow is locked 📝 (PageComponent/index.tsx): Update edge actions based on isLocked state 📝 (lock-flow.spec.ts): Add test to simulate deleting edges when flow is locked
This commit is contained in:
parent
cf985bd834
commit
9898d1cacd
3 changed files with 63 additions and 14 deletions
|
|
@ -3,6 +3,7 @@ import useFlowStore from "@/stores/flowStore";
|
||||||
import { nodeColorsName } from "@/utils/styleUtils";
|
import { nodeColorsName } from "@/utils/styleUtils";
|
||||||
import { Connection, Handle, Position } from "@xyflow/react";
|
import { Connection, Handle, Position } from "@xyflow/react";
|
||||||
import { memo, useCallback, useEffect, useMemo, useState } from "react";
|
import { memo, useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
import { useShallow } from "zustand/react/shallow";
|
||||||
import ShadTooltip from "../../../../components/common/shadTooltipComponent";
|
import ShadTooltip from "../../../../components/common/shadTooltipComponent";
|
||||||
import {
|
import {
|
||||||
isValidConnection,
|
isValidConnection,
|
||||||
|
|
@ -179,6 +180,10 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
const [openTooltip, setOpenTooltip] = useState(false);
|
const [openTooltip, setOpenTooltip] = useState(false);
|
||||||
|
|
||||||
|
const isLocked = useFlowStore(
|
||||||
|
useShallow((state) => state.currentFlow?.locked),
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setHandleDragging,
|
setHandleDragging,
|
||||||
setFilterType,
|
setFilterType,
|
||||||
|
|
@ -384,16 +389,10 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Memoize the validation function
|
|
||||||
const validateConnection = useCallback(
|
|
||||||
(connection: any) => isValidConnection(connection),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ShadTooltip
|
<ShadTooltip
|
||||||
open={openTooltip}
|
open={openTooltip && !isLocked}
|
||||||
setOpen={setOpenTooltip}
|
setOpen={setOpenTooltip}
|
||||||
styleClasses={cn("tooltip-fixed-width custom-scroll nowheel bottom-2")}
|
styleClasses={cn("tooltip-fixed-width custom-scroll nowheel bottom-2")}
|
||||||
delayDuration={1000}
|
delayDuration={1000}
|
||||||
|
|
@ -414,13 +413,16 @@ const HandleRenderComponent = memo(function HandleRenderComponent({
|
||||||
position={left ? Position.Left : Position.Right}
|
position={left ? Position.Left : Position.Right}
|
||||||
id={myId}
|
id={myId}
|
||||||
isValidConnection={(connection) =>
|
isValidConnection={(connection) =>
|
||||||
isValidConnection(connection as Connection)
|
isLocked ? false : isValidConnection(connection as Connection)
|
||||||
}
|
}
|
||||||
className={cn(
|
className={cn(
|
||||||
`group/handle z-50 transition-all`,
|
`group/handle z-50 transition-all`,
|
||||||
!showNode && "no-show",
|
!showNode && "no-show",
|
||||||
)}
|
)}
|
||||||
style={BASE_HANDLE_STYLES}
|
style={{
|
||||||
|
...BASE_HANDLE_STYLES,
|
||||||
|
pointerEvents: isLocked ? "none" : "auto",
|
||||||
|
}}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
onMouseUp={handleMouseUp}
|
onMouseUp={handleMouseUp}
|
||||||
onContextMenu={handleContextMenu}
|
onContextMenu={handleContextMenu}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import {
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { useHotkeys } from "react-hotkeys-hook";
|
import { useHotkeys } from "react-hotkeys-hook";
|
||||||
|
import { useShallow } from "zustand/react/shallow";
|
||||||
import GenericNode from "../../../../CustomNodes/GenericNode";
|
import GenericNode from "../../../../CustomNodes/GenericNode";
|
||||||
import {
|
import {
|
||||||
INVALID_SELECTION_ERROR_ALERT,
|
INVALID_SELECTION_ERROR_ALERT,
|
||||||
|
|
@ -124,6 +125,10 @@ export default function Page({
|
||||||
const [selectionMenuVisible, setSelectionMenuVisible] = useState(false);
|
const [selectionMenuVisible, setSelectionMenuVisible] = useState(false);
|
||||||
const edgeUpdateSuccessful = useRef(true);
|
const edgeUpdateSuccessful = useRef(true);
|
||||||
|
|
||||||
|
const isLocked = useFlowStore(
|
||||||
|
useShallow((state) => state.currentFlow?.locked),
|
||||||
|
);
|
||||||
|
|
||||||
const position = useRef({ x: 0, y: 0 });
|
const position = useRef({ x: 0, y: 0 });
|
||||||
const [lastSelection, setLastSelection] =
|
const [lastSelection, setLastSelection] =
|
||||||
useState<OnSelectionChangeParams | null>(null);
|
useState<OnSelectionChangeParams | null>(null);
|
||||||
|
|
@ -521,6 +526,11 @@ export default function Page({
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleEdgeClick = (event, edge) => {
|
const handleEdgeClick = (event, edge) => {
|
||||||
|
if (isLocked) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const color =
|
const color =
|
||||||
nodeColorsName[edge?.data?.sourceHandle?.output_types[0]] || "cyan";
|
nodeColorsName[edge?.data?.sourceHandle?.output_types[0]] || "cyan";
|
||||||
|
|
||||||
|
|
@ -584,13 +594,13 @@ export default function Page({
|
||||||
edges={edges}
|
edges={edges}
|
||||||
onNodesChange={onNodesChange}
|
onNodesChange={onNodesChange}
|
||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
onConnect={onConnectMod}
|
onConnect={isLocked ? undefined : onConnectMod}
|
||||||
disableKeyboardA11y={true}
|
disableKeyboardA11y={true}
|
||||||
onInit={setReactFlowInstance}
|
onInit={setReactFlowInstance}
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
onReconnect={onEdgeUpdate}
|
onReconnect={isLocked ? undefined : onEdgeUpdate}
|
||||||
onReconnectStart={onEdgeUpdateStart}
|
onReconnectStart={isLocked ? undefined : onEdgeUpdateStart}
|
||||||
onReconnectEnd={onEdgeUpdateEnd}
|
onReconnectEnd={isLocked ? undefined : onEdgeUpdateEnd}
|
||||||
onNodeDragStart={onNodeDragStart}
|
onNodeDragStart={onNodeDragStart}
|
||||||
onSelectionDragStart={onSelectionDragStart}
|
onSelectionDragStart={onSelectionDragStart}
|
||||||
elevateEdgesOnSelect={true}
|
elevateEdgesOnSelect={true}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { test } from "@playwright/test";
|
import { expect, Page, test } from "@playwright/test";
|
||||||
import * as dotenv from "dotenv";
|
import * as dotenv from "dotenv";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
|
||||||
|
|
@ -74,5 +74,42 @@ test(
|
||||||
timeout: 3000,
|
timeout: 3000,
|
||||||
state: "visible",
|
state: "visible",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await tryDeleteEdge(page);
|
||||||
|
await page.locator(".react-flow__edge-path").nth(0).click();
|
||||||
|
await page.keyboard.press("Delete");
|
||||||
|
let numberOfEdges = await page.locator(".react-flow__edge-path").count();
|
||||||
|
expect(numberOfEdges).toBe(2);
|
||||||
|
|
||||||
|
await page.locator(".react-flow__edge-path").nth(0).click();
|
||||||
|
await page.keyboard.press("Delete");
|
||||||
|
numberOfEdges = await page.locator(".react-flow__edge-path").count();
|
||||||
|
expect(numberOfEdges).toBe(1);
|
||||||
|
|
||||||
|
await page.locator(".react-flow__edge-path").nth(0).click();
|
||||||
|
await page.keyboard.press("Delete");
|
||||||
|
numberOfEdges = await page.locator(".react-flow__edge-path").count();
|
||||||
|
expect(numberOfEdges).toBe(0);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
async function tryDeleteEdge(page: Page) {
|
||||||
|
await page.getByTestId("lock_unlock").click();
|
||||||
|
|
||||||
|
let numberOfEdges = await page.locator(".react-flow__edge-path").count();
|
||||||
|
expect(numberOfEdges).toBe(3);
|
||||||
|
const numberOfTries = 50;
|
||||||
|
|
||||||
|
for (let i = 0; i < numberOfTries; i++) {
|
||||||
|
await page.locator(".react-flow__edge-path").nth(0).click();
|
||||||
|
await page.keyboard.press("Delete");
|
||||||
|
await page.locator(".react-flow__edge-path").nth(1).click();
|
||||||
|
await page.keyboard.press("Delete");
|
||||||
|
await page.locator(".react-flow__edge-path").nth(2).click();
|
||||||
|
await page.keyboard.press("Delete");
|
||||||
|
numberOfEdges = await page.locator(".react-flow__edge-path").count();
|
||||||
|
expect(numberOfEdges).toBe(3);
|
||||||
|
}
|
||||||
|
//unlock the flow
|
||||||
|
await page.getByTestId("lock_unlock").click();
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue