feat(flows): 新增流程编辑器基础功能与相关组件

feat(backend): 添加流程模型与服务支持
feat(frontend): 实现流程编辑器UI与交互
feat(assets): 添加流程节点图标资源
feat(plugins): 实现上下文菜单和运行时插件
feat(components): 新增基础节点和侧边栏组件
feat(routes): 添加流程相关路由配置
feat(models): 创建流程和运行日志数据模型
feat(services): 实现流程服务层逻辑
feat(migration): 添加流程相关数据库迁移
feat(config): 更新前端配置支持流程编辑器
feat(utils): 增强axios错误处理和工具函数
This commit is contained in:
2025-09-15 00:27:13 +08:00
parent 9da3978f91
commit b0963e5e37
291 changed files with 17947 additions and 86 deletions

View File

@ -0,0 +1,84 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { NodePanelResult, WorkflowNodePanelService } from '@flowgram.ai/free-node-panel-plugin';
import {
Layer,
injectable,
inject,
FreeLayoutPluginContext,
WorkflowHoverService,
WorkflowNodeEntity,
WorkflowNodeJSON,
WorkflowSelectService,
WorkflowDocument,
PositionSchema,
WorkflowDragService,
} from '@flowgram.ai/free-layout-editor';
import { ContainerUtils } from '@flowgram.ai/free-container-plugin';
@injectable()
export class ContextMenuLayer extends Layer {
@inject(FreeLayoutPluginContext) ctx: FreeLayoutPluginContext;
@inject(WorkflowNodePanelService) nodePanelService: WorkflowNodePanelService;
@inject(WorkflowHoverService) hoverService: WorkflowHoverService;
@inject(WorkflowSelectService) selectService: WorkflowSelectService;
@inject(WorkflowDocument) document: WorkflowDocument;
@inject(WorkflowDragService) dragService: WorkflowDragService;
onReady() {
this.listenPlaygroundEvent('contextmenu', (e) => {
if (this.config.readonlyOrDisabled) return;
this.openNodePanel(e);
e.preventDefault();
e.stopPropagation();
});
}
openNodePanel(e: MouseEvent) {
const mousePos = this.getPosFromMouseEvent(e);
const containerNode = this.getContainerNode(mousePos);
this.nodePanelService.callNodePanel({
position: mousePos,
containerNode,
panelProps: {},
// handle node selection from panel - 处理从面板中选择节点
onSelect: async (panelParams?: NodePanelResult) => {
if (!panelParams) {
return;
}
const { nodeType, nodeJSON } = panelParams;
const position = this.dragService.adjustSubNodePosition(nodeType, containerNode, mousePos);
// create new workflow node based on selected type - 根据选择的类型创建新的工作流节点
const node: WorkflowNodeEntity = this.ctx.document.createWorkflowNodeByType(
nodeType,
position,
nodeJSON ?? ({} as WorkflowNodeJSON),
containerNode?.id
);
// select the newly created node - 选择新创建的节点
this.selectService.select(node);
},
// handle panel close - 处理面板关闭
onClose: () => {},
});
}
private getContainerNode(mousePos: PositionSchema): WorkflowNodeEntity | undefined {
const allNodes = this.document.getAllNodes();
const containerTransforms = ContainerUtils.getContainerTransforms(allNodes);
const collisionTransform = ContainerUtils.getCollisionTransform({
targetPoint: mousePos,
transforms: containerTransforms,
document: this.document,
});
return collisionTransform?.entity;
}
}

View File

@ -0,0 +1,28 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import {
definePluginCreator,
PluginCreator,
FreeLayoutPluginContext,
} from '@flowgram.ai/free-layout-editor';
import { ContextMenuLayer } from './context-menu-layer';
export interface ContextMenuPluginOptions {}
/**
* Creates a plugin of contextmenu
* @param ctx - The plugin context, containing the document and other relevant information.
* @param options - Plugin options, currently an empty object.
*/
export const createContextMenuPlugin: PluginCreator<ContextMenuPluginOptions> = definePluginCreator<
ContextMenuPluginOptions,
FreeLayoutPluginContext
>({
onInit(ctx, options) {
ctx.playground.registerLayer(ContextMenuLayer);
},
});

View File

@ -0,0 +1,6 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
export { createContextMenuPlugin } from './context-menu-plugin';