|
|
|
@ -163,6 +163,54 @@ const FlowEditorMain: React.FC<FlowEditorMainProps> = (props) => {
|
|
|
|
// 流程发布弹窗状态
|
|
|
|
// 流程发布弹窗状态
|
|
|
|
const [publishModalVisible, setPublishModalVisible] = React.useState(false);
|
|
|
|
const [publishModalVisible, setPublishModalVisible] = React.useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const selectedCopyableNodes = useMemo(
|
|
|
|
|
|
|
|
() =>
|
|
|
|
|
|
|
|
nodes.filter(
|
|
|
|
|
|
|
|
(node) =>
|
|
|
|
|
|
|
|
node.selected && node.type !== 'start' && node.type !== 'end'
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
[nodes]
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const selectedEdgeCount = useMemo(
|
|
|
|
|
|
|
|
() => edges.filter((edge) => edge.selected).length,
|
|
|
|
|
|
|
|
[edges]
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const hasMultiElementSelection =
|
|
|
|
|
|
|
|
selectedCopyableNodes.length > 1 || selectedEdgeCount > 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const copySelectedElements = React.useCallback(
|
|
|
|
|
|
|
|
(fallbackNode?: Node) => {
|
|
|
|
|
|
|
|
const shouldCopySelection =
|
|
|
|
|
|
|
|
selectedCopyableNodes.length > 0 &&
|
|
|
|
|
|
|
|
(!fallbackNode || fallbackNode.selected);
|
|
|
|
|
|
|
|
const nodeToCopy =
|
|
|
|
|
|
|
|
(shouldCopySelection ? selectedCopyableNodes[0] : undefined) ||
|
|
|
|
|
|
|
|
(fallbackNode?.type !== 'start' && fallbackNode?.type !== 'end'
|
|
|
|
|
|
|
|
? fallbackNode
|
|
|
|
|
|
|
|
: undefined);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!nodeToCopy) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
copyNode(nodeToCopy);
|
|
|
|
|
|
|
|
setIsEditModalOpen(false);
|
|
|
|
|
|
|
|
setMenu(null);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
[copyNode, selectedCopyableNodes, setIsEditModalOpen, setMenu]
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const contextNode =
|
|
|
|
|
|
|
|
menu?.type === 'node' ? nodes.find((node) => node.id === menu.id) : null;
|
|
|
|
|
|
|
|
const contextEdge =
|
|
|
|
|
|
|
|
menu?.type === 'edge' ? edges.find((edge) => edge.id === menu.id) : null;
|
|
|
|
|
|
|
|
const nodeContextCopiesSelection =
|
|
|
|
|
|
|
|
!!contextNode?.selected && hasMultiElementSelection;
|
|
|
|
|
|
|
|
const edgeContextCopiesSelection =
|
|
|
|
|
|
|
|
!!contextEdge?.selected && selectedCopyableNodes.length > 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 监听自定义事件以隐藏/显示节点
|
|
|
|
// 监听自定义事件以隐藏/显示节点
|
|
|
|
useEffect(() => {
|
|
|
|
useEffect(() => {
|
|
|
|
const handleToggleNodeVisibility = (event: CustomEvent) => {
|
|
|
|
const handleToggleNodeVisibility = (event: CustomEvent) => {
|
|
|
|
@ -255,12 +303,11 @@ const FlowEditorMain: React.FC<FlowEditorMainProps> = (props) => {
|
|
|
|
// Ctrl/Cmd+C 复制选中的节点
|
|
|
|
// Ctrl/Cmd+C 复制选中的节点
|
|
|
|
if (isModifierKey && e.key === 'c' && canEdit) {
|
|
|
|
if (isModifierKey && e.key === 'c' && canEdit) {
|
|
|
|
// 获取当前选中的节点
|
|
|
|
// 获取当前选中的节点
|
|
|
|
const selectedNode = nodes.find((node) => node.selected);
|
|
|
|
const selectedNode = nodes.find(
|
|
|
|
|
|
|
|
(node) =>
|
|
|
|
|
|
|
|
node.selected && node.type !== 'start' && node.type !== 'end'
|
|
|
|
|
|
|
|
);
|
|
|
|
if (selectedNode) {
|
|
|
|
if (selectedNode) {
|
|
|
|
// 不允许复制开始和结束节点
|
|
|
|
|
|
|
|
if (selectedNode.type === 'start' || selectedNode.type === 'end') {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
e.preventDefault();
|
|
|
|
copyNode(selectedNode);
|
|
|
|
copyNode(selectedNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -650,10 +697,11 @@ const FlowEditorMain: React.FC<FlowEditorMainProps> = (props) => {
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
>
|
|
|
|
<NodeContextMenu
|
|
|
|
<NodeContextMenu
|
|
|
|
node={nodes.find((n) => n.id === menu.id)!}
|
|
|
|
node={contextNode!}
|
|
|
|
onDelete={deleteNode}
|
|
|
|
onDelete={deleteNode}
|
|
|
|
onEdit={editNode}
|
|
|
|
onEdit={editNode}
|
|
|
|
onCopy={copyNode}
|
|
|
|
onCopy={copySelectedElements}
|
|
|
|
|
|
|
|
copyLabel={nodeContextCopiesSelection ? '复制选中内容' : '复制节点'}
|
|
|
|
onCloseMenu={setMenu}
|
|
|
|
onCloseMenu={setMenu}
|
|
|
|
onCloseOpenModal={setIsEditModalOpen}
|
|
|
|
onCloseOpenModal={setIsEditModalOpen}
|
|
|
|
isRunning={currentAppIsRunning}
|
|
|
|
isRunning={currentAppIsRunning}
|
|
|
|
@ -672,9 +720,13 @@ const FlowEditorMain: React.FC<FlowEditorMainProps> = (props) => {
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
>
|
|
|
|
<EdgeContextMenu
|
|
|
|
<EdgeContextMenu
|
|
|
|
edge={edges.find((e) => e.id === menu.id)!}
|
|
|
|
edge={contextEdge!}
|
|
|
|
onDelete={deleteEdge}
|
|
|
|
onDelete={deleteEdge}
|
|
|
|
onEdit={editEdge}
|
|
|
|
onEdit={editEdge}
|
|
|
|
|
|
|
|
onCopy={
|
|
|
|
|
|
|
|
edgeContextCopiesSelection ? () => copySelectedElements() : undefined
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
copyLabel="复制选中内容"
|
|
|
|
onAddNode={(edge) => {
|
|
|
|
onAddNode={(edge) => {
|
|
|
|
setEdgeForNodeAdd(edge);
|
|
|
|
setEdgeForNodeAdd(edge);
|
|
|
|
setIsEditModalOpen(false);
|
|
|
|
setIsEditModalOpen(false);
|
|
|
|
@ -696,6 +748,15 @@ const FlowEditorMain: React.FC<FlowEditorMainProps> = (props) => {
|
|
|
|
>
|
|
|
|
>
|
|
|
|
<PaneContextMenu
|
|
|
|
<PaneContextMenu
|
|
|
|
position={menu.position!}
|
|
|
|
position={menu.position!}
|
|
|
|
|
|
|
|
onCopySelection={
|
|
|
|
|
|
|
|
selectedCopyableNodes.length > 0
|
|
|
|
|
|
|
|
? () => copySelectedElements()
|
|
|
|
|
|
|
|
: undefined
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
onPasteNode={(position) => {
|
|
|
|
|
|
|
|
pasteNode(position);
|
|
|
|
|
|
|
|
setMenu(null);
|
|
|
|
|
|
|
|
}}
|
|
|
|
onAddNode={(
|
|
|
|
onAddNode={(
|
|
|
|
nodeType: string,
|
|
|
|
nodeType: string,
|
|
|
|
position: { x: number; y: number },
|
|
|
|
position: { x: number; y: number },
|
|
|
|
|