2 Commits

3 changed files with 128 additions and 114 deletions

View File

@@ -1,5 +1,5 @@
import {PlusCircleFilled, RollbackOutlined, SaveFilled} from '@ant-design/icons'
import {Background, BackgroundVariant, Controls, MiniMap, ReactFlow} from '@xyflow/react'
import {Background, BackgroundVariant, Controls, MiniMap, Panel, ReactFlow} from '@xyflow/react'
import {Button, Dropdown, message, Popconfirm, Space} from 'antd'
import {arrToMap, isEqual, randomId, unique} from 'licia'
import {useEffect} from 'react'
@@ -34,13 +34,6 @@ const FlowableDiv = styled.div`
}
}
.toolbar {
position: absolute;
right: 20px;
top: 20px;
z-index: 10;
}
.node-card {
cursor: default;
@@ -85,80 +78,6 @@ function FlowEditor(props: FlowEditorProps) {
return (
<FlowableDiv className="h-full w-full">
{contextHolder}
<Space className="toolbar">
<Dropdown
menu={{
items: unique(NodeRegistry.map(i => i.group))
.map(group => ({
type: 'group',
label: group,
children: NodeRegistry.filter(i => isEqual(group, i.group))
.map(i => ({key: i.key, label: i.name, icon: i.icon})),
})),
onClick: ({key}) => {
try {
if (commonInfo.debug) {
console.info('Add', key, JSON.stringify({nodes, edges, data}))
}
checkAddNode(key, nodes, edges)
let nodeId = randomId(10, 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM')
let define = NodeRegistryMap[key]
setDataById(
nodeId,
{
node: {
name: define.name,
description: define.description,
},
},
)
addNode({
id: nodeId,
type: key,
position: {x: 100, y: 100},
data: {},
})
} catch (e) {
// @ts-ignore
messageApi.error(e.toString())
}
},
}}
>
<Button type="default">
<PlusCircleFilled/>
</Button>
</Dropdown>
<Popconfirm
title="返回上一页"
description="未保存的流程图将会被丢弃,确认是否返回"
onConfirm={() => navigate(-1)}
>
<Button type="default">
<RollbackOutlined/>
</Button>
</Popconfirm>
<Button type="primary" onClick={() => {
try {
if (commonInfo.debug) {
console.info('Save', JSON.stringify({nodes, edges, data}))
}
checkSave(inputSchema, nodes, edges, data)
props.onGraphDataChange({nodes, edges, data})
} catch (e) {
// @ts-ignore
messageApi.error(e.toString())
}
}}>
<SaveFilled/>
</Button>
</Space>
<ReactFlow
nodes={nodes}
edges={edges}
@@ -179,6 +98,82 @@ function FlowEditor(props: FlowEditorProps) {
// @ts-ignore
nodeTypes={arrToMap(Object.keys(NodeRegistryMap), key => NodeRegistryMap[key]!.component)}
>
<Panel position="top-right">
<Space className="toolbar">
<Dropdown
menu={{
items: unique(NodeRegistry.map(i => i.group))
.map(group => ({
type: 'group',
label: group,
children: NodeRegistry.filter(i => isEqual(group, i.group))
.map(i => ({key: i.key, label: i.name, icon: i.icon})),
})),
onClick: ({key}) => {
try {
if (commonInfo.debug) {
console.info('Add', key, JSON.stringify({nodes, edges, data}))
}
checkAddNode(key, nodes, edges)
let nodeId = randomId(10, 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM')
let define = NodeRegistryMap[key]
setDataById(
nodeId,
{
node: {
name: define.name,
description: define.description,
},
},
)
addNode({
id: nodeId,
type: key,
position: {x: 100, y: 100},
data: {},
})
} catch (e) {
// @ts-ignore
messageApi.error(e.toString())
}
},
}}
>
<Button type="default">
<PlusCircleFilled/>
</Button>
</Dropdown>
<Popconfirm
title="返回上一页"
description="未保存的流程图将会被丢弃,确认是否返回"
onConfirm={() => navigate(-1)}
>
<Button type="default">
<RollbackOutlined/>
</Button>
</Popconfirm>
<Button type="primary" onClick={() => {
try {
if (commonInfo.debug) {
console.info('Save', JSON.stringify({nodes, edges, data}))
}
checkSave(inputSchema, nodes, edges, data)
props.onGraphDataChange({nodes, edges, data})
} catch (e) {
// @ts-ignore
messageApi.error(e.toString())
}
}}>
<SaveFilled/>
</Button>
</Space>
</Panel>
<Controls/>
<MiniMap/>
<Background variant={BackgroundVariant.Cross} gap={20} size={3}/>

View File

@@ -1,7 +1,7 @@
import {CopyFilled, DeleteFilled, EditFilled} from '@ant-design/icons'
import {type Edge, Handle, type Node, type NodeProps, Position} from '@xyflow/react'
import {type Edge, Handle, type Node, type NodeProps, NodeToolbar, Position} from '@xyflow/react'
import type {Schema} from 'amis'
import {Button, Card, Drawer} from 'antd'
import {Button, Card, Drawer, Space, Tooltip} from 'antd'
import {type JSX, useCallback, useState} from 'react'
import styled from 'styled-components'
import {amisRender, commonInfo, horizontalFormOptions} from '../../../util/amis.tsx'
@@ -247,37 +247,42 @@ const AmisNode: (props: AmisNodeProps) => JSX.Element = ({
>
{editDrawerForm}
</Drawer>
<NodeToolbar>
<Space>
<Tooltip title="复制节点">
<Button
className="text-secondary"
disabled
type="text"
size="small"
icon={<CopyFilled/>}
/>
</Tooltip>
<Tooltip title="编辑节点">
<Button
className="text-secondary"
type="text"
size="small"
icon={<EditFilled/>}
onClick={() => onOpenEditDrawerClick()}
/>
</Tooltip>
<Tooltip title="删除节点">
<Button
className="text-secondary"
type="text"
size="small"
icon={<DeleteFilled/>}
onClick={() => onRemoveClick()}
/>
</Tooltip>
</Space>
</NodeToolbar>
<Card
className="node-card"
title={nodeName}
extra={<span className="text-gray-300 text-xs">{id}</span>}
size="small"
actions={[
<Button
className="text-secondary"
disabled
type="text"
size="small"
icon={<CopyFilled/>}
block
/>,
<Button
className="text-secondary"
type="text"
size="small"
icon={<EditFilled/>}
block
onClick={() => onOpenEditDrawerClick()}
/>,
<Button
className="text-secondary"
type="text"
size="small"
icon={<DeleteFilled/>}
block
onClick={() => onRemoveClick()}
/>,
]}
>
<div className="card-description p-2 text-secondary text-sm">
{nodeDescription}

View File

@@ -1,10 +1,10 @@
import type {NodeProps} from '@xyflow/react'
import {Tag} from 'antd'
import React, {useCallback} from 'react'
import React, {useCallback, useEffect} from 'react'
import {useContextStore} from '../store/ContextStore.ts'
import {useDataStore} from '../store/DataStore.ts'
import {useFlowStore} from '../store/FlowStore.ts'
import AmisNode, {EndNodeHandler, inputsFormColumns} from './AmisNode.tsx'
import AmisNode, {inputsFormColumns, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
const typeMap: Record<string, string> = {
default: '默认',
@@ -15,11 +15,24 @@ const typeMap: Record<string, string> = {
const TemplateNode = (props: NodeProps) => {
const {getNodes, getEdges} = useFlowStore()
const {getData, getDataById} = useDataStore()
const {getData, getDataById, mergeDataById} = useDataStore()
const {getInputSchema} = useContextStore()
const nodeData = getDataById(props.id)
useEffect(() => {
mergeDataById(
props.id,
{
outputs: {
text: {
type: 'string',
},
},
},
)
}, [props.id])
const columnsSchema = useCallback(
() => [
...inputsFormColumns(props.id, getInputSchema(), getNodes(), getEdges(), getData()),
@@ -55,6 +68,7 @@ const TemplateNode = (props: NodeProps) => {
min_height: 500,
},
},
...outputsFormColumns(false, true),
],
[props.id],
)
@@ -71,7 +85,7 @@ const TemplateNode = (props: NodeProps) => {
: <></>
}
columnSchema={columnsSchema}
handler={<EndNodeHandler/>}
handler={<NormalNodeHandler/>}
/>
)
}