Explorar el Código

refactor(free-demo): support add node through button on the line

liuyangxing hace 10 meses
padre
commit
ae6899455a

+ 2 - 0
apps/demo-free-layout/src/components/index.ts

@@ -1 +1,3 @@
 export * from './base-node';
+export * from './line-add-button';
+export * from './node-panel';

+ 26 - 0
apps/demo-free-layout/src/components/line-add-button/button.tsx

@@ -0,0 +1,26 @@
+export const IconPlusCircle = () => (
+  <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
+    <g id="add">
+      <path
+        id="background"
+        fill="#ffffff"
+        fillRule="evenodd"
+        stroke="none"
+        d="M 24 12 C 24 5.372583 18.627417 0 12 0 C 5.372583 0 -0 5.372583 -0 12 C -0 18.627417 5.372583 24 12 24 C 18.627417 24 24 18.627417 24 12 Z"
+      />
+      <path
+        id="content"
+        fill="currentColor"
+        fillRule="evenodd"
+        stroke="none"
+        d="M 22 12.005 C 22 6.482153 17.522848 2.004999 12 2.004999 C 6.477152 2.004999 2 6.482153 2 12.005 C 2 17.527847 6.477152 22.004999 12 22.004999 C 17.522848 22.004999 22 17.527847 22 12.005 Z"
+      />
+      <path
+        id="cross"
+        fill="#ffffff"
+        stroke="none"
+        d="M 11.411996 16.411797 C 11.411996 16.736704 11.675362 17 12.00023 17 C 12.325109 17 12.588474 16.736704 12.588474 16.411797 L 12.588474 12.58826 L 16.41201 12.58826 C 16.736919 12.58826 17.000216 12.324894 17.000216 12.000015 C 17.000216 11.675147 16.736919 11.411781 16.41201 11.411781 L 12.588474 11.411781 L 12.588474 7.588234 C 12.588474 7.263367 12.325109 7 12.00023 7 C 11.675362 7 11.411996 7.263367 11.411996 7.588234 L 11.411996 11.411781 L 7.588449 11.411781 C 7.263581 11.411781 7.000215 11.675147 7.000215 12.000015 C 7.000215 12.324894 7.263581 12.58826 7.588449 12.58826 L 11.411996 12.58826 L 11.411996 16.411797 Z"
+      />
+    </g>
+  </svg>
+);

+ 8 - 0
apps/demo-free-layout/src/components/line-add-button/index.less

@@ -0,0 +1,8 @@
+.line-add-button {
+  position: absolute;
+  transform: translate(-50%, -60%);
+  width: 24px;
+  height: 24px;
+  cursor: pointer;
+  color: inherit;
+}

+ 53 - 0
apps/demo-free-layout/src/components/line-add-button/index.tsx

@@ -0,0 +1,53 @@
+import { WorkflowNodePanelService } from '@flowgram.ai/free-node-panel-plugin';
+import { LineRenderProps } from '@flowgram.ai/free-lines-plugin';
+import { useService } from '@flowgram.ai/free-layout-editor';
+
+import './index.less';
+import { useVisible } from './use-visible';
+import { IconPlusCircle } from './button';
+
+export const LineAddButton = (props: LineRenderProps) => {
+  const { line, selected, color } = props;
+  const visible = useVisible({ line, selected, color });
+  const nodePanelService = useService<WorkflowNodePanelService>(WorkflowNodePanelService);
+
+  if (!visible) {
+    return <></>;
+  }
+
+  const { fromPort, toPort } = line;
+
+  return (
+    <div
+      className="line-add-button"
+      style={{
+        left: '50%',
+        top: '50%',
+        color,
+      }}
+      data-testid="sdk.workflow.canvas.line.add"
+      data-line-id={line.id}
+      onClick={async () => {
+        const node = await nodePanelService.call({
+          panelPosition: {
+            x: (line.position.from.x + line.position.to.x) / 2,
+            y: (line.position.from.y + line.position.to.y) / 2,
+          },
+          fromPort,
+          toPort,
+          enableBuildLine: true,
+          enableAutoOffset: true,
+          panelProps: {
+            enableScrollClose: true,
+          },
+        });
+        if (!node) {
+          return;
+        }
+        line.dispose();
+      }}
+    >
+      <IconPlusCircle />
+    </div>
+  );
+};

