From de863df6fb3fcb0e7b8d1beb4207770eb33d48df Mon Sep 17 00:00:00 2001 From: xiamidaxia Date: Fri, 6 Jun 2025 19:07:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(demo-fixed-layout):=20add=20case-default/b?= =?UTF-8?q?reak-loop/if=20nodes=EF=BC=8Ccondition=20->=20switch=20(#336)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(demo-fixed-layout): add case-default/break-loop/if nodes * feat(demo-fixed-layout): condition -> switch * chore: e2e fixed --- .../src/assets/icon-break.svg | 1 + .../src/assets/icon-case.png | Bin 0 -> 2293 bytes .../src/components/base-node/index.tsx | 3 +- .../src/components/branch-adder/index.tsx | 7 +- .../src/components/node-list.tsx | 2 +- .../components/sidebar/sidebar-renderer.tsx | 15 +- apps/demo-fixed-layout/src/initial-data.ts | 138 ++++++++++++------ .../src/nodes/break-loop/form-meta.tsx | 13 ++ .../src/nodes/break-loop/index.ts | 42 ++++++ .../src/nodes/case-default/form-meta.tsx | 32 ++++ .../src/nodes/case-default/index.ts | 31 ++++ .../demo-fixed-layout/src/nodes/case/index.ts | 10 +- .../src/nodes/catch-block/index.ts | 5 +- .../src/nodes/if-block/form-meta.tsx | 28 ++++ .../src/nodes/if-block/index.ts | 30 ++++ apps/demo-fixed-layout/src/nodes/if/index.ts | 57 ++++++++ apps/demo-fixed-layout/src/nodes/index.ts | 12 +- .../src/nodes/start/index.ts | 7 +- .../src/nodes/{condition => switch}/index.ts | 22 ++- apps/demo-fixed-layout/src/typings/node.ts | 5 +- .../components/sidebar/sidebar-renderer.tsx | 15 +- .../src/hooks/use-editor-props.tsx | 2 +- .../src/nodes/comment/index.tsx | 2 +- .../src/nodes/loop/loop-form-render.tsx | 2 - apps/demo-free-layout/src/typings/node.ts | 2 +- e2e/fixed-layout/tests/models/index.ts | 2 +- e2e/fixed-layout/tests/node.spec.ts | 6 +- .../document/src/entities/flow-node-entity.ts | 2 +- 28 files changed, 398 insertions(+), 95 deletions(-) create mode 100644 apps/demo-fixed-layout/src/assets/icon-break.svg create mode 100644 apps/demo-fixed-layout/src/assets/icon-case.png create mode 100644 apps/demo-fixed-layout/src/nodes/break-loop/form-meta.tsx create mode 100644 apps/demo-fixed-layout/src/nodes/break-loop/index.ts create mode 100644 apps/demo-fixed-layout/src/nodes/case-default/form-meta.tsx create mode 100644 apps/demo-fixed-layout/src/nodes/case-default/index.ts create mode 100644 apps/demo-fixed-layout/src/nodes/if-block/form-meta.tsx create mode 100644 apps/demo-fixed-layout/src/nodes/if-block/index.ts create mode 100644 apps/demo-fixed-layout/src/nodes/if/index.ts rename apps/demo-fixed-layout/src/nodes/{condition => switch}/index.ts (80%) diff --git a/apps/demo-fixed-layout/src/assets/icon-break.svg b/apps/demo-fixed-layout/src/assets/icon-break.svg new file mode 100644 index 00000000..ef172eee --- /dev/null +++ b/apps/demo-fixed-layout/src/assets/icon-break.svg @@ -0,0 +1 @@ + diff --git a/apps/demo-fixed-layout/src/assets/icon-case.png b/apps/demo-fixed-layout/src/assets/icon-case.png new file mode 100644 index 0000000000000000000000000000000000000000..e2a9d1a26557ecef9e2e1cff3362054717dc8e40 GIT binary patch literal 2293 zcmZvedpy&B1I0hz@66WNX0lw*Lj`)&R<8!@nqp~R2%>R@5W~M%oF*au&VRk zu#wj?4=Boq#L`&8!MHxz?U4&!i;%M}GH3|se}pk1F_*x64wB1TMo4+6 zyIyKZv9C`BcRn4zkuV;%>*`qVh~waZW7GKBx#=K#V(;s3b0aUeR|&z^(N(k6L**vo zgd>ATpk0%fH`>^Xx>@BQv@W9Oph>h_uI~ASLPiu2ZKz2flH@g8J)r1j0@~f7E~_Mk z&1^ne#~CHd9=&8|1Dx3)Q#)q)$|Qx>swMF-_gcM#hs8SSfaf6!BYevmu`mD8>~A{F z7sLG>Jf~X*(Qo1CVUpMl-M7o{h}50PAiFwdT}2jQzxX11U3<-XW-v9gZ(^kn$^;==KJ*CEmeZ^+V({f|LJHULOs~Hho<`QUyS@XHRE~N zG3xVd%c{=F^_wxg>cTx?SYL>18P581!(Bl0DYH+cg0JXBoSEgur0^1$9xvcHSbjJf z-eq14F9LQa=A<_yM}qTGanFF&0{@KDHWBGB&-po;+g;WN3BQTG)7o3Y>#VKAGvZ6> zDxhUrurNJ(>-fW$QLwj77)q)cVi@YG?QQRvz60&qhynP39jC4J)Uh4j2pa490asYk=iy zA&E}bpxyZX@?t-i=!@A-PQ=gZKb{#>8i6lt3^>i#d*$lmk`X<7+s*I%A&wUK!otuZ zCy$e3Ph>W%HKBtdh9?RO#`nx38gJ7E14L@Fab~jA7;uP%gq{bJ*$LW2B6eT~UH%pnqm$CpMDhEc1#H2K1vm zcbab-f;D8=f5H?F9Cgo;gVXM2cnzN|Bw+T{4j_~wpR+FC3h#uVf$_(aIshA&678-X z#Dbb3?8!7E0E0L?VNU*DV_o*^HR|2>e%|n6IAZz=M?l%L7k=C%aA1Dg(=UA(!PP_AU|JLk1qUdNs=PgDTS|(F? z;mcv}pxlS`x#H1EK+@Cr?vV!3t1nv7+RBax(Uec(kC^$N8k>=bSh^tWQ=tD2+cV$K zd0*VMtZLpgINlaE$N3QE^L%>)Li|&c^T=WHx3Fr(n=G>hslcK@<7VP8CI9 z{{*2YA|Fi#Ker;k{708zVUw+lIssH?`5lxDC{gmOswp2BG>cMm!}qCE=G#?VH|}H< zK!DoSpeH+h%TT&|F~j9R64BM+Q#BjpJ!x8w_dSQ~4JH3b&enjCV2oXHT(JTDA(Og4 z^k;Smv8kQ?Vy>Tx^zG|ka7z)V%U&ZYpNv#d{ldBgxY(bYP#(tg!R9(?sXWLFAETps z-AETv6Y$Vp&;t3|eg8N=qKwaX}*!}5N+Q~{^_fm)-x ziN-y%&KSp+cg*!6oknhlnS6zrwE=bN$)M&2AlqrhUV&ga)7yw6dx{YgGLV=KtVx>j z4T|6PxuM6g``xa;ntID&i>tO17buHh*jxXHNo%7j;-~g2P_;a~{sczwY?GD-#5FGC*UG@ja#DtLjF@_MqUTG%~-Up_bO)wq@-H+YBHxeB896 zY*OheFT5tyKE$qNF&@XyY@sXF*I9@O@oZ zwx*dk%$kyEZMtn~+n4iftrv8lp{(evEjB`-KVaJHCpfOvO9t=Qkt~1vVw{zTk-K|L zOm-EO%?6A`xk0-x%S)A;Ok1?_zbh_{Nk&ES>w$+BYq7b@j__<=bMB+G++R0~lB${- zZysOp#m?7t+s { * isBlockIcon: 整个 condition 分支的 头部节点 * isBlockOrderIcon: 分支的第一个节点 */ - ...(nodeRender.isBlockOrderIcon || nodeRender.isBlockIcon ? { width: 260 } : {}), + ...(nodeRender.isBlockOrderIcon || nodeRender.isBlockIcon ? {} : {}), + ...nodeRender.node.getNodeRegistry().meta.style, outline: form?.state.invalid ? '1px solid red' : 'none', }} > diff --git a/apps/demo-fixed-layout/src/components/branch-adder/index.tsx b/apps/demo-fixed-layout/src/components/branch-adder/index.tsx index ec2abcf1..423fc883 100644 --- a/apps/demo-fixed-layout/src/components/branch-adder/index.tsx +++ b/apps/demo-fixed-layout/src/components/branch-adder/index.tsx @@ -20,9 +20,12 @@ export default function BranchAdder(props: PropsType) { function addBranch() { const block = operation.addBlock( node, - node.flowNodeType === 'condition' + node.flowNodeType === 'switch' ? CaseNodeRegistry.onAdd!(ctx, node) - : CatchBlockNodeRegistry.onAdd!(ctx, node) + : CatchBlockNodeRegistry.onAdd!(ctx, node), + { + index: 0, + } ); setTimeout(() => { diff --git a/apps/demo-fixed-layout/src/components/node-list.tsx b/apps/demo-fixed-layout/src/components/node-list.tsx index 907f39d5..bb575f36 100644 --- a/apps/demo-fixed-layout/src/components/node-list.tsx +++ b/apps/demo-fixed-layout/src/components/node-list.tsx @@ -55,7 +55,7 @@ export function NodeList(props: { onSelect: (meta: any) => void; from: FlowNodeE }; return ( - {FlowNodeRegistries.map((registry) => ( + {FlowNodeRegistries.filter((registry) => !registry.meta?.addDisable).map((registry) => ( { if (!node) { return false; } - const { disableSideBar = false } = node.getNodeMeta(); - return !disableSideBar; + const { sidebarDisable = false } = node.getNodeMeta(); + return !sidebarDisable; }, [node]); if (playground.config.readonly) { @@ -73,11 +73,12 @@ export const SidebarRenderer = () => { /** * Add "key" to rerender the sidebar when the node changes */ - const content = node ? ( - - - - ) : null; + const content = + node && visible ? ( + + + + ) : null; return ( diff --git a/apps/demo-fixed-layout/src/initial-data.ts b/apps/demo-fixed-layout/src/initial-data.ts index 21d6ce3f..9b98928a 100644 --- a/apps/demo-fixed-layout/src/initial-data.ts +++ b/apps/demo-fixed-layout/src/initial-data.ts @@ -88,63 +88,115 @@ export const initialData: FlowDocumentJSON = { }, }, { - id: 'loop_0', - type: 'loop', + id: 'if_0', + type: 'if', data: { - title: 'Loop', - batchFor: { - type: 'ref', - content: ['start_0', 'array_obj'], + title: 'If', + inputsValues: { + condition: { type: 'constant', content: true }, + }, + inputs: { + type: 'object', + required: ['condition'], + properties: { + condition: { + type: 'boolean', + }, + }, }, }, blocks: [ { - id: 'condition_0', - type: 'condition', + id: 'if_true', + type: 'ifBlock', data: { - title: 'Condition', + title: 'true', + }, + blocks: [], + }, + { + id: 'if_false', + type: 'ifBlock', + data: { + title: 'false', }, blocks: [ { - id: 'case_0', - type: 'case', + id: 'loop_0', + type: 'loop', data: { - title: 'If_0', - inputsValues: { - condition: { type: 'constant', content: true }, - }, - inputs: { - type: 'object', - required: ['condition'], - properties: { - condition: { - type: 'boolean', - }, - }, + title: 'Loop', + batchFor: { + type: 'ref', + content: ['start_0', 'array_obj'], }, }, - blocks: [], - }, - { - id: 'case_1', - type: 'case', - data: { - title: 'If_1', - inputsValues: { - condition: { type: 'constant', content: true }, - }, - inputs: { - type: 'object', - required: ['condition'], - properties: { - condition: { - type: 'boolean', - }, + blocks: [ + { + id: 'switch_0', + type: 'switch', + data: { + title: 'Switch', }, + blocks: [ + { + id: 'case_0', + type: 'case', + data: { + title: 'Case_0', + inputsValues: { + condition: { type: 'constant', content: true }, + }, + inputs: { + type: 'object', + required: ['condition'], + properties: { + condition: { + type: 'boolean', + }, + }, + }, + }, + blocks: [], + }, + { + id: 'case_1', + type: 'case', + data: { + title: 'Case_1', + inputsValues: { + condition: { type: 'constant', content: true }, + }, + inputs: { + type: 'object', + required: ['condition'], + properties: { + condition: { + type: 'boolean', + }, + }, + }, + }, + }, + { + id: 'case_default_1', + type: 'caseDefault', + data: { + title: 'Default', + }, + blocks: [ + { + id: 'break_0', + type: 'breakLoop', + data: { + title: 'BreakLoop', + }, + }, + ], + }, + ], }, - }, - meta: {}, - blocks: [], + ], }, ], }, diff --git a/apps/demo-fixed-layout/src/nodes/break-loop/form-meta.tsx b/apps/demo-fixed-layout/src/nodes/break-loop/form-meta.tsx new file mode 100644 index 00000000..c688d805 --- /dev/null +++ b/apps/demo-fixed-layout/src/nodes/break-loop/form-meta.tsx @@ -0,0 +1,13 @@ +import { FormMeta } from '@flowgram.ai/fixed-layout-editor'; + +import { FormHeader } from '../../form-components'; + +export const renderForm = () => ( + <> + + +); + +export const formMeta: FormMeta = { + render: renderForm, +}; diff --git a/apps/demo-fixed-layout/src/nodes/break-loop/index.ts b/apps/demo-fixed-layout/src/nodes/break-loop/index.ts new file mode 100644 index 00000000..41f37a33 --- /dev/null +++ b/apps/demo-fixed-layout/src/nodes/break-loop/index.ts @@ -0,0 +1,42 @@ +import { nanoid } from 'nanoid'; + +import { FlowNodeRegistry } from '../../typings'; +import iconBreak from '../../assets/icon-break.svg'; +import { formMeta } from './form-meta'; + +/** + * Break 节点用于在 loop 中根据条件终止并跳出 + */ +export const BreakLoopNodeRegistry: FlowNodeRegistry = { + type: 'breakLoop', + extend: 'end', + info: { + icon: iconBreak, + description: 'Break in current Loop.', + }, + meta: { + style: { + width: 240, + }, + }, + /** + * Render node via formMeta + */ + formMeta, + canAdd(ctx, from) { + while (from.parent) { + if (from.parent.flowNodeType === 'loop') return true; + from = from.parent; + } + return false; + }, + onAdd(ctx, from) { + return { + id: `break_${nanoid()}`, + type: 'breakLoop', + data: { + title: 'BreakLoop', + }, + }; + }, +}; diff --git a/apps/demo-fixed-layout/src/nodes/case-default/form-meta.tsx b/apps/demo-fixed-layout/src/nodes/case-default/form-meta.tsx new file mode 100644 index 00000000..d883231a --- /dev/null +++ b/apps/demo-fixed-layout/src/nodes/case-default/form-meta.tsx @@ -0,0 +1,32 @@ +import { FormRenderProps, FormMeta, ValidateTrigger } from '@flowgram.ai/fixed-layout-editor'; + +import { FlowNodeJSON } from '../../typings'; +import { FormHeader, FormContent, FormInputs, FormOutputs } from '../../form-components'; + +export const renderForm = ({ form }: FormRenderProps) => ( + <> + + + + + + +); + +export const formMeta: FormMeta = { + render: renderForm, + validateTrigger: ValidateTrigger.onChange, + validate: { + 'inputsValues.*': ({ value, context, formValues, name }) => { + const valuePropetyKey = name.replace(/^inputsValues\./, ''); + const required = formValues.inputs?.required || []; + if ( + required.includes(valuePropetyKey) && + (value === '' || value === undefined || value?.content === '') + ) { + return `${valuePropetyKey} is required`; + } + return undefined; + }, + }, +}; diff --git a/apps/demo-fixed-layout/src/nodes/case-default/index.ts b/apps/demo-fixed-layout/src/nodes/case-default/index.ts new file mode 100644 index 00000000..c2f24ef5 --- /dev/null +++ b/apps/demo-fixed-layout/src/nodes/case-default/index.ts @@ -0,0 +1,31 @@ +import { FlowNodeRegistry } from '../../typings'; +import iconCase from '../../assets/icon-case.png'; +import { formMeta } from './form-meta'; + +export const CaseDefaultNodeRegistry: FlowNodeRegistry = { + type: 'caseDefault', + /** + * 分支节点需要继承自 block + * Branch nodes need to inherit from 'block' + */ + extend: 'case', + meta: { + copyDisable: true, + addDisable: true, + /** + * caseDefault 永远在最后一个分支,所以不允许拖拽排序 + * "caseDefault" is always in the last branch, so dragging and sorting is not allowed. + */ + draggable: false, + deleteDisable: true, + style: { + width: 240, + }, + }, + info: { + icon: iconCase, + description: 'Switch default branch', + }, + canDelete: (ctx, node) => false, + formMeta, +}; diff --git a/apps/demo-fixed-layout/src/nodes/case/index.ts b/apps/demo-fixed-layout/src/nodes/case/index.ts index 74367cf8..d0e6f95a 100644 --- a/apps/demo-fixed-layout/src/nodes/case/index.ts +++ b/apps/demo-fixed-layout/src/nodes/case/index.ts @@ -1,7 +1,7 @@ import { nanoid } from 'nanoid'; import { FlowNodeRegistry } from '../../typings'; -import iconIf from '../../assets/icon-if.png'; +import iconCase from '../../assets/icon-case.png'; import { formMeta } from './form-meta'; let id = 2; @@ -14,19 +14,19 @@ export const CaseNodeRegistry: FlowNodeRegistry = { extend: 'block', meta: { copyDisable: true, + addDisable: true, }, info: { - icon: iconIf, + icon: iconCase, description: 'Execute the branch when the condition is met.', }, - canAdd: () => false, canDelete: (ctx, node) => node.parent!.blocks.length >= 3, onAdd(ctx, from) { return { - id: `if_${nanoid(5)}`, + id: `Case_${nanoid(5)}`, type: 'case', data: { - title: `If_${id++}`, + title: `Case_${id++}`, inputs: { type: 'object', required: ['condition'], diff --git a/apps/demo-fixed-layout/src/nodes/catch-block/index.ts b/apps/demo-fixed-layout/src/nodes/catch-block/index.ts index 8b35a95a..e6143445 100644 --- a/apps/demo-fixed-layout/src/nodes/catch-block/index.ts +++ b/apps/demo-fixed-layout/src/nodes/catch-block/index.ts @@ -1,7 +1,7 @@ import { nanoid } from 'nanoid'; import { FlowNodeRegistry } from '../../typings'; -import iconIf from '../../assets/icon-if.png'; +import iconCase from '../../assets/icon-case.png'; import { formMeta } from './form-meta'; let id = 3; @@ -9,9 +9,10 @@ export const CatchBlockNodeRegistry: FlowNodeRegistry = { type: 'catchBlock', meta: { copyDisable: true, + addDisable: true, }, info: { - icon: iconIf, + icon: iconCase, description: 'Execute the catch branch when the condition is met.', }, canAdd: () => false, diff --git a/apps/demo-fixed-layout/src/nodes/if-block/form-meta.tsx b/apps/demo-fixed-layout/src/nodes/if-block/form-meta.tsx new file mode 100644 index 00000000..45deff81 --- /dev/null +++ b/apps/demo-fixed-layout/src/nodes/if-block/form-meta.tsx @@ -0,0 +1,28 @@ +import { FormRenderProps, FormMeta, Field } from '@flowgram.ai/fixed-layout-editor'; + +import { FlowNodeJSON } from '../../typings'; +import { useNodeRenderContext } from '../../hooks'; + +export const renderForm = (props: FormRenderProps) => { + const { node } = useNodeRenderContext(); + return ( +
+ {({ field }) => <>{field.value}} +
+ ); +}; + +export const formMeta: FormMeta = { + render: renderForm, +}; diff --git a/apps/demo-fixed-layout/src/nodes/if-block/index.ts b/apps/demo-fixed-layout/src/nodes/if-block/index.ts new file mode 100644 index 00000000..b398b5ea --- /dev/null +++ b/apps/demo-fixed-layout/src/nodes/if-block/index.ts @@ -0,0 +1,30 @@ +import { FlowNodeRegistry } from '../../typings'; +import iconIf from '../../assets/icon-if.png'; +import { formMeta } from './form-meta'; + +export const IFBlockNodeRegistry: FlowNodeRegistry = { + type: 'ifBlock', + /** + * 分支节点需要继承自 block + * Branch nodes need to inherit from 'block' + */ + extend: 'block', + meta: { + copyDisable: true, + addDisable: true, + sidebarDisable: true, + defaultExpanded: false, + style: { + width: 66, + height: 20, + borderRadius: 4, + }, + }, + info: { + icon: iconIf, + description: '', + }, + canAdd: () => false, + canDelete: (ctx, node) => false, + formMeta, +}; diff --git a/apps/demo-fixed-layout/src/nodes/if/index.ts b/apps/demo-fixed-layout/src/nodes/if/index.ts new file mode 100644 index 00000000..1678544d --- /dev/null +++ b/apps/demo-fixed-layout/src/nodes/if/index.ts @@ -0,0 +1,57 @@ +import { nanoid } from 'nanoid'; +import { FlowNodeSplitType } from '@flowgram.ai/fixed-layout-editor'; + +import { defaultFormMeta } from '../default-form-meta'; +import { FlowNodeRegistry } from '../../typings'; +import iconIf from '../../assets/icon-if.png'; + +export const IFNodeRegistry: FlowNodeRegistry = { + extend: FlowNodeSplitType.STATIC_SPLIT, + type: 'if', + info: { + icon: iconIf, + description: 'Only the corresponding branch will be executed if the set conditions are met.', + }, + meta: { + expandable: false, // disable expanded + }, + formMeta: defaultFormMeta, + onAdd() { + return { + id: `if_${nanoid(5)}`, + type: 'if', + data: { + title: 'If', + inputsValues: { + condition: { type: 'constant', content: true }, + }, + inputs: { + type: 'object', + required: ['condition'], + properties: { + condition: { + type: 'boolean', + }, + }, + }, + }, + blocks: [ + { + id: nanoid(5), + type: 'ifBlock', + data: { + title: 'true', + }, + blocks: [], + }, + { + id: nanoid(5), + type: 'ifBlock', + data: { + title: 'false', + }, + }, + ], + }; + }, +}; diff --git a/apps/demo-fixed-layout/src/nodes/index.ts b/apps/demo-fixed-layout/src/nodes/index.ts index 5a82c9fc..b5cedd80 100644 --- a/apps/demo-fixed-layout/src/nodes/index.ts +++ b/apps/demo-fixed-layout/src/nodes/index.ts @@ -1,20 +1,28 @@ import { type FlowNodeRegistry } from '../typings'; import { TryCatchNodeRegistry } from './trycatch'; +import { SwitchNodeRegistry } from './switch'; import { StartNodeRegistry } from './start'; import { LoopNodeRegistry } from './loop'; import { LLMNodeRegistry } from './llm'; +import { IFBlockNodeRegistry } from './if-block'; +import { IFNodeRegistry } from './if'; import { EndNodeRegistry } from './end'; -import { ConditionNodeRegistry } from './condition'; import { CatchBlockNodeRegistry } from './catch-block'; +import { CaseDefaultNodeRegistry } from './case-default'; import { CaseNodeRegistry } from './case'; +import { BreakLoopNodeRegistry } from './break-loop'; export const FlowNodeRegistries: FlowNodeRegistry[] = [ StartNodeRegistry, EndNodeRegistry, - ConditionNodeRegistry, + SwitchNodeRegistry, LLMNodeRegistry, LoopNodeRegistry, CaseNodeRegistry, TryCatchNodeRegistry, CatchBlockNodeRegistry, + IFNodeRegistry, + IFBlockNodeRegistry, + BreakLoopNodeRegistry, + CaseDefaultNodeRegistry, ]; diff --git a/apps/demo-fixed-layout/src/nodes/start/index.ts b/apps/demo-fixed-layout/src/nodes/start/index.ts index 0b1e4767..5efca223 100644 --- a/apps/demo-fixed-layout/src/nodes/start/index.ts +++ b/apps/demo-fixed-layout/src/nodes/start/index.ts @@ -10,6 +10,7 @@ export const StartNodeRegistry: FlowNodeRegistry = { selectable: false, // Start node cannot select copyDisable: true, // Start node cannot copy expandable: false, // disable expanded + addDisable: true, // Start Node cannot be added }, info: { icon: iconStart, @@ -20,10 +21,4 @@ export const StartNodeRegistry: FlowNodeRegistry = { * Render node via formMeta */ formMeta, - /** - * Start Node cannot be added - */ - canAdd() { - return false; - }, }; diff --git a/apps/demo-fixed-layout/src/nodes/condition/index.ts b/apps/demo-fixed-layout/src/nodes/switch/index.ts similarity index 80% rename from apps/demo-fixed-layout/src/nodes/condition/index.ts rename to apps/demo-fixed-layout/src/nodes/switch/index.ts index 58d36a06..bab588c5 100644 --- a/apps/demo-fixed-layout/src/nodes/condition/index.ts +++ b/apps/demo-fixed-layout/src/nodes/switch/index.ts @@ -5,9 +5,9 @@ import { defaultFormMeta } from '../default-form-meta'; import { FlowNodeRegistry } from '../../typings'; import iconCondition from '../../assets/icon-condition.svg'; -export const ConditionNodeRegistry: FlowNodeRegistry = { +export const SwitchNodeRegistry: FlowNodeRegistry = { extend: FlowNodeSplitType.DYNAMIC_SPLIT, - type: 'condition', + type: 'switch', info: { icon: iconCondition, description: @@ -19,17 +19,17 @@ export const ConditionNodeRegistry: FlowNodeRegistry = { formMeta: defaultFormMeta, onAdd() { return { - id: `condition_${nanoid(5)}`, - type: 'condition', + id: `switch_${nanoid(5)}`, + type: 'switch', data: { - title: 'Condition', + title: 'Switch', }, blocks: [ { id: nanoid(5), type: 'case', data: { - title: 'If_0', + title: 'Case_0', inputsValues: { condition: { type: 'constant', content: '' }, }, @@ -49,7 +49,7 @@ export const ConditionNodeRegistry: FlowNodeRegistry = { id: nanoid(5), type: 'case', data: { - title: 'If_1', + title: 'Case_1', inputsValues: { condition: { type: 'constant', content: '' }, }, @@ -64,6 +64,14 @@ export const ConditionNodeRegistry: FlowNodeRegistry = { }, }, }, + { + id: nanoid(5), + type: 'caseDefault', + data: { + title: 'Default', + }, + blocks: [], + }, ], }; }, diff --git a/apps/demo-fixed-layout/src/typings/node.ts b/apps/demo-fixed-layout/src/typings/node.ts index fbed5065..05318b95 100644 --- a/apps/demo-fixed-layout/src/typings/node.ts +++ b/apps/demo-fixed-layout/src/typings/node.ts @@ -43,14 +43,15 @@ export interface FlowNodeJSON extends FlowNodeJSONDefault { * 你可以自定义节点的meta */ export interface FlowNodeMeta extends FlowNodeMetaDefault { - disableSideBar?: boolean; + sidebarDisable?: boolean; + style?: React.CSSProperties; } /** * You can customize your own node registry * 你可以自定义节点的注册器 */ export interface FlowNodeRegistry extends FlowNodeRegistryDefault { - meta: FlowNodeMeta; + meta?: FlowNodeMeta; info: { icon: string; description: string; diff --git a/apps/demo-free-layout/src/components/sidebar/sidebar-renderer.tsx b/apps/demo-free-layout/src/components/sidebar/sidebar-renderer.tsx index dbccd3af..e8fb2b28 100644 --- a/apps/demo-free-layout/src/components/sidebar/sidebar-renderer.tsx +++ b/apps/demo-free-layout/src/components/sidebar/sidebar-renderer.tsx @@ -63,8 +63,8 @@ export const SidebarRenderer = () => { if (!node) { return false; } - const { disableSideBar = false } = node.getNodeMeta(); - return !disableSideBar; + const { sidebarDisable = false } = node.getNodeMeta(); + return !sidebarDisable; }, [node]); if (playground.config.readonly) { @@ -73,11 +73,12 @@ export const SidebarRenderer = () => { /** * Add "key" to rerender the sidebar when the node changes */ - const content = node ? ( - - - - ) : null; + const content = + node && visible ? ( + + + + ) : null; return ( diff --git a/apps/demo-free-layout/src/hooks/use-editor-props.tsx b/apps/demo-free-layout/src/hooks/use-editor-props.tsx index 2edf66c8..d7f8ae15 100644 --- a/apps/demo-free-layout/src/hooks/use-editor-props.tsx +++ b/apps/demo-free-layout/src/hooks/use-editor-props.tsx @@ -6,7 +6,7 @@ import { createMinimapPlugin } from '@flowgram.ai/minimap-plugin'; import { createFreeSnapPlugin } from '@flowgram.ai/free-snap-plugin'; import { createFreeNodePanelPlugin } from '@flowgram.ai/free-node-panel-plugin'; import { createFreeLinesPlugin } from '@flowgram.ai/free-lines-plugin'; -import { FreeLayoutProps, WorkflowNodeLinesData } from '@flowgram.ai/free-layout-editor'; +import { FreeLayoutProps, WorkflowNodeLinesData, Form } from '@flowgram.ai/free-layout-editor'; import { createFreeGroupPlugin } from '@flowgram.ai/free-group-plugin'; import { createContainerNodePlugin } from '@flowgram.ai/free-container-plugin'; diff --git a/apps/demo-free-layout/src/nodes/comment/index.tsx b/apps/demo-free-layout/src/nodes/comment/index.tsx index 83f7e4f0..afd9faa7 100644 --- a/apps/demo-free-layout/src/nodes/comment/index.tsx +++ b/apps/demo-free-layout/src/nodes/comment/index.tsx @@ -4,7 +4,7 @@ import { FlowNodeRegistry } from '../../typings'; export const CommentNodeRegistry: FlowNodeRegistry = { type: WorkflowNodeType.Comment, meta: { - disableSideBar: true, + sidebarDisable: true, defaultPorts: [], renderKey: WorkflowNodeType.Comment, size: { diff --git a/apps/demo-free-layout/src/nodes/loop/loop-form-render.tsx b/apps/demo-free-layout/src/nodes/loop/loop-form-render.tsx index cdc07208..a06c8b47 100644 --- a/apps/demo-free-layout/src/nodes/loop/loop-form-render.tsx +++ b/apps/demo-free-layout/src/nodes/loop/loop-form-render.tsx @@ -1,5 +1,4 @@ import { FormRenderProps, FlowNodeJSON, Field } from '@flowgram.ai/free-layout-editor'; -import { SubCanvasRender } from '@flowgram.ai/free-container-plugin'; import { BatchVariableSelector, IFlowRefValue } from '@flowgram.ai/form-materials'; import { useIsSidebar, useNodeRenderContext } from '../../hooks'; @@ -48,7 +47,6 @@ export const LoopFormRender = ({ form }: FormRenderProps) => { {batchFor} - diff --git a/apps/demo-free-layout/src/typings/node.ts b/apps/demo-free-layout/src/typings/node.ts index 2f2e5fc6..e54a49a4 100644 --- a/apps/demo-free-layout/src/typings/node.ts +++ b/apps/demo-free-layout/src/typings/node.ts @@ -44,7 +44,7 @@ export interface FlowNodeJSON extends FlowNodeJSONDefault { * 你可以自定义节点的meta */ export interface FlowNodeMeta extends WorkflowNodeMeta { - disableSideBar?: boolean; + sidebarDisable?: boolean; } /** diff --git a/e2e/fixed-layout/tests/models/index.ts b/e2e/fixed-layout/tests/models/index.ts index fd7b3878..a2e77a08 100644 --- a/e2e/fixed-layout/tests/models/index.ts +++ b/e2e/fixed-layout/tests/models/index.ts @@ -25,7 +25,7 @@ class FixedLayoutModel { } public async isConditionNodeExist() { - return await this.page.locator('[data-node-id="$blockIcon$condition_0"]').count(); + return await this.page.locator('[data-node-id="$blockIcon$switch_0"]').count(); } public async insert(searchText: string, { from, to }: InsertEdgeOptions) { diff --git a/e2e/fixed-layout/tests/node.spec.ts b/e2e/fixed-layout/tests/node.spec.ts index cd8b6d9f..a869e39c 100644 --- a/e2e/fixed-layout/tests/node.spec.ts +++ b/e2e/fixed-layout/tests/node.spec.ts @@ -21,11 +21,11 @@ test.describe('node operations', () => { test('add node', async () => { const prevCount = await editorPage.getNodeCount(); - await editorPage.insert('condition', { + await editorPage.insert('switch', { from: 'llm_0', - to: 'loop_0', + to: 'if_0', }); const defaultNodeCount = await editorPage.getNodeCount(); - expect(defaultNodeCount).toEqual(prevCount + 3); + expect(defaultNodeCount).toEqual(prevCount + 4); }); }); diff --git a/packages/canvas-engine/document/src/entities/flow-node-entity.ts b/packages/canvas-engine/document/src/entities/flow-node-entity.ts index 507ba6f3..6b0ee55b 100644 --- a/packages/canvas-engine/document/src/entities/flow-node-entity.ts +++ b/packages/canvas-engine/document/src/entities/flow-node-entity.ts @@ -174,7 +174,7 @@ export class FlowNodeEntity extends Entity { return this.document.renderTree.getParent(this); } - getNodeRegistry(): M { + getNodeRegistry(): M { if (this._registerCache) return this._registerCache as M; this._registerCache = this.document.getNodeRegistry(this.flowNodeType, this.originParent); return this._registerCache as M;