import type { HookHub, ICmdHooks as IHooks, NsGraph, IModelService } from '@antv/xflow'; import { Deferred, ManaSyringe } from '@antv/xflow'; import type { FormInstance } from 'antd'; import { Modal, Form, Input, ConfigProvider } from 'antd'; import type { IArgsBase, ICommandHandler, IGraphCommandService } from '@antv/xflow'; import { ICommandContextProvider } from '@antv/xflow'; import { CustomCommands } from './constants'; import 'antd/es/modal/style/index.css'; // prettier-ignore type ICommand = ICommandHandler; export namespace NsRenameNodeCmd { /** Command: 用于注册named factory */ // eslint-disable-next-line export const command = CustomCommands.SHOW_RENAME_MODAL; /** hook name */ // eslint-disable-next-line export const hookKey = 'renameNode'; /** hook 参数类型 */ export interface IArgs extends IArgsBase { nodeConfig: NsGraph.INodeConfig; updateNodeNameService: IUpdateNodeNameService; } export interface IUpdateNodeNameService { (newName: string, nodeConfig: NsGraph.INodeConfig, meta: NsGraph.IGraphMeta): Promise<{ err: string | null; nodeName: string; }>; } /** hook handler 返回类型 */ export interface IResult { err: string | null; preNodeName?: string; currentNodeName?: string; } /** hooks 类型 */ export interface ICmdHooks extends IHooks { renameNode: HookHub; } } @ManaSyringe.injectable() /** 部署画布数据 */ // prettier-ignore export class RenameNodeCommand implements ICommand { /** api */ @ManaSyringe.inject(ICommandContextProvider) contextProvider!: ICommand['contextProvider']; /** 执行Cmd */ execute = async () => { const ctx = this.contextProvider(); // const app = useXFlowApp(); const { args } = ctx.getArgs(); const hooks = ctx.getHooks(); const result = await hooks.renameNode.call(args, async (args) => { const { nodeConfig, graphMeta, commandService, modelService, updateNodeNameService } = args; const preNodeName = nodeConfig.label; const getAppContext: IGetAppCtx = () => { return { graphMeta, commandService, modelService, updateNodeNameService, }; }; const x6Graph = await ctx.getX6Graph(); const cell = x6Graph.getCellById(nodeConfig.id); const nodes = x6Graph.getNodes(); const edges = x6Graph.getEdges(); nodes.forEach((node) => { if (node !== cell) { x6Graph.removeCell(node); } }); edges.forEach((edge) => { x6Graph.removeEdge(edge); }); if (!cell || !cell.isNode()) { throw new Error(`${nodeConfig.id} is not a valid node`); } /** 通过modal 获取 new name */ const newName = await showModal(nodeConfig, getAppContext); /** 更新 node name */ if (newName) { const cellData = cell.getData(); cell.setData({ ...cellData, label: newName } as NsGraph.INodeConfig); return { err: null, preNodeName, currentNodeName: newName }; } return { err: null, preNodeName, currentNodeName: '' }; }); ctx.setResult(result); return this; }; /** undo cmd */ undo = async () => { if (this.isUndoable()) { const ctx = this.contextProvider(); ctx.undo(); } return this; }; /** redo cmd */ redo = async () => { if (!this.isUndoable()) { await this.execute(); } return this; }; isUndoable(): boolean { const ctx = this.contextProvider(); return ctx.isUndoable(); } } export interface IGetAppCtx { (): { graphMeta: NsGraph.IGraphMeta; commandService: IGraphCommandService; modelService: IModelService; updateNodeNameService: NsRenameNodeCmd.IUpdateNodeNameService; }; } export type IModalInstance = ReturnType; export interface IFormProps { newNodeName: string; } const layout = { labelCol: { span: 5 }, wrapperCol: { span: 19 }, }; function showModal(node: NsGraph.INodeConfig, getAppContext: IGetAppCtx) { /** showModal 返回一个Promise */ const defer = new Deferred(); /** modal确认保存逻辑 */ class ModalCache { static modal: IModalInstance; static form: FormInstance; } /** modal确认保存逻辑 */ const onOk = async () => { const { form, modal } = ModalCache; const appContext = getAppContext(); const { updateNodeNameService, graphMeta } = appContext; try { modal.update({ okButtonProps: { loading: true } }); await form.validateFields(); const values = await form.getFieldsValue(); const newName: string = values.newNodeName; /** 执行 backend service */ if (updateNodeNameService) { const { err, nodeName } = await updateNodeNameService(newName, node, graphMeta); if (err) { throw new Error(err); } defer.resolve(nodeName); } /** 更新成功后,关闭modal */ onHide(); } catch (error) { console.error(error); /** 如果resolve空字符串则不更新 */ modal.update({ okButtonProps: { loading: false } }); } }; /** modal销毁逻辑 */ const onHide = () => { modal.destroy(); ModalCache.form = null as any; ModalCache.modal = null as any; container.destroy(); }; /** modal内容 */ const ModalContent = () => { const [form] = Form.useForm(); /** 缓存form实例 */ ModalCache.form = form; return (
); }; /** 创建modal dom容器 */ const container = createContainer(); /** 创建modal */ const modal = Modal.confirm({ title: '重命名', content: , getContainer: () => { return container.element; }, okButtonProps: { onClick: (e) => { e.stopPropagation(); onOk(); }, }, onCancel: () => { onHide(); }, afterClose: () => { onHide(); }, }); /** 缓存modal实例 */ ModalCache.modal = modal; /** showModal 返回一个Promise,用于await */ return defer.promise; } const createContainer = () => { const div = document.createElement('div'); div.classList.add('xflow-modal-container'); window.document.body.append(div); return { element: div, destroy: () => { window.document.body.removeChild(div); }, }; };