+ 35 - 0
apps/demo-free-layout/src/components/line-add-button/use-visible.ts

@@ -0,0 +1,35 @@
+import { LineColors, usePlayground, WorkflowLineEntity } from '@flowgram.ai/free-layout-editor';
+
+import './index.less';
+
+export const useVisible = (params: {
+  line: WorkflowLineEntity;
+  selected?: boolean;
+  color?: string;
+}): boolean => {
+  const playground = usePlayground();
+  const { line, selected = false, color } = params;
+  if (line.disposed) {
+    // 在 dispose 后,再去获取 line.to | line.from 会导致错误创建端口
+    return false;
+  }
+  if (playground.config.readonly) {
+    return false;
+  }
+  if (!selected && color !== LineColors.HOVER) {
+    return false;
+  }
+  if (
+    line.fromPort.portID === 'loop-output-to-function' &&
+    line.toPort?.portID === 'loop-function-input'
+  ) {
+    return false;
+  }
+  if (
+    line.fromPort.portID === 'batch-output-to-function' &&
+    line.toPort?.portID === 'batch-function-input'
+  ) {
+    return false;
+  }
+  return true;
+};

+ 9 - 1
apps/demo-free-layout/src/hooks/use-editor-props.tsx

@@ -4,6 +4,7 @@ import { useMemo } from 'react';
 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 } from '@flowgram.ai/free-layout-editor';
 
 import { FlowNodeRegistry, FlowDocumentJSON } from '../typings';
@@ -11,7 +12,7 @@ import { shortcuts } from '../shortcuts';
 import { createVariablePlugin } from '../plugins';
 import { defaultFormMeta } from '../nodes/default-form-meta';
 import { SelectorBoxPopover } from '../components/selector-box-popover';
-import { BaseNode, NodePanel } from '../components';
+import { BaseNode, LineAddButton, NodePanel } from '../components';
 
 export function useEditorProps(
   initialData: FlowDocumentJSON,
@@ -124,6 +125,13 @@ export function useEditorProps(
         console.log('---- Playground Dispose ----');
       },
       plugins: () => [
+        /**
+         * Line render plugin
+         * 连线渲染插件
+         */
+        createFreeLinesPlugin({
+          renderInsideLine: LineAddButton,
+        }),
         /**
          * Minimap plugin
          * 缩略图插件

+ 4 - 0
apps/demo-free-layout/src/nodes/condition/index.ts

@@ -15,6 +15,10 @@ export const ConditionNodeRegistry: FlowNodeRegistry = {
     defaultPorts: [{ type: 'input' }],
     // Condition Outputs use dynamic port
     useDynamicPort: true,
+    size: {
+      width: 360,
+      height: 305,
+    },
   },
   formMeta,
   onAdd() {

+ 4 - 0
apps/demo-free-layout/src/nodes/end/index.ts

@@ -8,6 +8,10 @@ export const EndNodeRegistry: FlowNodeRegistry = {
     deleteDisable: true,
     copyDisable: true,
     defaultPorts: [{ type: 'input' }],
+    size: {
+      width: 360,
+      height: 211,
+    },
   },
   info: {
     icon: iconEnd,

+ 6 - 0
apps/demo-free-layout/src/nodes/llm/index.ts

@@ -11,6 +11,12 @@ export const LLMNodeRegistry: FlowNodeRegistry = {
     description:
       'Call the large language model and use variables and prompt words to generate responses.',
   },
+  meta: {
+    size: {
+      width: 360,
+      height: 94,
+    },
+  },
   onAdd() {
     return {
       id: `llm_${nanoid(5)}`,

+ 4 - 0
apps/demo-free-layout/src/nodes/start/index.ts

@@ -9,6 +9,10 @@ export const StartNodeRegistry: FlowNodeRegistry = {
     deleteDisable: true,
     copyDisable: true,
     defaultPorts: [{ type: 'output' }],
+    size: {
+      width: 360,
+      height: 211,
+    },
   },
   info: {
     icon: iconStart,