浏览代码

fix: prevent multiple node panel openings and add active state management (#1012)

Louis Young 1 月之前
父节点
当前提交
a3560928d2
共有 2 个文件被更改,包括 86 次插入54 次删除
  1. 85 54
      apps/demo-free-layout/src/hooks/use-port-click.ts
  2. 1 0
      packages/plugins/free-node-panel-plugin/src/index.ts

+ 85 - 54
apps/demo-free-layout/src/hooks/use-port-click.ts

@@ -3,11 +3,13 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { useCallback } from 'react';
+import { useCallback, useState } from 'react';
 
 import {
   WorkflowNodePanelService,
   WorkflowNodePanelUtils,
+  type CallNodePanelParams,
+  type NodePanelResult,
 } from '@flowgram.ai/free-node-panel-plugin';
 import {
   delay,
@@ -31,66 +33,95 @@ export const usePortClick = () => {
   const document = useService(WorkflowDocument);
   const dragService = useService(WorkflowDragService);
   const linesManager = useService(WorkflowLinesManager);
+  const [active, setActive] = useState(false);
 
-  const onPortClick = useCallback(async (e: React.MouseEvent, port: WorkflowPortEntity) => {
-    if (port.portType === 'input') return;
-    const mousePos = playground.config.getPosFromMouseEvent(e);
-    const containerNode = port.node.parent;
-    // open node selection panel - 打开节点选择面板
-    const result = await nodePanelService.singleSelectNodePanel({
-      position: mousePos,
-      containerNode,
-      panelProps: {
-        enableScrollClose: true,
-        fromPort: port,
-      },
-    });
+  const singleSelectNodePanel = useCallback(
+    async (
+      params: Omit<CallNodePanelParams, 'onSelect' | 'onClose' | 'enableMultiAdd'>
+    ): Promise<NodePanelResult | undefined> => {
+      if (active) {
+        return;
+      }
+      setActive(true);
+      return new Promise((resolve) => {
+        nodePanelService.callNodePanel({
+          ...params,
+          enableMultiAdd: false,
+          onSelect: async (panelParams?: NodePanelResult) => {
+            resolve(panelParams);
+          },
+          onClose: () => {
+            setActive(false);
+            resolve(undefined);
+          },
+        });
+      });
+    },
+    [active]
+  );
+
+  const onPortClick = useCallback(
+    async (e: React.MouseEvent, port: WorkflowPortEntity) => {
+      if (port.portType === 'input') return;
+      const mousePos = playground.config.getPosFromMouseEvent(e);
+      const containerNode = port.node.parent;
+      // open node selection panel - 打开节点选择面板
+      const result = await singleSelectNodePanel({
+        position: mousePos,
+        containerNode,
+        panelProps: {
+          enableScrollClose: true,
+          fromPort: port,
+        },
+      });
 
-    // return if no node selected - 如果没有选择节点则返回
-    if (!result) {
-      return;
-    }
+      // return if no node selected - 如果没有选择节点则返回
+      if (!result) {
+        return;
+      }
 
-    // get selected node type and data - 获取选择的节点类型和数据
-    const { nodeType, nodeJSON } = result;
+      // get selected node type and data - 获取选择的节点类型和数据
+      const { nodeType, nodeJSON } = result;
 
-    // calculate position for the new node - 计算新节点的位置
-    const nodePosition = WorkflowNodePanelUtils.adjustNodePosition({
-      nodeType,
-      position:
-        port.location === 'bottom'
-          ? {
-              x: mousePos.x,
-              y: mousePos.y + 100,
-            }
-          : {
-              x: mousePos.x + 100,
-              y: mousePos.y,
-            },
-      fromPort: port,
-      containerNode,
-      document,
-      dragService,
-    });
+      // calculate position for the new node - 计算新节点的位置
+      const nodePosition = WorkflowNodePanelUtils.adjustNodePosition({
+        nodeType,
+        position:
+          port.location === 'bottom'
+            ? {
+                x: mousePos.x,
+                y: mousePos.y + 100,
+              }
+            : {
+                x: mousePos.x + 100,
+                y: mousePos.y,
+              },
+        fromPort: port,
+        containerNode,
+        document,
+        dragService,
+      });
 
-    // create new workflow node - 创建新的工作流节点
-    const node: WorkflowNodeEntity = document.createWorkflowNodeByType(
-      nodeType,
-      nodePosition,
-      nodeJSON ?? ({} as WorkflowNodeJSON),
-      containerNode?.id
-    );
+      // create new workflow node - 创建新的工作流节点
+      const node: WorkflowNodeEntity = document.createWorkflowNodeByType(
+        nodeType,
+        nodePosition,
+        nodeJSON ?? ({} as WorkflowNodeJSON),
+        containerNode?.id
+      );
 
-    // wait for node render - 等待节点渲染
-    await delay(20);
+      // wait for node render - 等待节点渲染
+      await delay(20);
 
-    // build connection line - 构建连接线
-    WorkflowNodePanelUtils.buildLine({
-      fromPort: port,
-      node,
-      linesManager,
-    });
-  }, []);
+      // build connection line - 构建连接线
+      WorkflowNodePanelUtils.buildLine({
+        fromPort: port,
+        node,
+        linesManager,
+      });
+    },
+    [singleSelectNodePanel]
+  );
 
   return onPortClick;
 };

+ 1 - 0
packages/plugins/free-node-panel-plugin/src/index.ts

@@ -11,5 +11,6 @@ export type {
   NodePanelRender,
   NodePanelLayerOptions as NodePanelServiceOptions,
   NodePanelPluginOptions,
+  CallNodePanelParams,
 } from './type';
 export { type IWorkflowNodePanelUtils, WorkflowNodePanelUtils } from './utils';