From e7bfa884c454b0c75893c077e348c78d940cc386 Mon Sep 17 00:00:00 2001 From: everbrez Date: Sat, 13 Jan 2024 13:39:21 +0800 Subject: [PATCH 1/3] feat: update StateOperator & ConstStateOperator --- .eslintrc.js | 1 + .../src/Diagrams/Nodes/Node/Node.module.less | 7 + .../Nodes/Node/components/NodePorts/index.tsx | 52 ++--- .../flow/src/Diagrams/Nodes/Node/index.tsx | 53 ++++- .../flow/src/Diagrams/Nodes/NodeTypeEnum.ts | 2 - .../Nodes/StateNode/StateNode.module.less | 10 - .../src/Diagrams/Nodes/StateNode/index.tsx | 32 --- packages/flow/src/Diagrams/Nodes/index.ts | 2 - .../flow/src/Diagrams/Nodes/types/index.ts | 16 -- .../Operators/ConstStateOperator/index.tsx | 49 ---- .../flow/src/Diagrams/Operators/Operator.tsx | 10 +- .../StateOperator/ConstStateOperator.tsx | 51 ++++ .../Operators/StateOperator/StateOperator.tsx | 217 ++++++++++++++++++ .../Diagrams/Operators/StateOperator/index.ts | 2 + .../Operators/StateOperator/index.tsx | 187 --------------- packages/flow/src/Diagrams/Operators/index.ts | 7 +- .../src/Diagrams/Operators/types/index.ts | 33 ++- .../src/Diagrams/Panels/FlowDiagram/index.tsx | 2 - 18 files changed, 389 insertions(+), 344 deletions(-) delete mode 100644 packages/flow/src/Diagrams/Nodes/StateNode/StateNode.module.less delete mode 100644 packages/flow/src/Diagrams/Nodes/StateNode/index.tsx delete mode 100644 packages/flow/src/Diagrams/Operators/ConstStateOperator/index.tsx create mode 100644 packages/flow/src/Diagrams/Operators/StateOperator/ConstStateOperator.tsx create mode 100644 packages/flow/src/Diagrams/Operators/StateOperator/StateOperator.tsx create mode 100644 packages/flow/src/Diagrams/Operators/StateOperator/index.ts delete mode 100644 packages/flow/src/Diagrams/Operators/StateOperator/index.tsx diff --git a/.eslintrc.js b/.eslintrc.js index b07c449..7b186a5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -53,5 +53,6 @@ module.exports = { '@typescript-eslint/no-floating-promises': 'off', 'generator-star-spacing': 'off', '@typescript-eslint/brace-style': 'off', + 'multiline-ternary': 'off', } } diff --git a/packages/flow/src/Diagrams/Nodes/Node/Node.module.less b/packages/flow/src/Diagrams/Nodes/Node/Node.module.less index 60868aa..c5e4494 100644 --- a/packages/flow/src/Diagrams/Nodes/Node/Node.module.less +++ b/packages/flow/src/Diagrams/Nodes/Node/Node.module.less @@ -46,4 +46,11 @@ .node__operator-description { font-size: 10px; +} + +.value-container { + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } \ No newline at end of file diff --git a/packages/flow/src/Diagrams/Nodes/Node/components/NodePorts/index.tsx b/packages/flow/src/Diagrams/Nodes/Node/components/NodePorts/index.tsx index d815778..874eb47 100644 --- a/packages/flow/src/Diagrams/Nodes/Node/components/NodePorts/index.tsx +++ b/packages/flow/src/Diagrams/Nodes/Node/components/NodePorts/index.tsx @@ -10,6 +10,30 @@ export function NodePorts(props: { node: Partial> }) { const { updateNode } = useDiagramsActions(); const operator = getOperatorFromNode(node); + function renderSinglePort(port: EndPoint) { + if (port.type !== 'source' && port.type !== 'target') { + return
unknown type: {port.type}
; + } + + return ( +
+
+ {port.label || port.variableName} +
+ +
+ ); + } + if (!endPointOptions?.endPointList?.length || !operator) { return null; } @@ -27,31 +51,7 @@ export function NodePorts(props: { node: Partial> }) {
{item.label}
{item.children?.map((port) => { - if (port.type !== 'source' && port.type !== 'target') { - return
unknown type: {port.type}
; - } - - return ( -
-
- {port.label || port.variableName} -
- -
- ); + return renderSinglePort(port); })}
{item.allowAddAndRemoveChildren && ( @@ -75,7 +75,7 @@ export function NodePorts(props: { node: Partial> }) { ); } else { - return null; + return renderSinglePort(item); } })} diff --git a/packages/flow/src/Diagrams/Nodes/Node/index.tsx b/packages/flow/src/Diagrams/Nodes/Node/index.tsx index a7d6bec..0f2de6b 100644 --- a/packages/flow/src/Diagrams/Nodes/Node/index.tsx +++ b/packages/flow/src/Diagrams/Nodes/Node/index.tsx @@ -5,12 +5,56 @@ import css from './Node.module.less'; import { type IMetaOperatorData } from '../../Operators/types'; import { NodePorts } from './components/NodePorts'; import { useDiagramsHookOption } from '../../State/DiagramsProvider'; +import { message } from 'antd'; + +export interface INodeProps { + showValue?: boolean; + getBriefValue?: () => { value: string; hasDetail?: boolean }; + getDetailValue?: () => string; +} export function Node(props: NodeProps) { const operator = getOperatorFromNode(props); const { currentStateRef, actionsRef } = useDiagramsHookOption(); const { selected, data } = props; + const nodeOptions: INodeProps | undefined = operator?.getNodeProps?.(props); + + function renderValueSection() { + if (!nodeOptions?.showValue) { + return null; + } + + const briefValue = nodeOptions?.getBriefValue?.(); + + if (!briefValue) { + return null; + } + + return ( +
{ + if (briefValue.hasDetail) { + message.info(nodeOptions?.getDetailValue?.() || ''); + } + }} + > + {briefValue.value} +
+ ); + } + + const valueSection = renderValueSection(); + + const headerInfo = [ + operator?.description && ( +
+ {operator?.description} +
+ ), + valueSection &&
{valueSection}
, + ].filter(Boolean); return (
) { }); }} > - {operator?.description && ( + {headerInfo?.length ? (
-
- {operator?.description} -
+ {headerInfo} {/*
{data.label}
*/} - {/*
{title}
*/}
- )} + ) : null}
diff --git a/packages/flow/src/Diagrams/Nodes/NodeTypeEnum.ts b/packages/flow/src/Diagrams/Nodes/NodeTypeEnum.ts index a4c218a..51b05c5 100644 --- a/packages/flow/src/Diagrams/Nodes/NodeTypeEnum.ts +++ b/packages/flow/src/Diagrams/Nodes/NodeTypeEnum.ts @@ -1,6 +1,4 @@ export enum NodeTypeEnum { - /** 状态节点 */ - StateNode = 'StateNode', /** 组合节点 */ CompositionNode = 'CompositionNode', /** 流操作 */ diff --git a/packages/flow/src/Diagrams/Nodes/StateNode/StateNode.module.less b/packages/flow/src/Diagrams/Nodes/StateNode/StateNode.module.less deleted file mode 100644 index f2a6948..0000000 --- a/packages/flow/src/Diagrams/Nodes/StateNode/StateNode.module.less +++ /dev/null @@ -1,10 +0,0 @@ -.state-node__container { - --color-node-theme: #0079FF; -} - -.value-container { - text-align: center; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} \ No newline at end of file diff --git a/packages/flow/src/Diagrams/Nodes/StateNode/index.tsx b/packages/flow/src/Diagrams/Nodes/StateNode/index.tsx deleted file mode 100644 index 0d9df14..0000000 --- a/packages/flow/src/Diagrams/Nodes/StateNode/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { type NodeProps } from 'reactflow'; -import { BaseNode } from '../components/BaseNode'; -import { type IStateNodeData, StateNodeValueTypeEnum } from '../types'; -import css from './StateNode.module.less'; -import { message } from 'antd'; - -export function StateNode(props: NodeProps) { - const { - data: { value, valueType }, - } = props; - - return ( - { - if (valueType === StateNodeValueTypeEnum.Object) { - message.info(value); - } - }} - > - {valueType === StateNodeValueTypeEnum.Object - ? 'Object(click to view)' - : JSON.stringify(value)} - - } - {...props} - className={css['state-node__container']} - /> - ); -} diff --git a/packages/flow/src/Diagrams/Nodes/index.ts b/packages/flow/src/Diagrams/Nodes/index.ts index 41ba402..ee78743 100644 --- a/packages/flow/src/Diagrams/Nodes/index.ts +++ b/packages/flow/src/Diagrams/Nodes/index.ts @@ -1,4 +1,3 @@ -import { StateNode } from './StateNode'; import { StreamOperatorNode } from './StreamOperatorNode'; import { ContainerNode } from './ContainerNode'; import { DoNode } from './DoNode'; @@ -6,7 +5,6 @@ import { Node } from './Node'; import { NodeTypeEnum } from './NodeTypeEnum'; export const nodeTypes: Record = { - [NodeTypeEnum.StateNode]: StateNode, [NodeTypeEnum.StreamOperatorNode]: StreamOperatorNode, [NodeTypeEnum.ContainerNode]: ContainerNode, [NodeTypeEnum.DoNode]: DoNode, diff --git a/packages/flow/src/Diagrams/Nodes/types/index.ts b/packages/flow/src/Diagrams/Nodes/types/index.ts index edfbd91..4bb07b4 100644 --- a/packages/flow/src/Diagrams/Nodes/types/index.ts +++ b/packages/flow/src/Diagrams/Nodes/types/index.ts @@ -25,22 +25,6 @@ export interface IBaseNodeData { targetPorts: NodePort[]; } -export enum StateNodeValueTypeEnum { - String = 'string', - Number = 'number', - Boolean = 'boolean', - Object = 'object', -} - -export type IStateNodeData = IBaseNodeData & { - valueType: StateNodeValueTypeEnum; - value: string | number | boolean | undefined; -}; - export type IStreamOperatorNodeData = IBaseNodeData & { allowAddTargetPort?: boolean; }; -export enum StateNodePortTypeEnum { - State = 'State', - UpdateHanlder = 'UpdateHanlder', -} diff --git a/packages/flow/src/Diagrams/Operators/ConstStateOperator/index.tsx b/packages/flow/src/Diagrams/Operators/ConstStateOperator/index.tsx deleted file mode 100644 index fb51f5e..0000000 --- a/packages/flow/src/Diagrams/Operators/ConstStateOperator/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { - StateNodePortTypeEnum, - NodePort, - type IStateNodeData, -} from '../../Nodes/types'; -import { type IGenerationOption } from '../../Compiler/graph'; -import { EosOperatorsSymbol } from '../../Compiler/runtime'; -import { StateOperator } from '../StateOperator'; - -export class ConstStateOperator extends StateOperator { - constructor(data?: Partial) { - super(); - - // init ports - this.data = { - ...this.data, - sourcePorts: [ - new NodePort({ - label: 'data', - type: StateNodePortTypeEnum.State, - }), - ], - targetPorts: [], - operatorType: 'ConstStateOperator', - operatorName: 'ConstStateOperator', - ...data?.data, - } as IStateNodeData; - } - - static generateBlockDeclarations?( - options: IGenerationOption, - ): string[] { - const { node } = options; - - return [ - `const ${ConstStateOperator.getStateSymbol( - options, - )} = new ${EosOperatorsSymbol}.constValue(${JSON.stringify( - node.data.value, - )})`, - ]; - } - - static generateBlockRelation?( - options: IGenerationOption, - ): string[] { - return []; - } -} diff --git a/packages/flow/src/Diagrams/Operators/Operator.tsx b/packages/flow/src/Diagrams/Operators/Operator.tsx index 4943c44..1b0ac29 100644 --- a/packages/flow/src/Diagrams/Operators/Operator.tsx +++ b/packages/flow/src/Diagrams/Operators/Operator.tsx @@ -1,4 +1,4 @@ -import { type Node } from 'reactflow'; +import { type NodeProps, type Node } from 'reactflow'; import { getRandomId } from '../utils'; import { type IBaseNodeData, NodePort } from '../Nodes/types'; import { @@ -115,8 +115,8 @@ export abstract class MetaOperator< } // ============ START: Operator Meta Data(static) ============= // - abstract isUnique?: boolean; - abstract nodeColor?: string; + isUnique?: boolean; + nodeColor?: string; description?: string; constructor(defaultOperatorData: IMetaOperatorData) { @@ -236,5 +236,9 @@ export abstract class MetaOperator< ); } + // ============ START: Node Render Relative ============= // + getNodeProps(currentNode: NodeProps): Record { + return {}; + } } diff --git a/packages/flow/src/Diagrams/Operators/StateOperator/ConstStateOperator.tsx b/packages/flow/src/Diagrams/Operators/StateOperator/ConstStateOperator.tsx new file mode 100644 index 0000000..7d97ec0 --- /dev/null +++ b/packages/flow/src/Diagrams/Operators/StateOperator/ConstStateOperator.tsx @@ -0,0 +1,51 @@ +import { type IGenerationOption } from '../../Compiler/graph'; +import { EosOperatorsSymbol } from '../../Compiler/runtime'; +import { StateOperator } from '.'; +import { type MetaOperator } from '../Operator'; +import { EndPoint, type IStateOperatorData } from '../types'; +import { type Node } from 'reactflow'; + +export class ConstStateOperator extends StateOperator implements MetaOperator { + constructor() { + super(); + this.defaultOperatorData.operatorName = 'ConstStateOperator'; + this.defaultOperatorData.operatorType = 'ConstStateOperator'; + } + + create(): Node>> { + const newNode = super.create(); + const node = this.updateData(newNode, { + endPointOptions: { + endPointList: [ + new EndPoint({ + type: 'source', + label: 'data', + hint: 'data', + }), + ], + }, + }); + + return node; + } + + generateBlockDeclarations( + options: IGenerationOption, + ): string[] { + const { node } = options; + + return [ + `const ${super.getStateSymbol( + options, + )} = new ${EosOperatorsSymbol}.constValue(${JSON.stringify( + node.data.value, + )})`, + ]; + } + + generateBlockRelation( + options: IGenerationOption, + ): string[] { + return []; + } +} diff --git a/packages/flow/src/Diagrams/Operators/StateOperator/StateOperator.tsx b/packages/flow/src/Diagrams/Operators/StateOperator/StateOperator.tsx new file mode 100644 index 0000000..c94fd59 --- /dev/null +++ b/packages/flow/src/Diagrams/Operators/StateOperator/StateOperator.tsx @@ -0,0 +1,217 @@ +import { MetaOperator } from '../Operator'; +import { NodeTypeEnum } from '../../Nodes/NodeTypeEnum'; +import { Form, Input, Select, message } from 'antd'; +import { + type IStateOperatorData, + type IAttributeControlOption, + StateOperatorValueTypeEnum, + EndPoint, +} from '../types'; +import { type IGenerationOption } from '../../Compiler/graph'; +import { EosCoreSymbol } from '../../Compiler/runtime'; +import { type NodeProps, type Node } from 'reactflow'; +import { type INodeProps } from '../../Nodes/Node'; + +function getDefaultValue(valueType: StateOperatorValueTypeEnum) { + switch (valueType) { + case StateOperatorValueTypeEnum.Boolean: + return false; + case StateOperatorValueTypeEnum.Number: + return 0; + case StateOperatorValueTypeEnum.String: + return ''; + case StateOperatorValueTypeEnum.Object: + return '{}'; + default: + return undefined; + } +} + +export class StateOperator + extends MetaOperator + implements MetaOperator +{ + nodeColor?: string | undefined = '#0079FF'; + + constructor() { + super({ + operatorName: 'StateOperator', + operatorType: 'StateOperator', + nodeType: NodeTypeEnum.Node, + }); + } + + create(): Node { + return super.create({ + endPointOptions: { + endPointList: [ + new EndPoint({ + type: 'source', + label: 'data', + hint: 'data', + }), + new EndPoint({ + type: 'target', + label: 'update', + hint: 'update', + }), + ], + }, + value: 0, + valueType: StateOperatorValueTypeEnum.Number, + }); + } + + getStateSymbol(options: IGenerationOption) { + const { node, formatVariableName } = options; + return formatVariableName( + node.data.endPointOptions?.endPointList?.find( + (item) => item.type === 'source' && item.hint === 'data', + )?.id || '', + ); + } + + generateBlockDeclarations( + options: IGenerationOption, + ): string[] { + const { node } = options; + + return [ + `const ${this.getStateSymbol( + options, + )} = new ${EosCoreSymbol}.ModelState(${JSON.stringify(node.data.value)})`, + ]; + } + + generateBlockOutput( + options: IGenerationOption, + ): string[] { + return []; + } + + generateBlockRelation( + options: IGenerationOption, + ): string[] { + const { node, formatVariableName, nodeGraph } = options; + + const sources = nodeGraph.findSourceNodes(node.id) || []; + + return [ + ...sources?.map( + (item) => ` + ${formatVariableName( + item.relatedHandleId, + )}.subscribe((val, extraInfo) => { + ${this.getStateSymbol(options)}.update(val, extraInfo.concat('${ + item.nodeId + }')); + });`, + ), + ]; + } + + generateAttributeControl( + options: IAttributeControlOption>, + ): JSX.Element { + const { node, actions } = options; + + return ( +
+ + + + + { + let valueWillUpdate = node.data.value; + const targetValue = event.target.value; + + if (node.data.valueType === StateOperatorValueTypeEnum.Object) { + try { + JSON.parse(targetValue); + valueWillUpdate = targetValue; + } catch (error) { + message.error('JSON parse error, please check again'); + } + } else if ( + node.data.valueType === StateOperatorValueTypeEnum.Boolean + ) { + valueWillUpdate = !!targetValue; + } else if ( + node.data.valueType === StateOperatorValueTypeEnum.Number + ) { + valueWillUpdate = Number(targetValue); + } else { + valueWillUpdate = targetValue; + } + + actions.updateNode(node.id, (item) => + this.updateData(item, { + value: valueWillUpdate, + }), + ); + }} + > + +
+ ); + } + + getNodeProps( + currentNode: NodeProps>>, + ): INodeProps { + const { data } = currentNode; + return { + showValue: true, + getBriefValue() { + return { + value: + data.valueType === StateOperatorValueTypeEnum.Object + ? 'Object(click to view)' + : JSON.stringify(data.value), + hasDetail: data.valueType === StateOperatorValueTypeEnum.Object, + }; + }, + getDetailValue() { + return JSON.stringify(data.value, undefined, 2); + }, + }; + } +} diff --git a/packages/flow/src/Diagrams/Operators/StateOperator/index.ts b/packages/flow/src/Diagrams/Operators/StateOperator/index.ts new file mode 100644 index 0000000..4088208 --- /dev/null +++ b/packages/flow/src/Diagrams/Operators/StateOperator/index.ts @@ -0,0 +1,2 @@ +export { StateOperator } from './StateOperator'; +export { ConstStateOperator } from './ConstStateOperator'; diff --git a/packages/flow/src/Diagrams/Operators/StateOperator/index.tsx b/packages/flow/src/Diagrams/Operators/StateOperator/index.tsx deleted file mode 100644 index f52297b..0000000 --- a/packages/flow/src/Diagrams/Operators/StateOperator/index.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import { Operator } from '../Operator'; -import { NodeTypeEnum } from '../../Nodes/NodeTypeEnum'; -import { - StateNodePortTypeEnum, - NodePort, - type IStateNodeData, - StateNodeValueTypeEnum, -} from '../../Nodes/types'; -import { Form, Input, Select, message } from 'antd'; -import { type IAttributeControlOption } from '../types'; -import { type IGenerationOption } from '../../Compiler/graph'; -import { EosCoreSymbol } from '../../Compiler/runtime'; - -function getDefaultValue(valueType: StateNodeValueTypeEnum) { - switch (valueType) { - case StateNodeValueTypeEnum.Boolean: - return false; - case StateNodeValueTypeEnum.Number: - return 0; - case StateNodeValueTypeEnum.String: - return ''; - case StateNodeValueTypeEnum.Object: - return '{}'; - default: - return undefined; - } -} - -export class StateOperator extends Operator { - constructor(data?: Partial) { - super('StateOperator', { - ...data, - type: NodeTypeEnum.StateNode, - }); - - // init ports - this.data = { - ...this.data, - sourcePorts: [ - new NodePort({ - label: 'data', - type: StateNodePortTypeEnum.State, - }), - ], - targetPorts: [ - new NodePort({ - label: 'update', - type: StateNodePortTypeEnum.UpdateHanlder, - }), - ], - operatorName: 'StateOperator', - value: getDefaultValue(StateNodeValueTypeEnum.Number), - valueType: StateNodeValueTypeEnum.Number, - ...data?.data, - } as IStateNodeData; - } - - static generateAttributeControl( - options: IAttributeControlOption, - ) { - const { node, actions } = options; - - return ( -
- - - - - { - let valueWillUpdate = node.data.value; - const targetValue = event.target.value; - - if (node.data.valueType === StateNodeValueTypeEnum.Object) { - try { - JSON.parse(targetValue); - valueWillUpdate = targetValue; - } catch (error) { - message.error('JSON parse error, please check again'); - } - } else if ( - node.data.valueType === StateNodeValueTypeEnum.Boolean - ) { - valueWillUpdate = !!targetValue; - } else if ( - node.data.valueType === StateNodeValueTypeEnum.Number - ) { - valueWillUpdate = Number(targetValue); - } else { - valueWillUpdate = targetValue; - } - - actions.updateNode(node.id, (item) => ({ - ...item, - data: { - ...item?.data, - value: valueWillUpdate, - }, - })); - }} - > - -
- ); - } - - static getStateSymbol(options: IGenerationOption) { - const { node, formatVariableName } = options; - return formatVariableName( - node.data.sourcePorts.find( - (item) => item.type === StateNodePortTypeEnum.State, - )?.id || '', - ); - } - - static generateBlockDeclarations?( - options: IGenerationOption, - ): string[] { - const { node } = options; - - return [ - `const ${StateOperator.getStateSymbol( - options, - )} = new ${EosCoreSymbol}.ModelState(${JSON.stringify(node.data.value)})`, - ]; - } - - static generateBlockRelation?( - options: IGenerationOption, - ): string[] { - const { node, formatVariableName, nodeGraph } = options; - - const sources = nodeGraph.findSourceNodes(node.id) || []; - - return [ - ...sources?.map( - (item) => ` - ${formatVariableName( - item.relatedHandleId, - )}.subscribe((val, extraInfo) => { - ${StateOperator.getStateSymbol( - options, - )}.update(val, extraInfo.concat('${item.nodeId}')); - });`, - ), - ]; - } -} diff --git a/packages/flow/src/Diagrams/Operators/index.ts b/packages/flow/src/Diagrams/Operators/index.ts index 3871e40..84bf5d0 100644 --- a/packages/flow/src/Diagrams/Operators/index.ts +++ b/packages/flow/src/Diagrams/Operators/index.ts @@ -1,8 +1,7 @@ -import { StateOperator } from './StateOperator'; +import { StateOperator, ConstStateOperator } from './StateOperator'; import { InputOperator } from './InputOperator'; import { OutputOperator } from './OutputOperator'; import { SumOperator } from './SumOperator'; -import { ConstStateOperator } from './ConstStateOperator'; import { type Operator } from './Operator'; import { CustomOperator } from './CustomOperator'; import { WatchOperator } from './WatchOperator'; @@ -13,6 +12,8 @@ import { registerOperator } from './OperatorMap'; registerOperator(new InputOperator()); registerOperator(new OutputOperator()); registerOperator(new CustomOperator()); +registerOperator(new StateOperator()); +registerOperator(new ConstStateOperator()); export { OperatorMap as NextOperatorMap, @@ -22,9 +23,7 @@ export { export const OperatorMap = new Map( Object.entries({ - StateOperator, SumOperator, - ConstStateOperator, WatchOperator, DoOperator, }) as any, diff --git a/packages/flow/src/Diagrams/Operators/types/index.ts b/packages/flow/src/Diagrams/Operators/types/index.ts index b64f1fb..e372132 100644 --- a/packages/flow/src/Diagrams/Operators/types/index.ts +++ b/packages/flow/src/Diagrams/Operators/types/index.ts @@ -61,7 +61,9 @@ export class EndPoint { type IEndPointOption = EndPoint; -export interface IMetaOperatorData { +export interface IMetaOperatorData< + NodeOptions extends Record = Record, +> { /** operator type, unique specifier */ operatorType: string; /** operator name, label for user */ @@ -69,7 +71,7 @@ export interface IMetaOperatorData { /** node type for render */ nodeType: NodeTypeEnum; /** options for rendering node */ - nodeOptions?: Record; + nodeOptions?: NodeOptions; /** custom label/name for user */ nodeLabel?: string; /** description for node writtern by user */ @@ -81,14 +83,35 @@ export interface IMetaOperatorData { }; } -export interface IInputOperatorData extends IMetaOperatorData { +export interface IInputOperatorData< + NodeOptions extends Record = Record, +> extends IMetaOperatorData { // noop to add } -export interface IOutputOperatorData extends IMetaOperatorData { +export interface IOutputOperatorData< + NodeOptions extends Record = Record, +> extends IMetaOperatorData { // noop to add } -export interface ICustomOperatorData extends IMetaOperatorData { +export interface ICustomOperatorData< + NodeOptions extends Record = Record, +> extends IMetaOperatorData { layerId: string; } + +export enum StateOperatorValueTypeEnum { + String = 'string', + Number = 'number', + Boolean = 'boolean', + Object = 'object', +} + +export interface IStateOperatorData< + NodeOptions extends Record = Record, +> extends IMetaOperatorData { + layerId: string; + valueType: StateOperatorValueTypeEnum; + value: string | number | boolean | undefined; +} diff --git a/packages/flow/src/Diagrams/Panels/FlowDiagram/index.tsx b/packages/flow/src/Diagrams/Panels/FlowDiagram/index.tsx index 8b51300..0fd5002 100644 --- a/packages/flow/src/Diagrams/Panels/FlowDiagram/index.tsx +++ b/packages/flow/src/Diagrams/Panels/FlowDiagram/index.tsx @@ -40,8 +40,6 @@ const nodeColor = (node: Node) => { } switch (node.type) { - case NodeTypeEnum.StateNode: - return '#0079FF'; case NodeTypeEnum.StreamOperatorNode: return '#FF0060'; case NodeTypeEnum.ContainerNode: From d151e42bad492d48b89d8b822ff7c2b1918f46b2 Mon Sep 17 00:00:00 2001 From: everbrez Date: Sat, 13 Jan 2024 14:38:18 +0800 Subject: [PATCH 2/3] feat: switch all to meta operator based operator --- packages/flow/src/Diagrams/Compiler/graph.ts | 25 +- .../ContainerNode/ContainerNode.module.less | 3 - .../Diagrams/Nodes/ContainerNode/index.tsx | 19 -- .../flow/src/Diagrams/Nodes/DoNode/index.tsx | 28 +- .../flow/src/Diagrams/Nodes/Node/index.tsx | 10 +- .../flow/src/Diagrams/Nodes/NodeTypeEnum.ts | 13 - .../StreamOperatorNode.module.less | 3 - .../Nodes/StreamOperatorNode/index.tsx | 34 -- .../components/BaseNode/BaseNode.module.less | 301 ------------------ .../Nodes/components/BaseNode/PortList.tsx | 118 ------- .../Nodes/components/BaseNode/index.tsx | 81 ----- packages/flow/src/Diagrams/Nodes/index.ts | 6 - .../flow/src/Diagrams/Nodes/types/index.ts | 30 -- .../Diagrams/Operators/DoOperator/index.tsx | 54 ---- .../flow/src/Diagrams/Operators/Operator.tsx | 90 ------ .../Operators/OutputOperator/index.tsx | 8 +- .../Diagrams/Operators/SumOperator/index.tsx | 95 +++--- .../Operators/WatchOperator/index.tsx | 82 ----- packages/flow/src/Diagrams/Operators/index.ts | 14 +- .../src/Diagrams/Operators/types/index.ts | 21 +- .../Diagrams/Panels/AttributePanel/index.tsx | 12 +- .../src/Diagrams/Panels/FlowDiagram/index.tsx | 84 +---- .../Diagrams/Panels/OperatorPanel/index.tsx | 16 +- 23 files changed, 112 insertions(+), 1035 deletions(-) delete mode 100644 packages/flow/src/Diagrams/Nodes/ContainerNode/ContainerNode.module.less delete mode 100644 packages/flow/src/Diagrams/Nodes/ContainerNode/index.tsx delete mode 100644 packages/flow/src/Diagrams/Nodes/StreamOperatorNode/StreamOperatorNode.module.less delete mode 100644 packages/flow/src/Diagrams/Nodes/StreamOperatorNode/index.tsx delete mode 100644 packages/flow/src/Diagrams/Nodes/components/BaseNode/BaseNode.module.less delete mode 100644 packages/flow/src/Diagrams/Nodes/components/BaseNode/PortList.tsx delete mode 100644 packages/flow/src/Diagrams/Nodes/components/BaseNode/index.tsx delete mode 100644 packages/flow/src/Diagrams/Nodes/types/index.ts delete mode 100644 packages/flow/src/Diagrams/Operators/DoOperator/index.tsx delete mode 100644 packages/flow/src/Diagrams/Operators/WatchOperator/index.tsx diff --git a/packages/flow/src/Diagrams/Compiler/graph.ts b/packages/flow/src/Diagrams/Compiler/graph.ts index 17f07e2..65dcff3 100644 --- a/packages/flow/src/Diagrams/Compiler/graph.ts +++ b/packages/flow/src/Diagrams/Compiler/graph.ts @@ -1,6 +1,6 @@ import { type Edge, type Node } from 'reactflow'; -import { OperatorMap, getOperatorFromNode } from '../Operators'; -import { type IBaseNodeData } from '../Nodes/types'; +import { getOperatorFromNode } from '../Operators'; +import { type IMetaOperatorData } from '../Operators/types'; import { EosCoreSymbol } from './runtime'; import { type Layer, flatLayer } from '../State/Layer'; import { message } from 'antd'; @@ -168,10 +168,9 @@ function generateBlock( const sortedNode = nodeGraph.getSortedNodes(); const declarations: string[] = sortedNode - .map((node: Node) => { - const Operator = - getOperatorFromNode(node) || OperatorMap.get(node.data.operatorName); - return Operator?.generateBlockDeclarations?.({ + .map((node: Node) => { + const operator = getOperatorFromNode(node); + return operator?.generateBlockDeclarations?.({ node, nodeGraph, formatVariableName, @@ -182,10 +181,9 @@ function generateBlock( .filter((x): x is string => Boolean(x)); const relations: string[] = sortedNode - .map((node: Node) => { - const Operator = - getOperatorFromNode(node) || OperatorMap.get(node.data.operatorName); - return Operator?.generateBlockRelation?.({ + .map((node: Node) => { + const operator = getOperatorFromNode(node); + return operator?.generateBlockRelation?.({ node, nodeGraph, formatVariableName, @@ -196,10 +194,9 @@ function generateBlock( .filter((x): x is string => Boolean(x)); const outputs: string[] = sortedNode - .map((node: Node) => { - const Operator = - getOperatorFromNode(node) || OperatorMap.get(node.data.operatorName); - return Operator?.generateBlockOutput?.({ + .map((node: Node) => { + const operator = getOperatorFromNode(node); + return operator?.generateBlockOutput?.({ node, nodeGraph, formatVariableName, diff --git a/packages/flow/src/Diagrams/Nodes/ContainerNode/ContainerNode.module.less b/packages/flow/src/Diagrams/Nodes/ContainerNode/ContainerNode.module.less deleted file mode 100644 index 667f53a..0000000 --- a/packages/flow/src/Diagrams/Nodes/ContainerNode/ContainerNode.module.less +++ /dev/null @@ -1,3 +0,0 @@ -.container { - --color-node-theme: #FF8080; -} \ No newline at end of file diff --git a/packages/flow/src/Diagrams/Nodes/ContainerNode/index.tsx b/packages/flow/src/Diagrams/Nodes/ContainerNode/index.tsx deleted file mode 100644 index 851f7d0..0000000 --- a/packages/flow/src/Diagrams/Nodes/ContainerNode/index.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { type NodeProps } from 'reactflow'; -import { BaseNode } from '../components/BaseNode'; -import css from './ContainerNode.module.less'; -import { useDiagramsContext } from '../../State/DiagramsProvider'; - -export function ContainerNode(props: NodeProps) { - const { data } = props; - const { setActiveLayerId } = useDiagramsContext(); - - return ( - { - setActiveLayerId(data.layerId); - }} - {...props} - className={css.container} - /> - ); -} diff --git a/packages/flow/src/Diagrams/Nodes/DoNode/index.tsx b/packages/flow/src/Diagrams/Nodes/DoNode/index.tsx index d831937..186e3a3 100644 --- a/packages/flow/src/Diagrams/Nodes/DoNode/index.tsx +++ b/packages/flow/src/Diagrams/Nodes/DoNode/index.tsx @@ -1,31 +1,25 @@ import { type NodeProps } from 'reactflow'; -import { BaseNode } from '../components/BaseNode'; import css from './DoNode.module.less'; import { Button, Modal } from 'antd'; import { useState } from 'react'; import { Editor } from '../../components/Editor'; +/** @deprecated */ export function DoNode(props: NodeProps) { const [visible, setVisible] = useState(false); return ( <> - { - setVisible(true); - }} - > - 点击编辑 - - } - className={css.container} - /> + ) { }); }} > - {headerInfo?.length ? ( -
- {headerInfo} - {/*
{data.label}
*/} -
- ) : null} +
+ {headerInfo} + {/*
{data.label}
*/} +
diff --git a/packages/flow/src/Diagrams/Nodes/NodeTypeEnum.ts b/packages/flow/src/Diagrams/Nodes/NodeTypeEnum.ts index 51b05c5..4608b9f 100644 --- a/packages/flow/src/Diagrams/Nodes/NodeTypeEnum.ts +++ b/packages/flow/src/Diagrams/Nodes/NodeTypeEnum.ts @@ -1,16 +1,3 @@ export enum NodeTypeEnum { - /** 组合节点 */ - CompositionNode = 'CompositionNode', - /** 流操作 */ - StreamOperatorNode = 'StreamOperatorNode', - /** 值操作 */ - ValueOperatorNode = 'ValueOperatorNode', - /** - * 容器 - * @see https://reactflow.dev/learn/layouting/sub-flows#adding-child-nodes - * @see https://reactflow.dev/examples/layout/sub-flows - * */ - ContainerNode = 'ContainerNode', - DoNode = 'DoNode', Node = 'Node', } diff --git a/packages/flow/src/Diagrams/Nodes/StreamOperatorNode/StreamOperatorNode.module.less b/packages/flow/src/Diagrams/Nodes/StreamOperatorNode/StreamOperatorNode.module.less deleted file mode 100644 index d19a23c..0000000 --- a/packages/flow/src/Diagrams/Nodes/StreamOperatorNode/StreamOperatorNode.module.less +++ /dev/null @@ -1,3 +0,0 @@ -.container { - --color-node-theme: #FF0060; -} \ No newline at end of file diff --git a/packages/flow/src/Diagrams/Nodes/StreamOperatorNode/index.tsx b/packages/flow/src/Diagrams/Nodes/StreamOperatorNode/index.tsx deleted file mode 100644 index cc0bd94..0000000 --- a/packages/flow/src/Diagrams/Nodes/StreamOperatorNode/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { type NodeProps, type Node } from 'reactflow'; -import { BaseNode } from '../components/BaseNode'; -import { NodePort, type IStreamOperatorNodeData } from '../types'; -import { useDiagramsActions } from '../../State/DiagramsProvider'; -import css from './StreamOperatorNode.module.less'; - -export function StreamOperatorNode(props: NodeProps) { - const { data, id } = props; - const { updateNode } = useDiagramsActions(); - - return ( - { - updateNode(id, (node: Node) => ({ - ...node, - data: { - ...node.data, - targetPorts: node.data.targetPorts.concat( - new NodePort({ - label: `input-${node.data.targetPorts?.length + 1 || 0}`, - }), - ), - }, - })); - } - : undefined - } - {...props} - className={css.container} - /> - ); -} diff --git a/packages/flow/src/Diagrams/Nodes/components/BaseNode/BaseNode.module.less b/packages/flow/src/Diagrams/Nodes/components/BaseNode/BaseNode.module.less deleted file mode 100644 index e182d9c..0000000 --- a/packages/flow/src/Diagrams/Nodes/components/BaseNode/BaseNode.module.less +++ /dev/null @@ -1,301 +0,0 @@ -.node__container { - --color-bg: #2e2e2e; - --content-padding: 12px; - - display: grid; - - color: #e2e2e2; - font-size: 16px; - gap: 4px; - - min-width: 125px; - max-width: 200px; -} - -.node__operator-name { - font-size: 12px; -} - -.node__content { - min-height: 40px; - - border: 1px solid transparent; - border-radius: 4px; - - background-color: var(--color-bg); - - padding: var(--content-padding) var(--content-padding); - padding-top: calc(var(--content-padding) / 2); - - transition: border-color cubic-bezier(0.215, 0.610, 0.355, 1) .25s; -} - -.is-selected { - .node__content { - border-color: var(--color-node-theme, #9a7844); - } -} - -.node__port-list { - @gap: 8px; - @padding-left: 16px; - --nest-level: 1; - --padding-left: calc(@padding-left * var(--nest-level)); - --last-padding-left: calc(@padding-left * (var(--nest-level, 0) - 1)); - - list-style-type: none; - margin: 0; - padding: 0; - - font-size: 12px; - - display: grid; - gap: @gap; - - >li { - position: relative; - } - - &:not(.is-sub-list) { - margin-top: 16px; - } - - &.is-sub-list { - >li:not(.node__port-children) { - &::before { - content: ''; - position: absolute; - top: -@gap; - bottom: 50%; - - width: @padding-left; - border: 1px solid white; - } - - &::after { - content: ''; - position: absolute; - top: 50%; - bottom: -4px; - width: @padding-left; - border: 1px solid white; - transform: translateY(-2px); - } - - >.node__port-dot { - position: absolute; - top: 50%; - width: 4px; - height: 4px; - border-radius: 50%; - background-color: white; - transform: translateY(-50%); - } - - &.is-last { - &::before { - bottom: 50%; - } - - &::after { - display: none; - } - } - } - - >.node__port-children:not(:last-child) { - &::before { - content: ''; - position: absolute; - top: -@gap; - bottom: -1px; - width: 1px; - background-color: white; - } - } - } - - :global { - .react-flow__handle { - width: 9px; - height: 9px; - } - } - - &.source { - text-align: right; - - :global { - .react-flow__handle { - top: 50%; - right: calc(var(--content-padding) * -1); - transform: translate(50%, -50%); - } - } - - &.is-sub-list { - >li { - &:not(.node__port-children) { - padding-right: var(--padding-left, @padding-left); - } - - &::before { - right: var(--last-padding-left); - border-color: transparent white white transparent; - } - - &::after { - right: var(--last-padding-left); - border-color: transparent white transparent transparent; - } - - >.node__port-dot { - right: var(--padding-left); - } - - &.is-last { - &::before { - border-bottom-right-radius: 4px; - } - } - } - } - - &.is-sub-list { - >.node__port-children:not(:last-child) { - &::before { - right: var(--last-padding-left); - } - } - } - } - - &.target { - text-align: left; - - :global { - .react-flow__handle { - top: 50%; - left: calc(var(--content-padding) * -1); - transform: translate(-50%, -50%); - } - } - - &.is-sub-list { - >li { - &:not(.node__port-children) { - padding-left: var(--padding-left, @padding-left); - } - - &::before { - left: var(--last-padding-left); - border-color: transparent transparent white white; - } - - &::after { - left: var(--last-padding-left); - border-color: transparent transparent transparent white; - } - - >.node__port-dot { - left: var(--padding-left); - } - - &.is-last { - &::before { - border-bottom-left-radius: 4px; - } - } - } - } - - &.is-sub-list { - >.node__port-children:not(:last-child) { - &::before { - left: var(--last-padding-left); - } - } - } - } -} - -.node__port-children:not(:last-child)>.is-sub-list { - margin-bottom: 8px; -} - -.node__title { - padding-bottom: 2px; - margin-bottom: 8px; - border-bottom: 3px solid var(--color-node-theme, #9a7844); -} - -.node__port-expand-trigger { - display: flex; - flex-flow: row nowrap; - align-items: center; - justify-content: center; - - position: absolute; - top: 50%; - - font-size: 10px; - cursor: pointer; - - background-color: var(--color-bg); - - >svg { - transform: rotate(180deg); - transition: transform cubic-bezier(0.215, 0.610, 0.355, 1) 0.6s; - } - - - &.is-children-hidden { - >svg { - transform: rotate(0deg); - } - } - - .target & { - left: calc(var(--padding-left) + 0.5px); - transform: translate(-50%, -50%); - } - - .source & { - right: calc(var(--padding-left) + 0.5px); - transform: translate(50%, -50%); - } -} - -.node__port-expand-line { - position: absolute; - top: calc(50% + 4px); - bottom: -2px; - - .target & { - left: var(--padding-left); - border-left: 1px solid white; - } - - .source & { - right: var(--padding-left); - border-right: 1px solid white; - } -} - -.node__port-label { - padding: 0 6px; -} - -.add-button { - background: none; - border: none; - cursor: pointer; - display: block; - text-align: center; - color: #e2e2e2; - border: 1px #e2e2e2 solid; -} - -.node__operator-description { - font-size: 10px; -} \ No newline at end of file diff --git a/packages/flow/src/Diagrams/Nodes/components/BaseNode/PortList.tsx b/packages/flow/src/Diagrams/Nodes/components/BaseNode/PortList.tsx deleted file mode 100644 index ffbeee1..0000000 --- a/packages/flow/src/Diagrams/Nodes/components/BaseNode/PortList.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import React, { useState } from 'react'; -import classnames from 'classnames'; -import { Handle, type HandleProps, Position } from 'reactflow'; -import { type NodePort } from '../../../Operators/Operator'; -import css from './BaseNode.module.less'; - -export interface PortListProps { - value?: NodePort[]; - type: HandleProps['type']; - nestLevel?: number; - onPortAdd?: () => void; -} - -export const PortList: React.FC = (props) => { - const { value = [], type, nestLevel = 0, onPortAdd } = props; - const [hideChildrenIds, setHideChildren] = useState([]); - - function checkIsHideChildren(id: string) { - return !hideChildrenIds?.includes(id); - } - - function handleToggleHideChildren(id: string) { - return () => { - setHideChildren((hideIds) => { - const hideIdsWillUpdate = [...hideIds]; - if (hideIdsWillUpdate?.includes(id)) { - hideIdsWillUpdate.splice(hideIdsWillUpdate.indexOf(id)); - } else { - hideIdsWillUpdate.push(id); - } - return hideIdsWillUpdate; - }); - }; - } - - return ( -
    - {value.map((port, index) => { - const hasChildren = Boolean(port?.children?.length); - const hideChildren = checkIsHideChildren(port.id); - - return ( - -
  • - {Boolean(nestLevel) && !hasChildren && ( -
    - )} - {hasChildren && ( - <> - {/* TODO: 处理收起时候,链接内容的修改 */} -
    - -
    - {!hideChildren && ( -
    - )} - - )} -
    {port.label}
    - -
  • - {!hideChildren && hasChildren && ( -
  • - -
  • - )} -
    - ); - })} - {onPortAdd && ( -
  • - { - onPortAdd?.(); - }} - > - add port - -
  • - )} -
- ); -}; diff --git a/packages/flow/src/Diagrams/Nodes/components/BaseNode/index.tsx b/packages/flow/src/Diagrams/Nodes/components/BaseNode/index.tsx deleted file mode 100644 index 8ceff77..0000000 --- a/packages/flow/src/Diagrams/Nodes/components/BaseNode/index.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { type PropsWithChildren } from 'react'; -import classnames from 'classnames'; -import { type NodeProps } from 'reactflow'; -import { type IBaseNodeData } from '../../types'; -import { PortList } from './PortList'; -import css from './BaseNode.module.less'; - -export function BaseNode( - props: PropsWithChildren< - NodeProps & { - className?: string; - title?: React.ReactNode; - onSourcePortAdd?: () => void; - onTargetPortAdd?: () => void; - onDoubleClick?: () => void; - description?: string; - onFocus?: () => void; - } - >, -) { - const { - data, - selected, - className, - title, - onSourcePortAdd, - onTargetPortAdd, - onDoubleClick, - description, - onFocus, - } = props; - const operatorName = data?.operatorName; - - const ports = [ - { - type: 'source' as const, - value: data.sourcePorts, - }, - { - type: 'target' as const, - value: data.targetPorts, - }, - ]; - - return ( -
{ - onFocus?.(); - }} - > -
{operatorName}
-
-
-
{description}
-
{data.label}
-
{title}
-
- {ports?.map(({ type, value }) => { - if (!value?.length) { - return null; - } - return ( - - ); - })} -
-
- ); -} diff --git a/packages/flow/src/Diagrams/Nodes/index.ts b/packages/flow/src/Diagrams/Nodes/index.ts index ee78743..b7b575b 100644 --- a/packages/flow/src/Diagrams/Nodes/index.ts +++ b/packages/flow/src/Diagrams/Nodes/index.ts @@ -1,12 +1,6 @@ -import { StreamOperatorNode } from './StreamOperatorNode'; -import { ContainerNode } from './ContainerNode'; -import { DoNode } from './DoNode'; import { Node } from './Node'; import { NodeTypeEnum } from './NodeTypeEnum'; export const nodeTypes: Record = { - [NodeTypeEnum.StreamOperatorNode]: StreamOperatorNode, - [NodeTypeEnum.ContainerNode]: ContainerNode, - [NodeTypeEnum.DoNode]: DoNode, [NodeTypeEnum.Node]: Node, }; diff --git a/packages/flow/src/Diagrams/Nodes/types/index.ts b/packages/flow/src/Diagrams/Nodes/types/index.ts deleted file mode 100644 index 4bb07b4..0000000 --- a/packages/flow/src/Diagrams/Nodes/types/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { v4 as uuid } from 'uuid'; - -export class NodePort { - id: string; - type: string; - label: string = ''; - isConnectable?: boolean; - children?: NodePort[]; - - constructor(data: Partial) { - Object.assign(this, data); - this.id ??= uuid(); - this.type ??= 'unknown port type'; - } -} - -export interface IBaseNodeData { - /** 类型唯一标识 */ - operatorType: string; - /** 可以修改 */ - operatorName: string; - label?: string; - description?: string; - sourcePorts: NodePort[]; - targetPorts: NodePort[]; -} - -export type IStreamOperatorNodeData = IBaseNodeData & { - allowAddTargetPort?: boolean; -}; diff --git a/packages/flow/src/Diagrams/Operators/DoOperator/index.tsx b/packages/flow/src/Diagrams/Operators/DoOperator/index.tsx deleted file mode 100644 index d29ef58..0000000 --- a/packages/flow/src/Diagrams/Operators/DoOperator/index.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Operator } from '../Operator'; -import { NodeTypeEnum } from '../../Nodes/NodeTypeEnum'; -import { type Node } from 'reactflow'; -import { NodePort, type IStreamOperatorNodeData } from '../../Nodes/types'; -import { type IGenerationOption } from '../../Compiler/graph'; -import { type IAttributeControlOption } from '../types'; - -export class DoOperator extends Operator { - constructor(data?: Partial>) { - super('DoOperator', { - ...data, - type: NodeTypeEnum.DoNode, - }); - - // init ports - this.data = { - ...this.data, - sourcePorts: [ - new NodePort({ - label: 'output', - }), - ], - targetPorts: [ - new NodePort({ - label: 'input-1', - }), - new NodePort({ - label: 'input-2', - }), - ], - operatorName: 'DoOperator', - allowAddTargetPort: true, - ...data?.data, - } as IStreamOperatorNodeData; - } - - static generateAttributeControl( - options: IAttributeControlOption, - ) { - return
empty
; - } - - static generateBlockDeclarations?( - options: IGenerationOption, - ): string[] { - return []; - } - - static generateBlockRelation?( - options: IGenerationOption, - ): string[] { - return []; - } -} diff --git a/packages/flow/src/Diagrams/Operators/Operator.tsx b/packages/flow/src/Diagrams/Operators/Operator.tsx index 1b0ac29..c4a769e 100644 --- a/packages/flow/src/Diagrams/Operators/Operator.tsx +++ b/packages/flow/src/Diagrams/Operators/Operator.tsx @@ -1,6 +1,5 @@ import { type NodeProps, type Node } from 'reactflow'; import { getRandomId } from '../utils'; -import { type IBaseNodeData, NodePort } from '../Nodes/types'; import { type IHookOption, type IAttributeControlOption, @@ -9,95 +8,6 @@ import { import { type IGenerationOption } from '../Compiler/graph'; import { pick } from 'lodash'; -export { NodePort }; - -export interface OperatorNodeData extends IBaseNodeData { - operatorType: string; - [key: string]: any; -} - -/** @deprecated 请用 MetaOperator 替代 */ -export class Operator implements Node { - unique?: boolean; - - static generateOperatorIcon?() { - return
{this.name}
; - } - - static generateAttributeControl?( - options: IAttributeControlOption>, - ) { - const { node, actions } = options; - function handleChange(val: string) { - node.data.label = val; - actions.updateNode(node.id, node); - } - return ( - <> - { - handleChange(e.target.value); - }} - /> - - ); - } - - static generateBlockDeclarations?(options: IGenerationOption): string[] { - return []; - } - - static generateBlockRelation?(options: IGenerationOption): string[] { - return []; - } - - static generateBlockOutput?(options: IGenerationOption): string[] { - return []; - } - - static onAfterCreate?(options: IHookOption>) { - // nothing - } - - // 1. should generate the attributes that can modified by user - // 2. should generate the nodes - // 3. should generate the ports in graph - // 4. should generate the funtion which will be used in later code piping - id: Node['id'] = getRandomId(); - position: Node['position'] = { - x: 0, - y: 0, - }; - - type: string = 'OperatorNode'; - data: T = {} as any; - style?: Node['style']; - className?: Node['className']; - targetPosition?: Node['targetPosition']; - sourcePosition?: Node['sourcePosition']; - hidden?: boolean; - draggable?: boolean; - selectable?: boolean; - connectable?: boolean; - - constructor( - operatorType: string = 'Operator', - data?: Partial>>, - ) { - Object.assign(this, { - ...data, - data: { - operatorType, - ...this.data, - ...data?.data, - }, - }); - } -} - export abstract class MetaOperator< T extends IMetaOperatorData = IMetaOperatorData, > { diff --git a/packages/flow/src/Diagrams/Operators/OutputOperator/index.tsx b/packages/flow/src/Diagrams/Operators/OutputOperator/index.tsx index bef302d..783569a 100644 --- a/packages/flow/src/Diagrams/Operators/OutputOperator/index.tsx +++ b/packages/flow/src/Diagrams/Operators/OutputOperator/index.tsx @@ -33,10 +33,10 @@ export class OutputOperator hint: 'state', }, children: [ - // new EndPoint({ - // type: 'target', - // hint: 'state', - // }), + new EndPoint({ + type: 'target', + hint: 'state', + }), ], }), diff --git a/packages/flow/src/Diagrams/Operators/SumOperator/index.tsx b/packages/flow/src/Diagrams/Operators/SumOperator/index.tsx index af884d7..3672e0b 100644 --- a/packages/flow/src/Diagrams/Operators/SumOperator/index.tsx +++ b/packages/flow/src/Diagrams/Operators/SumOperator/index.tsx @@ -1,51 +1,68 @@ -import { Operator } from '../Operator'; +import { MetaOperator } from '../Operator'; import { NodeTypeEnum } from '../../Nodes/NodeTypeEnum'; import { type Node } from 'reactflow'; -import { NodePort, type IStreamOperatorNodeData } from '../../Nodes/types'; import { type IGenerationOption } from '../../Compiler/graph'; -import { type IAttributeControlOption } from '../types'; +import { type ISumOperatorData, EndPoint } from '../types'; import { EosOperatorsSymbol } from '../../Compiler/runtime'; -export class SumOperator extends Operator { - constructor(data?: Partial>) { - super('SumOperator', { - ...data, - type: NodeTypeEnum.StreamOperatorNode, - }); +export class SumOperator + extends MetaOperator + implements MetaOperator +{ + nodeColor?: string | undefined = '#FF0060'; - // init ports - this.data = { - ...this.data, - sourcePorts: [ - new NodePort({ - label: 'output', - }), - ], - targetPorts: [ - new NodePort({ - label: 'input-1', - }), - new NodePort({ - label: 'input-2', - }), - ], + constructor() { + super({ operatorName: 'SumOperator', - allowAddTargetPort: true, - ...data?.data, - } as IStreamOperatorNodeData; + operatorType: 'SumOperator', + nodeType: NodeTypeEnum.Node, + }); } - static generateAttributeControl( - options: IAttributeControlOption, - ) { - return
empty
; + create(): Node>> { + return super.create({ + endPointOptions: { + endPointList: [ + new EndPoint({ + type: 'source', + label: 'output', + hint: 'output', + }), + new EndPoint({ + type: 'group', + allowAddAndRemoveChildren: true, + hint: 'input', + defaultChildData: { + type: 'target', + label: 'input', + hint: 'input', + }, + children: [ + new EndPoint({ + type: 'target', + label: 'input', + hint: 'input', + }), + new EndPoint({ + type: 'target', + label: 'input', + hint: 'input', + }), + ], + }), + ], + }, + }); } - static generateBlockDeclarations?( - options: IGenerationOption, + generateBlockDeclarations( + options: IGenerationOption, ): string[] { const { node, formatVariableName, nodeGraph } = options; - const handleId = node.data.sourcePorts[0].id; + const handleId = + node.data.endPointOptions?.endPointList?.find( + (item) => item.hint === 'output', + )?.id || ''; const sourceIds = nodeGraph.findSourceNodes(node.id)?.map((item) => item.relatedHandleId) || @@ -60,9 +77,13 @@ export class SumOperator extends Operator { ]; } - static generateBlockRelation?( - options: IGenerationOption, + generateBlockRelation( + options: IGenerationOption, ): string[] { return []; } + + generateBlockOutput(options: IGenerationOption): string[] { + return []; + } } diff --git a/packages/flow/src/Diagrams/Operators/WatchOperator/index.tsx b/packages/flow/src/Diagrams/Operators/WatchOperator/index.tsx deleted file mode 100644 index 4d50092..0000000 --- a/packages/flow/src/Diagrams/Operators/WatchOperator/index.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { Operator } from '../Operator'; -import { NodeTypeEnum } from '../../Nodes/NodeTypeEnum'; -import { type Node } from 'reactflow'; -import { NodePort, type IStreamOperatorNodeData } from '../../Nodes/types'; -import { - type ICustomOperatorData, - type IHookOption, - type IAttributeControlOption, -} from '../types'; -import { type IGenerationOption } from '../../Compiler/graph'; -import { Layer, findLayer } from '../../State/Layer'; - -export class WatchOperator extends Operator { - constructor(data?: Partial>) { - super('WatchOperator', { - ...data, - type: NodeTypeEnum.ContainerNode, - }); - - // init ports - this.data = { - ...this.data, - sourcePorts: [ - new NodePort({ - label: 'output', - }), - ], - targetPorts: [ - new NodePort({ - label: 'input-1', - }), - new NodePort({ - label: 'input-2', - }), - ], - operatorName: 'WatchOperator', - allowAddTargetPort: true, - ...data?.data, - } as ICustomOperatorData; - } - - static onAfterCreate(options: IHookOption) { - const { node, actions, currentState } = options; - const { setLayer } = actions; - const { activeLayerId, layer } = currentState; - - const currentActiveLayer = findLayer(layer, activeLayerId); - const newLayer = new Layer(node.data.operatorName); - newLayer.relativeNodeId = node.id; - newLayer.parentLayerId = currentActiveLayer?.id; - node.data.layerId = newLayer.id; - // todo: 设置之后不会马上展示新的 node,需要排查 - setLayer((layer) => { - const currentActiveLayer = findLayer(layer, activeLayerId); - if (currentActiveLayer) { - if (!currentActiveLayer.nodes.find((item) => item.id === node.id)) { - currentActiveLayer.nodes = currentActiveLayer.nodes.concat(node); - } - currentActiveLayer.children.push(newLayer); - } - return { ...layer }; - }); - } - - static generateAttributeControl( - options: IAttributeControlOption, - ) { - return
empty
; - } - - static generateBlockDeclarations?( - options: IGenerationOption, - ): string[] { - return []; - } - - static generateBlockRelation?( - options: IGenerationOption, - ): string[] { - return []; - } -} diff --git a/packages/flow/src/Diagrams/Operators/index.ts b/packages/flow/src/Diagrams/Operators/index.ts index 84bf5d0..4787ee6 100644 --- a/packages/flow/src/Diagrams/Operators/index.ts +++ b/packages/flow/src/Diagrams/Operators/index.ts @@ -2,10 +2,7 @@ import { StateOperator, ConstStateOperator } from './StateOperator'; import { InputOperator } from './InputOperator'; import { OutputOperator } from './OutputOperator'; import { SumOperator } from './SumOperator'; -import { type Operator } from './Operator'; import { CustomOperator } from './CustomOperator'; -import { WatchOperator } from './WatchOperator'; -import { DoOperator } from './DoOperator'; import { registerOperator } from './OperatorMap'; @@ -14,17 +11,10 @@ registerOperator(new OutputOperator()); registerOperator(new CustomOperator()); registerOperator(new StateOperator()); registerOperator(new ConstStateOperator()); +registerOperator(new SumOperator()); export { - OperatorMap as NextOperatorMap, + OperatorMap, getOperatorFromNode, getOperatorFromOperatorType, } from './OperatorMap'; - -export const OperatorMap = new Map( - Object.entries({ - SumOperator, - WatchOperator, - DoOperator, - }) as any, -); diff --git a/packages/flow/src/Diagrams/Operators/types/index.ts b/packages/flow/src/Diagrams/Operators/types/index.ts index e372132..3c86f05 100644 --- a/packages/flow/src/Diagrams/Operators/types/index.ts +++ b/packages/flow/src/Diagrams/Operators/types/index.ts @@ -3,24 +3,24 @@ import { type NodeTypeEnum } from '../../Nodes/NodeTypeEnum'; import { type Node } from 'reactflow'; import { v4 as uuid } from 'uuid'; -type GetOperatorType = T extends Node ? P : any; +type GetOperatorStateType = T extends Node ? P : any; -export interface IAttributeControlOption> { - node: Op; +export interface IAttributeControlOption> { + node: OpNode; actions: Pick< - DiagramsContextType>, + DiagramsContextType>, 'updateEdge' | 'updateNode' | 'setLayer' >; } -export interface IHookOption> { - node: Op; +export interface IHookOption> { + node: OpNode; currentState: Pick< - DiagramsContextType>, + DiagramsContextType>, 'activeLayerId' | 'layer' | 'nodes' | 'edges' >; actions: Pick< - DiagramsContextType>, + DiagramsContextType>, 'updateEdge' | 'updateNode' | 'setLayer' | 'setActiveLayerId' >; } @@ -115,3 +115,8 @@ export interface IStateOperatorData< valueType: StateOperatorValueTypeEnum; value: string | number | boolean | undefined; } +export interface ISumOperatorData< + NodeOptions extends Record = Record, +> extends IMetaOperatorData { + // noop +} diff --git a/packages/flow/src/Diagrams/Panels/AttributePanel/index.tsx b/packages/flow/src/Diagrams/Panels/AttributePanel/index.tsx index afcfb3e..c9767ab 100644 --- a/packages/flow/src/Diagrams/Panels/AttributePanel/index.tsx +++ b/packages/flow/src/Diagrams/Panels/AttributePanel/index.tsx @@ -3,8 +3,7 @@ import { useDiagramsContextSelector, useDiagramsActions, } from '../../State/DiagramsProvider'; -import { OperatorMap, getOperatorFromNode } from '../../Operators'; -import { type Operator } from '../../Operators/Operator'; +import { getOperatorFromNode } from '../../Operators'; export const AttributePanel: React.FC = () => { const nodes = useDiagramsContextSelector((ctx) => ctx.nodes); @@ -13,15 +12,12 @@ export const AttributePanel: React.FC = () => { const selectedElement = selectedElements?.length === 1 ? selectedElements[0] : undefined; - const selectedElementNode = useDiagramsContextSelector( - (ctx) => - ctx.nodes.find((item) => item.id === selectedElement?.id) as Operator, + const selectedElementNode = useDiagramsContextSelector((ctx) => + ctx.nodes.find((item) => item.id === selectedElement?.id), ); const operatorType = selectedElementNode?.data?.operatorType; - // TODO - const operator = - getOperatorFromNode(selectedElementNode) || OperatorMap.get(operatorType); + const operator = getOperatorFromNode(selectedElementNode); const showConfig = !!selectedElement && operatorType; const { updateEdge, updateNode, setLayer } = useDiagramsActions(); diff --git a/packages/flow/src/Diagrams/Panels/FlowDiagram/index.tsx b/packages/flow/src/Diagrams/Panels/FlowDiagram/index.tsx index 0fd5002..1ef6e71 100644 --- a/packages/flow/src/Diagrams/Panels/FlowDiagram/index.tsx +++ b/packages/flow/src/Diagrams/Panels/FlowDiagram/index.tsx @@ -18,18 +18,11 @@ import ReactFlow, { Panel, } from 'reactflow'; import { OPERATOR_TYPE_DATA } from '../OperatorPanel'; -import { - OperatorMap, - NextOperatorMap, - getOperatorFromNode, -} from '../../Operators'; +import { OperatorMap, getOperatorFromNode } from '../../Operators'; import { useDiagramsContext } from '../../State/DiagramsProvider'; import { nodeTypes } from '../../Nodes'; -import { NodeTypeEnum } from '../../Nodes/NodeTypeEnum'; import { isSameSourceHandle, isSameTargetHandle } from '../../utils'; -// import { defaultLayerData } from './defaultData'; import css from './FlowDiagram.module.less'; -import { type Operator } from '../../Operators/Operator'; import { useLatest } from 'ahooks'; import { BackToLayer } from '../LayerPanel/BackToLayer'; @@ -38,17 +31,7 @@ const nodeColor = (node: Node) => { if (operator?.nodeColor) { return operator?.nodeColor; } - - switch (node.type) { - case NodeTypeEnum.StreamOperatorNode: - return '#FF0060'; - case NodeTypeEnum.ContainerNode: - return '#FF8080'; - case NodeTypeEnum.DoNode: - return '#FFF5E0'; - default: - return '#ff0072'; - } + return '#ff0072'; }; const getLayoutedElements = (nodes: Node[], edges: Edge[]) => { const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({})); @@ -147,7 +130,7 @@ export const FlowDiagram: React.FC = () => { const handleDrop: DragEventHandler = (event) => { const operatorType = event.dataTransfer.getData(OPERATOR_TYPE_DATA); if (operatorType) { - const operator = NextOperatorMap.get(operatorType); + const operator = OperatorMap.get(operatorType); if (operator) { const operatorInstance = operator.create(); if (operator.isUnique) { @@ -208,68 +191,7 @@ export const FlowDiagram: React.FC = () => { }, }); }); - return; - } - } - // TODO: DELETE - const operatorName = operatorType; - const Operator = OperatorMap.get(operatorName); - - if (Operator) { - const operatorInstance = new Operator(); - if (operatorInstance.unique) { - if (nodes.find((item) => item.type === operatorInstance.type)) { - message.warning('只允许存在一个'); - return; - } - } - const { clientX, clientY } = event; - const rect = dropTarget.current?.getBoundingClientRect(); - if (rect) { - operatorInstance.position = { - x: clientX - rect.left, - y: clientY - rect.y, - }; } - - setNodes((eles) => [...eles, operatorInstance]); - setTimeout(() => { - const node = nodesRef.current.find( - (item) => item.id === operatorInstance.id, - ); - - if (node) { - const pos = { - x: node?.position?.x - (node?.width || 0) / 2, - y: node.position.y - Math.max((node?.height || 0) / 5, 30), - }; - - node.position = pos; - // TODO: zoom - updateNodePos([node], false, false); - } - - setNodes((eles) => { - const target = eles.find((item) => item.id === operatorInstance.id); - if (target) { - operatorInstance.style = { - visibility: 'visible', - }; - } - return [...eles]; - }); - - Operator?.onAfterCreate?.({ - node: node as Operator, - currentState: latestState.current, - actions: { - updateEdge, - updateNode, - setActiveLayerId, - setLayer, - }, - }); - }); } }; diff --git a/packages/flow/src/Diagrams/Panels/OperatorPanel/index.tsx b/packages/flow/src/Diagrams/Panels/OperatorPanel/index.tsx index f9079ce..19efabe 100644 --- a/packages/flow/src/Diagrams/Panels/OperatorPanel/index.tsx +++ b/packages/flow/src/Diagrams/Panels/OperatorPanel/index.tsx @@ -1,5 +1,5 @@ import React, { type DragEventHandler } from 'react'; -import { OperatorMap, NextOperatorMap } from '../../Operators'; +import { OperatorMap } from '../../Operators'; import css from './OperatorPanel.module.less'; export const OPERATOR_TYPE_DATA = 'operator_type'; @@ -18,19 +18,7 @@ export const OperatorPanel: React.FC = () => {
Operators
- {[...OperatorMap.entries()].map(([name, Operator]) => { - return ( -
- {name} -
- ); - })} - {[...NextOperatorMap.entries()].map(([name, operator]) => { + {[...OperatorMap.entries()].map(([name, operator]) => { return (
Date: Sat, 13 Jan 2024 16:14:42 +0800 Subject: [PATCH 3/3] feat: fix CustomOperator error --- .../flow/src/Diagrams/Nodes/Node/index.tsx | 18 ++- .../CustomOperator/AttributeControl/index.tsx | 15 ++- .../Operators/CustomOperator/index.tsx | 67 ++++++------ .../src/Diagrams/Operators/types/index.ts | 2 +- .../Diagrams/Panels/CommandPanel/index.tsx | 55 ++++++++-- .../src/Diagrams/State/DiagramsProvider.tsx | 103 ++++++++++++------ packages/flow/src/Diagrams/utils/index.ts | 4 + 7 files changed, 175 insertions(+), 89 deletions(-) diff --git a/packages/flow/src/Diagrams/Nodes/Node/index.tsx b/packages/flow/src/Diagrams/Nodes/Node/index.tsx index 77e727c..651ec84 100644 --- a/packages/flow/src/Diagrams/Nodes/Node/index.tsx +++ b/packages/flow/src/Diagrams/Nodes/Node/index.tsx @@ -46,21 +46,12 @@ export function Node(props: NodeProps) { } const valueSection = renderValueSection(); - - const headerInfo = [ - operator?.description && ( -
- {operator?.description} -
- ), - valueSection &&
{valueSection}
, - ].filter(Boolean); - return (
) { }} >
- {headerInfo} + {operator?.description && ( +
+ {operator?.description} +
+ )} + {valueSection &&
{valueSection}
} {/*
{data.label}
*/}
diff --git a/packages/flow/src/Diagrams/Operators/CustomOperator/AttributeControl/index.tsx b/packages/flow/src/Diagrams/Operators/CustomOperator/AttributeControl/index.tsx index ce87078..a4810be 100644 --- a/packages/flow/src/Diagrams/Operators/CustomOperator/AttributeControl/index.tsx +++ b/packages/flow/src/Diagrams/Operators/CustomOperator/AttributeControl/index.tsx @@ -1,5 +1,8 @@ import { type Node } from 'reactflow'; -import { useDiagramsContext } from '../../../State/DiagramsProvider'; +import { + useDiagramsContext, + useDiagramsHookOption, +} from '../../../State/DiagramsProvider'; import { Button, Form, Input } from 'antd'; import { findLayer } from '../../../State/Layer'; import { type CustomOperator } from '..'; @@ -8,7 +11,8 @@ import { getOperatorFromNode } from '../../OperatorMap'; export function AttributeControl(props: { node: Node }) { const { node } = props; - const { updateNode, layer, setLayer } = useDiagramsContext(); + const { updateNode, setLayer } = useDiagramsContext(); + const { currentStateRef, actionsRef } = useDiagramsHookOption(); const operator = getOperatorFromNode(node); @@ -46,9 +50,10 @@ export function AttributeControl(props: { node: Node }) { + +
); } diff --git a/packages/flow/src/Diagrams/State/DiagramsProvider.tsx b/packages/flow/src/Diagrams/State/DiagramsProvider.tsx index 754e2a1..c54a867 100644 --- a/packages/flow/src/Diagrams/State/DiagramsProvider.tsx +++ b/packages/flow/src/Diagrams/State/DiagramsProvider.tsx @@ -16,15 +16,38 @@ import { getOperatorFromNode } from '../Operators'; import { type ICustomOperatorData } from '../Operators/types'; import { type CustomOperator } from '../Operators/CustomOperator'; +interface IUpdateNodeOption { + updateInternal?: boolean; + layerId?: string; +} + +type ISetNodeOption = Pick; + +type ISetEdgeOption = ISetNodeOption; + export interface DiagramsContextType { /** ====== current ====== */ nodes: Node[]; - setNodes: React.Dispatch[]>>; - updateNode: (id: string, action: React.SetStateAction>) => void; + setNodes: ( + action: React.SetStateAction[]>, + options?: ISetNodeOption, + ) => void; + updateNode: ( + id: string, + action: React.SetStateAction>, + options?: IUpdateNodeOption, + ) => void; edges: Edge[]; - setEdges: React.Dispatch[]>>; - updateEdge: (id: string, action: React.SetStateAction>) => void; + setEdges: ( + action: React.SetStateAction[]>, + options?: ISetEdgeOption, + ) => void; + updateEdge: ( + id: string, + action: React.SetStateAction>, + options?: ISetEdgeOption, + ) => void; /** ====== all ====== */ layer: Layer; @@ -68,6 +91,7 @@ export function useDiagramsHookOption() { updateNode, setActiveLayerId, setLayer, + setEdges, layer, activeLayerId, } = useDiagramsContext(); @@ -81,6 +105,7 @@ export function useDiagramsHookOption() { const actionsRef = useLatest({ updateEdge, updateNode, + setEdges, setActiveLayerId, setLayer, }); @@ -144,9 +169,10 @@ export const DiagramsContextInnerProvider: React.FC = (props) => { const setNodes = useMemoizedFn(function setNodes( action: React.SetStateAction, + options?: ISetNodeOption, ) { setLayer((layer) => { - const activeLayer = findLayer(layer, activeLayerId); + const activeLayer = findLayer(layer, options?.layerId || activeLayerId); if (activeLayer) { activeLayer.nodes = typeof action === 'function' ? action(activeLayer.nodes) : action; @@ -163,9 +189,10 @@ export const DiagramsContextInnerProvider: React.FC = (props) => { const setEdges = useMemoizedFn(function setEdges( action: React.SetStateAction, + options?: ISetEdgeOption, ) { setLayer((layer) => { - const activeLayer = findLayer(layer, activeLayerId); + const activeLayer = findLayer(layer, options?.layerId || activeLayerId); if (activeLayer) { activeLayer.edges = typeof action === 'function' ? action(activeLayer.edges) : action; @@ -179,7 +206,7 @@ export const DiagramsContextInnerProvider: React.FC = (props) => { const updateEdge = useMemoizedFn(function updateEdge( id: string, updateElementAction: React.SetStateAction, - updateInternal?: boolean, + options?: ISetEdgeOption, ) { if (!id) { return; @@ -199,39 +226,38 @@ export const DiagramsContextInnerProvider: React.FC = (props) => { ? updateElementAction(target) : updateElementAction; return elesWillUpdate.concat(res); - }); - - if (updateInternal) { - setTimeout(() => { - updateNodeInternals(id); - }, 0); - } + }, options); }); const updateNode = useMemoizedFn(function updateNode( id: string, updateElementAction: React.SetStateAction, - updateInternal?: boolean, + option?: IUpdateNodeOption, ) { if (!id) { return; } - setNodes((eles) => { - const targetIndex = eles.findIndex((item) => item.id === id); + const { updateInternal, layerId } = option || {}; - if (targetIndex < 0) { - return eles; - } + setNodes( + (eles) => { + const targetIndex = eles.findIndex((item) => item.id === id); - const elesWillUpdate = [...eles]; - const target = elesWillUpdate.splice(targetIndex, 1)?.[0]; - const res = - typeof updateElementAction === 'function' - ? updateElementAction(target) - : updateElementAction; - return elesWillUpdate.concat(res); - }); + if (targetIndex < 0) { + return eles; + } + + const elesWillUpdate = [...eles]; + const target = elesWillUpdate.splice(targetIndex, 1)?.[0]; + const res = + typeof updateElementAction === 'function' + ? updateElementAction(target) + : updateElementAction; + return elesWillUpdate.concat(res); + }, + { layerId }, + ); if (updateInternal) { setTimeout(() => { @@ -240,6 +266,20 @@ export const DiagramsContextInnerProvider: React.FC = (props) => { } }); + const currentStateRef = useLatest({ + nodes, + edges, + layer, + activeLayerId, + }); + const actionsRef = useLatest({ + updateEdge, + updateNode, + setEdges, + setActiveLayerId: () => undefined, + setLayer, + }); + const setActiveLayerId = useMemoizedFn((activeId: string) => { const prevActiveId = activeLayerId; _setActiveLayerId(activeId); @@ -256,9 +296,10 @@ export const DiagramsContextInnerProvider: React.FC = (props) => { if (targetNode) { const operator = getOperatorFromNode(targetNode); - operator?.refreshNode(targetNode as any, { - updateNode, - layer: layerRef.current, + operator?.refreshNode({ + node: targetNode, + actions: actionsRef.current, + currentState: currentStateRef.current, }); } } diff --git a/packages/flow/src/Diagrams/utils/index.ts b/packages/flow/src/Diagrams/utils/index.ts index 6fd15a9..7287946 100644 --- a/packages/flow/src/Diagrams/utils/index.ts +++ b/packages/flow/src/Diagrams/utils/index.ts @@ -18,3 +18,7 @@ export function isSameSourceHandle(source: Edge, target: Edge | Connection) { source.sourceHandle === target.sourceHandle ); } + +export async function sleepMs(milSec: number) { + return await new Promise((resolve) => setTimeout(resolve, milSec)); +}