Просмотр исходного кода

refactor(free-layout): line and port validate (#570)

* refactor(free-layout): line and port validate

* fix(free-layout): line prePort validate
xiamidaxia 5 месяцев назад
Родитель
Сommit
51df6f87bf

+ 20 - 4
packages/canvas-engine/free-layout-core/src/entities/workflow-line-entity.ts

@@ -157,6 +157,14 @@ export class WorkflowLineEntity extends Entity<WorkflowLineEntityOpts> {
     if (opts.drawingTo) {
     if (opts.drawingTo) {
       this.isDrawing = true;
       this.isDrawing = true;
     }
     }
+    this.onEntityChange(() => {
+      this.fromPort?.validate();
+      this.toPort?.validate();
+    });
+    this.onDispose(() => {
+      this.fromPort?.validate();
+      this.toPort?.validate();
+    });
     // this.onDispose(() => {
     // this.onDispose(() => {
     // this._infoDispose.dispose();
     // this._infoDispose.dispose();
     // });
     // });
@@ -231,6 +239,7 @@ export class WorkflowLineEntity extends Entity<WorkflowLineEntityOpts> {
     if (this.toPort === toPort) {
     if (this.toPort === toPort) {
       return;
       return;
     }
     }
+    const prePort = this.toPort;
     if (
     if (
       toPort &&
       toPort &&
       toPort.portType === 'input' &&
       toPort.portType === 'input' &&
@@ -247,6 +256,12 @@ export class WorkflowLineEntity extends Entity<WorkflowLineEntityOpts> {
       this.info.to = undefined;
       this.info.to = undefined;
       this.info.toPort = '';
       this.info.toPort = '';
     }
     }
+    /**
+     * 移动到端口又快速移出,需要更新 prePort 的状态
+     */
+    if (prePort) {
+      prePort.validate();
+    }
     this.fireChange();
     this.fireChange();
   }
   }
 
 
@@ -383,13 +398,14 @@ export class WorkflowLineEntity extends Entity<WorkflowLineEntityOpts> {
 
 
   // 校验连线是否为错误态
   // 校验连线是否为错误态
   validate() {
   validate() {
-    const { fromPort, toPort } = this;
     this.validateSelf();
     this.validateSelf();
-    fromPort?.validate();
-    toPort?.validate();
   }
   }
 
 
-  validateSelf() {
+  /**
+   * use `validate` instead
+   * @deprecated
+   */
+  protected validateSelf() {
     const { fromPort, toPort } = this;
     const { fromPort, toPort } = this;
 
 
     if (fromPort) {
     if (fromPort) {

+ 4 - 5
packages/canvas-engine/free-layout-core/src/entities/workflow-port-entity.ts

@@ -107,8 +107,10 @@ export class WorkflowPortEntity extends Entity<WorkflowPortEntityOpts> {
 
 
   // 设置连线的错误态,外部应使用 validate 进行更新
   // 设置连线的错误态,外部应使用 validate 进行更新
   set hasError(hasError: boolean) {
   set hasError(hasError: boolean) {
-    this._hasError = hasError;
-    this._onErrorChangedEmitter.fire();
+    if (hasError !== this._hasError) {
+      this._hasError = hasError;
+      this._onErrorChangedEmitter.fire();
+    }
   }
   }
 
 
   validate() {
   validate() {
@@ -119,9 +121,6 @@ export class WorkflowPortEntity extends Entity<WorkflowPortEntityOpts> {
         return false;
         return false;
       }
       }
 
 
-      // 保证 hasError 最新
-      line.validateSelf();
-
       return line.hasError;
       return line.hasError;
     });
     });
     // 如果没有连线错误,需校验端口自身错误
     // 如果没有连线错误,需校验端口自身错误

+ 4 - 0
packages/canvas-engine/free-layout-core/src/entity-datas/workflow-node-lines-data.ts

@@ -53,6 +53,10 @@ export class WorkflowNodeLinesData extends EntityData<WorkflowNodeLines> {
     return this.data.outputLines;
     return this.data.outputLines;
   }
   }
 
 
+  get allLines(): WorkflowLineEntity[] {
+    return this.data.inputLines.concat(this.data.outputLines);
+  }
+
   /**
   /**
    * 输入节点
    * 输入节点
    */
    */

+ 16 - 17
packages/canvas-engine/free-layout-core/src/entity-datas/workflow-node-ports-data.ts

@@ -4,9 +4,9 @@
  */
  */
 
 
 import { isEqual } from 'lodash-es';
 import { isEqual } from 'lodash-es';
+import { type IPoint } from '@flowgram.ai/utils';
 import { FlowNodeRenderData } from '@flowgram.ai/document';
 import { FlowNodeRenderData } from '@flowgram.ai/document';
 import { EntityData, SizeData } from '@flowgram.ai/core';
 import { EntityData, SizeData } from '@flowgram.ai/core';
-import { type IPoint } from '@flowgram.ai/utils';
 
 
 import { type WorkflowPortType, getPortEntityId } from '../utils/statics';
 import { type WorkflowPortType, getPortEntityId } from '../utils/statics';
 import { type WorkflowNodeMeta } from '../typings';
 import { type WorkflowNodeMeta } from '../typings';
@@ -49,11 +49,11 @@ export class WorkflowNodePortsData extends EntityData {
           if (entity.getData!(SizeData).width && entity.getData!(SizeData).height) {
           if (entity.getData!(SizeData).width && entity.getData!(SizeData).height) {
             this.updateDynamicPorts();
             this.updateDynamicPorts();
           }
           }
-        }),
+        })
       );
       );
     }
     }
     this.onDispose(() => {
     this.onDispose(() => {
-      this.allPorts.forEach(port => port.dispose());
+      this.allPorts.forEach((port) => port.dispose());
     });
     });
   }
   }
 
 
@@ -84,11 +84,11 @@ export class WorkflowNodePortsData extends EntityData {
     const dynamicPorts: WorkflowPorts = [];
     const dynamicPorts: WorkflowPorts = [];
     if (elements.length > 0) {
     if (elements.length > 0) {
       dynamicPorts.push(
       dynamicPorts.push(
-        ...Array.from(elements).map(element => ({
+        ...Array.from(elements).map((element) => ({
           portID: element.getAttribute('data-port-id')!,
           portID: element.getAttribute('data-port-id')!,
           type: element.getAttribute('data-port-type')! as WorkflowPortType,
           type: element.getAttribute('data-port-type')! as WorkflowPortType,
           targetElement: element,
           targetElement: element,
-        })),
+        }))
       );
       );
     }
     }
     this.updatePorts(staticPorts.concat(dynamicPorts));
     this.updatePorts(staticPorts.concat(dynamicPorts));
@@ -99,7 +99,7 @@ export class WorkflowNodePortsData extends EntityData {
    */
    */
   public getPortEntityByKey(
   public getPortEntityByKey(
     portType: WorkflowPortType,
     portType: WorkflowPortType,
-    portKey?: string | number,
+    portKey?: string | number
   ): WorkflowPortEntity {
   ): WorkflowPortEntity {
     const entity = this.getOrCreatePortEntity({
     const entity = this.getOrCreatePortEntity({
       type: portType,
       type: portType,
@@ -113,13 +113,13 @@ export class WorkflowNodePortsData extends EntityData {
    */
    */
   public updatePorts(ports: WorkflowPorts): void {
   public updatePorts(ports: WorkflowPorts): void {
     if (!isEqual(this._prePorts, ports)) {
     if (!isEqual(this._prePorts, ports)) {
-      const portKeys = ports.map(port => this.getPortId(port.type, port.portID));
-      this._portIDSet.forEach(portId => {
+      const portKeys = ports.map((port) => this.getPortId(port.type, port.portID));
+      this._portIDSet.forEach((portId) => {
         if (!portKeys.includes(portId)) {
         if (!portKeys.includes(portId)) {
           this.getPortEntity(portId)?.dispose();
           this.getPortEntity(portId)?.dispose();
         }
         }
       });
       });
-      ports.forEach(port => this.updatePortEntity(port));
+      ports.forEach((port) => this.updatePortEntity(port));
       this._prePorts = ports;
       this._prePorts = ports;
       this.fireChange();
       this.fireChange();
     }
     }
@@ -128,11 +128,10 @@ export class WorkflowNodePortsData extends EntityData {
     // 原因:假设有这样的连线:dynamic port → end 节点。
     // 原因:假设有这样的连线:dynamic port → end 节点。
     // line.validate 时,line.fromPort 可能为 undefined(未创建实体),导致 end 节点上的 port 未正确校验
     // line.validate 时,line.fromPort 可能为 undefined(未创建实体),导致 end 节点上的 port 未正确校验
     // 所以需要在所有 port entities 准备完成后,通过再次调用 line.validate 来触发连线另一端的 port 更新
     // 所以需要在所有 port entities 准备完成后,通过再次调用 line.validate 来触发连线另一端的 port 更新
-    this.allPorts.forEach(port => {
-      port.allLines.forEach(line => {
+    this.allPorts.forEach((port) => {
+      port.allLines.forEach((line) => {
         line.validate();
         line.validate();
       });
       });
-      port.validate();
     });
     });
   }
   }
 
 
@@ -141,7 +140,7 @@ export class WorkflowNodePortsData extends EntityData {
    */
    */
   public get allPorts(): WorkflowPortEntity[] {
   public get allPorts(): WorkflowPortEntity[] {
     return Array.from(this._portIDSet)
     return Array.from(this._portIDSet)
-      .map(portId => this.getPortEntity(portId)!)
+      .map((portId) => this.getPortEntity(portId)!)
       .filter(Boolean); // dispose 时,会获取不到 port
       .filter(Boolean); // dispose 时,会获取不到 port
   }
   }
 
 
@@ -149,28 +148,28 @@ export class WorkflowNodePortsData extends EntityData {
    * 获取输入点位
    * 获取输入点位
    */
    */
   public get inputPorts(): WorkflowPortEntity[] {
   public get inputPorts(): WorkflowPortEntity[] {
-    return this.allPorts.filter(port => port.portType === 'input');
+    return this.allPorts.filter((port) => port.portType === 'input');
   }
   }
 
 
   /**
   /**
    * 获取输出点位
    * 获取输出点位
    */
    */
   public get outputPorts(): WorkflowPortEntity[] {
   public get outputPorts(): WorkflowPortEntity[] {
-    return this.allPorts.filter(port => port.portType === 'output');
+    return this.allPorts.filter((port) => port.portType === 'output');
   }
   }
 
 
   /**
   /**
    * 获取输入点位置
    * 获取输入点位置
    */
    */
   public get inputPoints(): IPoint[] {
   public get inputPoints(): IPoint[] {
-    return this.inputPorts.map(port => port.point);
+    return this.inputPorts.map((port) => port.point);
   }
   }
 
 
   /**
   /**
    * 获取输出点位置
    * 获取输出点位置
    */
    */
   public get outputPoints(): IPoint[] {
   public get outputPoints(): IPoint[] {
-    return this.inputPorts.map(port => port.point);
+    return this.inputPorts.map((port) => port.point);
   }
   }
 
 
   /**
   /**

+ 0 - 2
packages/canvas-engine/free-layout-core/src/workflow-lines-manager.ts

@@ -201,8 +201,6 @@ export class WorkflowLinesManager {
       }
       }
       fromNode.removeLine(line);
       fromNode.removeLine(line);
       toNode?.removeLine(line);
       toNode?.removeLine(line);
-      // 连线销毁时检验 连线错误态 & 端口错误态
-      line.validate();
     });
     });
     line.onDispose(() => {
     line.onDispose(() => {
       if (available) {
       if (available) {