@nocobase/flow-engine
Version:
A standalone flow engine for NocoBase, managing workflows, models, and actions.
1,134 lines (1,127 loc) • 42 kB
JavaScript
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __typeError = (msg) => {
throw TypeError(msg);
};
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
var flowModel_exports = {};
__export(flowModel_exports, {
ErrorFlowModel: () => ErrorFlowModel,
FlowModel: () => FlowModel,
ModelRenderMode: () => ModelRenderMode,
defineFlow: () => defineFlow
});
module.exports = __toCommonJS(flowModel_exports);
var import_reactive = require("@formily/reactive");
var import_reactive_react = require("@formily/reactive-react");
var import_lodash = __toESM(require("lodash"));
var import_react = __toESM(require("react"));
var import_secure = require("uid/secure");
var import_StepRequiredSettingsDialog = require("../components/settings/wrappers/contextual/StepRequiredSettingsDialog");
var import_StepSettingsDialog = require("../components/settings/wrappers/contextual/StepSettingsDialog");
var import_emitter = require("../emitter");
var import_InstanceFlowRegistry = require("../flow-registry/InstanceFlowRegistry");
var import_flowContext = require("../flowContext");
var import_flowEngine = require("../flowEngine");
var import_utils = require("../utils");
var import_lib = require("antd/lib");
var import_ModelActionRegistry = require("../action-registry/ModelActionRegistry");
var import_utils2 = require("../components/subModel/utils");
var import_ModelEventRegistry = require("../event-registry/ModelEventRegistry");
var import_GlobalFlowRegistry = require("../flow-registry/GlobalFlowRegistry");
var import_forkFlowModel = require("./forkFlowModel");
var _flowContext;
const classActionRegistries = /* @__PURE__ */ new WeakMap();
const classEventRegistries = /* @__PURE__ */ new WeakMap();
const modelMetas = /* @__PURE__ */ new WeakMap();
const modelGlobalRegistries = /* @__PURE__ */ new WeakMap();
var ModelRenderMode = /* @__PURE__ */ ((ModelRenderMode2) => {
ModelRenderMode2["ReactElement"] = "reactElement";
ModelRenderMode2["RenderFunction"] = "renderFunction";
return ModelRenderMode2;
})(ModelRenderMode || {});
const _FlowModel = class _FlowModel {
constructor(options) {
__publicField(this, "uid");
__publicField(this, "sortIndex");
__publicField(this, "hidden", false);
__publicField(this, "props", {});
__publicField(this, "stepParams", {});
__publicField(this, "flowEngine");
__publicField(this, "parent");
__publicField(this, "subModels");
__publicField(this, "_options");
__publicField(this, "_title");
__publicField(this, "isNew", false);
// 标记是否为新建状态
/**
* 所有 fork 实例的引用集合。
* 使用 Set 便于在销毁时主动遍历并调用 dispose,避免悬挂引用。
*/
__publicField(this, "forks", /* @__PURE__ */ new Set());
__publicField(this, "emitter", new import_emitter.Emitter());
/**
* 基于 key 的 fork 实例缓存,用于复用 fork 实例
*/
__publicField(this, "forkCache", /* @__PURE__ */ new Map());
/**
* 上一次 applyAutoFlows 的执行参数
*/
__publicField(this, "_lastAutoRunParams", null);
__publicField(this, "observerDispose");
__privateAdd(this, _flowContext);
/**
* 原始 render 方法的引用
*/
__publicField(this, "_originalRender", null);
/**
* 缓存的响应式包装器组件(每个实例一个)
*/
__publicField(this, "_reactiveWrapperCache");
__publicField(this, "flowRegistry");
__publicField(this, "_cleanRun");
__publicField(this, "_dispatchEventWithDebounce", import_lodash.default.debounce(async (eventName, inputArgs) => {
return this._dispatchEvent(eventName, inputArgs);
}, 100));
/**
* 重新执行上一次的 applyAutoFlows,保持参数一致
* 如果之前没有执行过,则直接跳过
* 使用 lodash debounce 避免频繁调用
*/
__publicField(this, "_rerunLastAutoRun", import_lodash.default.debounce(async () => {
if (this._lastAutoRunParams) {
try {
await this.applyAutoFlows(...this._lastAutoRunParams);
} catch (error) {
console.error("FlowModel._rerunLastAutoRun: Error during rerun:", error);
}
}
}, 100));
if (!options.flowEngine) {
throw new Error("FlowModel must be initialized with a FlowEngine instance.");
}
this.flowEngine = options.flowEngine;
if (this.flowEngine.getModel(options.uid)) {
return this.flowEngine.getModel(options.uid);
}
if (!options.uid) {
options.uid = (0, import_secure.uid)();
}
this.uid = options.uid;
this.props = {
...options.props
};
this.stepParams = options.stepParams || {};
this.subModels = {};
this.sortIndex = options.sortIndex || 0;
this._options = options;
(0, import_reactive.define)(this, {
hidden: import_reactive.observable,
props: import_reactive.observable,
subModels: import_reactive.observable.shallow,
stepParams: import_reactive.observable,
// setProps: action,
setProps: import_reactive.batch,
// setStepParams: action,
setStepParams: import_reactive.batch
});
this.flowRegistry = new import_InstanceFlowRegistry.InstanceFlowRegistry(this);
this.flowRegistry.addFlows(options.flowRegistry);
this.observerDispose = (0, import_reactive.observe)(this.stepParams, (changed) => {
if (changed.type === "set" && import_lodash.default.isEqual(changed.value, changed.oldValue)) {
return;
}
if (this.flowEngine) {
this.invalidateAutoFlowCache();
}
this._rerunLastAutoRun();
this.forks.forEach((fork) => {
fork.rerender();
});
});
try {
this.setupReactiveRender();
} catch (error) {
console.error(`Failed to setup reactive render for ${this.constructor.name}:`, error);
if (typeof this.render !== "function") {
this.render = () => import_react.default.createElement("div", null, "Render method not available");
}
}
this._cleanRun = !!options["cleanRun"];
}
/**
* 当 flowSettings.enabled 且 model.hidden 为 true 时用于渲染设置态组件(实例方法,子类可覆盖)。
* 基类默认仅返回一个透明度降低的占位元素
*/
renderHiddenInConfig() {
var _a;
return /* @__PURE__ */ import_react.default.createElement("span", { style: { opacity: 0.5 } }, ((_a = this.translate) == null ? void 0 : _a.call(this, "Hidden")) || "Hidden");
}
/**
* 对外暴露的上下文:
*/
get context() {
if (!__privateGet(this, _flowContext)) {
__privateSet(this, _flowContext, new import_flowContext.FlowModelContext(this));
}
return __privateGet(this, _flowContext);
}
on(eventName, listener) {
this.emitter.on(eventName, listener);
}
onInit(options) {
}
/**
* 通过 AddSubModelButton 添加为子模型后调用(子类可覆盖)
*/
async afterAddAsSubModel() {
}
get async() {
return this._options.async || false;
}
get use() {
return this._options.use;
}
get subKey() {
return this._options.subKey;
}
get subType() {
return this._options.subType;
}
get reactView() {
return this.flowEngine.reactView;
}
get parentId() {
return this._options.parentId;
}
static get meta() {
return modelMetas.get(this);
}
static get globalFlowRegistry() {
const Cls = this;
let reg = modelGlobalRegistries.get(Cls);
if (!reg) {
reg = new import_GlobalFlowRegistry.GlobalFlowRegistry(Cls);
modelGlobalRegistries.set(Cls, reg);
}
return reg;
}
// 获取当前类的动作注册表(含父子链注入),按类缓存
static get actionRegistry() {
const ModelClass = this;
let registry = classActionRegistries.get(ModelClass);
if (!registry) {
let parentRegistry = null;
const ParentClass = Object.getPrototypeOf(ModelClass);
if (ParentClass && ParentClass !== Function.prototype && ParentClass !== Object.prototype) {
const isSubclassOfFlowModel = ParentClass === _FlowModel || (0, import_utils.isInheritedFrom)(ParentClass, _FlowModel);
if (isSubclassOfFlowModel) {
parentRegistry = ParentClass.actionRegistry;
}
}
registry = new import_ModelActionRegistry.ModelActionRegistry(ModelClass, parentRegistry);
classActionRegistries.set(ModelClass, registry);
}
return registry;
}
// 获取当前类的事件注册表(含父子链注入),按类缓存
static get eventRegistry() {
const ModelClass = this;
let registry = classEventRegistries.get(ModelClass);
if (!registry) {
let parentRegistry = null;
const ParentClass = Object.getPrototypeOf(ModelClass);
if (ParentClass && ParentClass !== Function.prototype && ParentClass !== Object.prototype) {
const isSubclassOfFlowModel = ParentClass === _FlowModel || (0, import_utils.isInheritedFrom)(ParentClass, _FlowModel);
if (isSubclassOfFlowModel) {
parentRegistry = ParentClass.eventRegistry;
}
}
registry = new import_ModelEventRegistry.ModelEventRegistry(ModelClass, parentRegistry);
classEventRegistries.set(ModelClass, registry);
}
return registry;
}
/**
* 注册仅当前 FlowModel 类及其子类可用的 Action。
* 该注册是类级别的,不会影响全局(FlowEngine)的 Action 注册。
*/
static registerAction(definition) {
this.actionRegistry.registerAction(definition);
}
/**
* 批量注册仅当前 FlowModel 类及其子类可用的 Actions。
*/
static registerActions(actions) {
this.actionRegistry.registerActions(actions);
}
/**
* 注册仅当前 FlowModel 类及其子类可用的 Event。
* 该注册是类级别的,不会影响全局(FlowEngine)的 Event 注册。
*/
static registerEvent(definition) {
this.eventRegistry.registerEvent(definition);
}
/**
* 批量注册仅当前 FlowModel 类及其子类可用的 Events。
*/
static registerEvents(events) {
this.eventRegistry.registerEvents(events);
}
static buildChildrenFromModels(ctx, Models) {
return Models.map((M) => (0, import_utils2.buildSubModelItem)(M, ctx, true));
}
get title() {
var _a;
return this.translate(this._title) || this.translate((_a = this.constructor["meta"]) == null ? void 0 : _a.label);
}
setTitle(value) {
this._title = value;
}
setHidden(value) {
this.hidden = !!value;
}
_createSubModels(subModels) {
let mergedSubModels = subModels || {};
try {
const Cls = this.constructor;
const meta = Cls.meta;
const metaCreate = meta == null ? void 0 : meta.createModelOptions;
if (metaCreate && typeof metaCreate === "object" && metaCreate.subModels) {
mergedSubModels = import_lodash.default.merge({}, import_lodash.default.cloneDeep(metaCreate.subModels || {}), import_lodash.default.cloneDeep(subModels || {}));
}
} catch (e) {
}
Object.entries(mergedSubModels || {}).forEach(([key, value]) => {
if (Array.isArray(value)) {
value.sort((a, b) => (a.sortIndex || 0) - (b.sortIndex || 0)).forEach((item) => {
this.addSubModel(key, item);
});
} else {
this.setSubModel(key, value);
}
});
}
invalidateAutoFlowCache(deep = false) {
if (this.flowEngine) {
const cacheKey = import_flowEngine.FlowEngine.generateApplyFlowCacheKey("autoFlow", "all", this.uid);
this.flowEngine.applyFlowCache.delete(cacheKey);
this.forks.forEach((fork) => {
const forkCacheKey = import_flowEngine.FlowEngine.generateApplyFlowCacheKey(`${fork["forkId"]}`, "all", this.uid);
this.flowEngine.applyFlowCache.delete(forkCacheKey);
});
}
if (deep) {
const subModelKeys = Object.keys(this.subModels);
for (const subModelKey of subModelKeys) {
const subModelValue = this.subModels[subModelKey];
if (Array.isArray(subModelValue)) {
for (const subModel of subModelValue) {
subModel.invalidateAutoFlowCache(deep);
}
} else if (subModelValue instanceof _FlowModel) {
subModelValue.invalidateAutoFlowCache(deep);
}
}
}
}
/**
* 设置FlowEngine实例
* @param {FlowEngine} flowEngine FlowEngine实例
*/
setFlowEngine(flowEngine) {
}
static define(meta) {
modelMetas.set(this, meta);
}
/**
* 注册一个 Flow。
* @template TModel 具体的FlowModel子类类型
* @param {string | FlowDefinitionOptions<TModel>} keyOrDefinition 流程的 Key 或 FlowDefinitionOptions 对象。
* 如果为字符串,则为流程 Key,需要配合 flowDefinition 参数。
* 如果为对象,则为包含 key 属性的完整 FlowDefinitionOptions。
* @param {FlowDefinitionOptions<TModel>} [flowDefinition] 当第一个参数为流程 Key 时,此参数为流程的定义。
* @returns {void}
*/
static registerFlow(keyOrDefinition, flowDefinition) {
const Cls = this;
if (typeof keyOrDefinition === "string") {
Cls.globalFlowRegistry.addFlow(keyOrDefinition, flowDefinition);
} else {
Cls.globalFlowRegistry.addFlow(keyOrDefinition.key, keyOrDefinition);
}
}
// /**
// * 清空所有注册的流程定义。在测试中用来清理已注册的流,防止对其它测试产生影响。
// */
// public static clearFlows(): void {
// modelFlows = new WeakMap<typeof FlowModel, Map<string, FlowDefinition>>();
// }
/**
* 获取已注册的流程定义。
* 如果当前类不存在对应的flow,会继续往父类查找。
* @param {string} key 流程 Key。
* @returns {FlowDefinition | undefined} 流程定义,如果未找到则返回 undefined。
*/
getFlow(key) {
if (this.flowRegistry.hasFlow(key)) {
return this.flowRegistry.getFlow(key);
}
const Cls = this.constructor;
return Cls.globalFlowRegistry.getFlow(key);
}
/**
* 注册一个实例级别的流程定义。
* @template TModel 具体的FlowModel子类类型
* @param {string | FlowDefinitionOptions<TModel>} keyOrDefinition 流程的 Key 或 FlowDefinitionOptions 对象。
* @param {FlowDefinitionOptions<TModel>} [flowDefinition] 当第一个参数为流程 Key 时,此参数为流程的定义。
* @returns {FlowDefinition} 注册的流程定义实例
*/
registerFlow(keyOrDefinition, flowDefinition) {
if (typeof keyOrDefinition === "string") {
return this.flowRegistry.addFlow(keyOrDefinition, flowDefinition);
} else {
return this.flowRegistry.addFlow(keyOrDefinition.key, keyOrDefinition);
}
}
/**
* 获取当前模型可用的所有 Actions:
* - 包含全局(FlowEngine)注册的 Actions;
* - 合并类级(FlowModel.registerAction(s))注册的 Actions,并考虑继承(子类覆盖父类同名 Action)。
*/
getActions() {
var _a;
const ModelClass = this.constructor;
const merged = ModelClass.actionRegistry.getActions();
const actions = /* @__PURE__ */ new Map();
const globalActions = (_a = this.flowEngine) == null ? void 0 : _a.getActions();
if (globalActions) for (const [k, v] of globalActions) actions.set(k, v);
for (const [k, v] of merged) actions.set(k, v);
return actions;
}
/**
* 获取当前模型可用的所有 Events:
* - 包含全局(FlowEngine)注册的 Events;
* - 合并类级(FlowModel.registerEvent(s))注册的 Events,并考虑继承(子类覆盖父类同名 Event)。
*/
getEvents() {
var _a;
const ModelClass = this.constructor;
const merged = ModelClass.eventRegistry.getEvents();
const events = /* @__PURE__ */ new Map();
const globalEvents = (_a = this.flowEngine) == null ? void 0 : _a.getEvents();
if (globalEvents) for (const [k, v] of globalEvents) events.set(k, v);
for (const [k, v] of merged) events.set(k, v);
return events;
}
/**
* 获取指定名称的 Event(优先返回类级注册的,未找到则回退到全局)。
*/
getEvent(name) {
var _a;
const ModelClass = this.constructor;
const own = ModelClass.eventRegistry.getEvent(name);
if (own) return own;
return (_a = this.flowEngine) == null ? void 0 : _a.getEvent(name);
}
/**
* 获取指定名称的 Action(优先返回类级注册的,未找到则回退到全局)。
*/
getAction(name) {
var _a;
const ModelClass = this.constructor;
const own = ModelClass.actionRegistry.getAction(name);
if (own) return own;
return (_a = this.flowEngine) == null ? void 0 : _a.getAction(name);
}
getFlows() {
const instanceFlows = this.flowRegistry.getFlows();
const staticFlows = this.constructor.globalFlowRegistry.getFlows();
const instanceKeys = new Set(instanceFlows.keys());
const staticEntries = Array.from(staticFlows.entries()).filter(([key]) => !instanceKeys.has(key));
const instanceEntries = Array.from(instanceFlows.entries());
const allEntries = [...staticEntries, ...instanceEntries];
allEntries.sort(([, a], [, b]) => {
const sa = a.sort ?? 0;
const sb = b.sort ?? 0;
if (sa !== sb) return sa - sb;
return 0;
});
return new Map(allEntries);
}
setProps(props, value) {
if (typeof props === "string") {
this.props[props] = value;
} else {
this.props = { ...this.props, ...props };
}
}
getProps() {
return this.props;
}
setStepParams(flowKeyOrAllParams, stepKeyOrStepsParams, params) {
if (typeof flowKeyOrAllParams === "string") {
const flowKey = flowKeyOrAllParams;
if (typeof stepKeyOrStepsParams === "string" && params !== void 0) {
if (!this.stepParams[flowKey]) {
this.stepParams[flowKey] = {};
}
this.stepParams[flowKey][stepKeyOrStepsParams] = {
...this.stepParams[flowKey][stepKeyOrStepsParams],
...params
};
} else if (typeof stepKeyOrStepsParams === "object" && stepKeyOrStepsParams !== null) {
this.stepParams[flowKey] = { ...this.stepParams[flowKey] || {}, ...stepKeyOrStepsParams };
}
} else if (typeof flowKeyOrAllParams === "object" && flowKeyOrAllParams !== null) {
for (const fk in flowKeyOrAllParams) {
if (Object.prototype.hasOwnProperty.call(flowKeyOrAllParams, fk)) {
this.stepParams[fk] = { ...this.stepParams[fk] || {}, ...flowKeyOrAllParams[fk] };
}
}
}
}
getStepParams(flowKey, stepKey) {
var _a;
if (flowKey && stepKey) {
return (_a = this.stepParams[flowKey]) == null ? void 0 : _a[stepKey];
}
if (flowKey) {
return this.stepParams[flowKey];
}
return this.stepParams;
}
async applyFlow(flowKey, inputArgs, runId) {
const currentFlowEngine = this.flowEngine;
if (!currentFlowEngine) {
console.warn("FlowEngine not available on this model for applyFlow. Check and model.flowEngine setup.");
return Promise.reject(new Error("FlowEngine not available for applyFlow. Please set flowEngine on the model."));
}
const isFork = this.isFork === true;
const target = this;
console.log(
`[FlowModel] applyFlow: uid=${this.uid}, flowKey=${flowKey}, isFork=${isFork}, cleanRun=${this.cleanRun}, targetIsFork=${(target == null ? void 0 : target.isFork) === true}`
);
return currentFlowEngine.executor.runFlow(target, flowKey, inputArgs, runId);
}
async _dispatchEvent(eventName, inputArgs) {
const currentFlowEngine = this.flowEngine;
if (!currentFlowEngine) {
console.warn("FlowEngine not available on this model for dispatchEvent. Please set flowEngine on the model.");
return;
}
const isFork = this.isFork === true;
const target = this;
console.log(
`[FlowModel] dispatchEvent: uid=${this.uid}, event=${eventName}, isFork=${isFork}, cleanRun=${this.cleanRun}, targetIsFork=${(target == null ? void 0 : target.isFork) === true}`
);
await currentFlowEngine.executor.dispatchEvent(target, eventName, inputArgs);
}
async dispatchEvent(eventName, inputArgs, options) {
if (options == null ? void 0 : options.debounce) {
return this._dispatchEventWithDebounce(eventName, inputArgs);
}
return this._dispatchEvent(eventName, inputArgs);
}
/**
* 获取所有自动应用流程定义(保持 getFlows 的顺序,即按 sort 排序)
* @returns {FlowDefinition[]} 自动应用流程定义数组(已按 sort 排序)
*/
getAutoFlows() {
const allFlows = this.getFlows();
const autoFlows = Array.from(allFlows.values()).filter((flow) => {
if (flow.on) {
return false;
}
if (flow.manual === true) {
return false;
}
return true;
});
return autoFlows;
}
/**
* 自动流程执行前钩子。
* 子类可覆盖;可抛出 FlowExitException 提前终止。
*/
async onBeforeAutoFlows(inputArgs) {
}
/**
* 自动流程执行后钩子。
* 子类可覆盖。
*/
async onAfterAutoFlows(results, inputArgs) {
}
/**
* 自动流程错误钩子。
* 子类可覆盖。
*/
async onAutoFlowsError(error, inputArgs) {
}
useHooksBeforeRender() {
}
async applyAutoFlows(...args) {
var _a, _b;
const [inputArgs, useCache = true] = args;
const cacheKey = useCache ? import_flowEngine.FlowEngine.generateApplyFlowCacheKey(this["forkId"] ?? "autoFlow", "all", this.uid) : null;
if (!import_lodash.default.isEqual(inputArgs, (_a = this._lastAutoRunParams) == null ? void 0 : _a[0]) && cacheKey) {
this.flowEngine.applyFlowCache.delete(cacheKey);
}
this._lastAutoRunParams = args;
try {
await this.onBeforeAutoFlows(inputArgs);
} catch (error) {
if (error instanceof import_utils.FlowExitException) {
(_b = this.context.logger) == null ? void 0 : _b.debug(`[FlowModel.applyAutoFlows] ${error.message}`);
return [];
}
try {
await this.onAutoFlowsError(error, inputArgs);
} catch (_2) {
}
throw error;
}
let results = [];
try {
results = await this.flowEngine.executor.runAutoFlows(this, inputArgs, useCache);
} catch (error) {
try {
await this.onAutoFlowsError(error, inputArgs);
} catch (_2) {
}
throw error;
}
try {
await this.onAfterAutoFlows(results, inputArgs);
} catch (error) {
try {
await this.onAutoFlowsError(error, inputArgs);
} catch (_2) {
}
throw error;
}
return results;
}
/**
* 智能检测是否应该跳过响应式包装
* 说明:
* - 仅基于标记判断,不会执行 render,避免出现“预调用 render”带来的副作用和双调用问题。
* - 当子类需要返回函数(如表格列的单元格渲染器),应在子类上设置静态属性 `renderReturnsFunction = true`。
*/
shouldSkipReactiveWrapping() {
if (this.render.__isReactiveWrapped) {
return true;
}
const Cls = this.constructor;
if (Cls.renderMode === "renderFunction" /* RenderFunction */) {
return true;
}
return false;
}
/**
* 设置 render 方法的响应式包装
* @private
*/
setupReactiveRender() {
if (typeof this.render !== "function") {
return;
}
try {
const originalRender = this.render;
this._originalRender = originalRender;
if (typeof originalRender !== "function") {
console.error(`FlowModel ${this.constructor.name}: original render method is not a function`, originalRender);
return;
}
if (this.shouldSkipReactiveWrapping()) {
const wrappedNonReactive = /* @__PURE__ */ __name(function() {
var _a, _b, _c;
const isConfigMode = !!((_b = (_a = this == null ? void 0 : this.flowEngine) == null ? void 0 : _a.flowSettings) == null ? void 0 : _b.enabled);
if (this.hidden) {
if (!isConfigMode) return null;
const rendered = (_c = this.renderHiddenInConfig) == null ? void 0 : _c.call(this);
const Cls = this.constructor;
const returnsFunction = Cls.renderMode === "renderFunction" /* RenderFunction */;
return returnsFunction ? typeof rendered === "function" ? rendered : () => rendered : rendered;
}
return originalRender.call(this);
}, "wrappedNonReactive");
wrappedNonReactive.__originalRender = originalRender;
this.render = wrappedNonReactive;
return;
}
const createReactiveWrapper = /* @__PURE__ */ __name((modelInstance) => {
const ReactiveWrapper = (0, import_reactive_react.observer)(() => {
var _a, _b, _c;
const renderTarget = modelInstance;
if (renderTarget !== modelInstance && (renderTarget == null ? void 0 : renderTarget.localProps) !== void 0) {
renderTarget.localProps;
modelInstance.props;
} else {
modelInstance.props;
}
import_react.default.useEffect(() => {
if (typeof renderTarget.onMount === "function") {
renderTarget.onMount();
}
return () => {
if (typeof renderTarget.onUnmount === "function") {
renderTarget.onUnmount();
}
};
}, [renderTarget]);
const isConfigMode = !!((_b = (_a = modelInstance == null ? void 0 : modelInstance.flowEngine) == null ? void 0 : _a.flowSettings) == null ? void 0 : _b.enabled);
if (modelInstance.hidden) {
if (!isConfigMode) {
return null;
}
return (_c = modelInstance.renderHiddenInConfig) == null ? void 0 : _c.call(modelInstance);
}
return originalRender.call(renderTarget);
});
ReactiveWrapper.displayName = `ReactiveWrapper(${modelInstance.constructor.name})`;
return ReactiveWrapper;
}, "createReactiveWrapper");
const wrappedRender = /* @__PURE__ */ __name(function() {
if (!this._reactiveWrapperCache) {
this._reactiveWrapperCache = createReactiveWrapper(this);
}
return import_react.default.createElement(this._reactiveWrapperCache);
}, "wrappedRender");
wrappedRender.__isReactiveWrapped = true;
wrappedRender.__originalRender = originalRender;
this.render = wrappedRender;
} catch (error) {
console.error(`FlowModel ${this.constructor.name}: Error during render method wrapping:`, error);
}
}
get cleanRun() {
return true;
}
setCleanRun(value) {
const prev = this._cleanRun;
this._cleanRun = !!value;
}
/**
* 组件挂载时的生命周期钩子
* 子类可以重写此方法来添加挂载时的逻辑
* @protected
*/
// eslint-disable-next-line no-empty
onMount() {
}
/**
* 组件卸载时的生命周期钩子
* 子类可以重写此方法来添加卸载时的逻辑
* @protected
*/
onUnmount() {
}
/**
* 有权限时的渲染逻辑。
* 这是一个抽象方法,所有子类都必须实现,用于返回自己的正常 UI。
*
* @returns {React.ReactNode} 有权限时的渲染结果
*/
render() {
return /* @__PURE__ */ import_react.default.createElement("div", { ...this.props });
}
async rerender() {
var _a;
await this.applyAutoFlows((_a = this._lastAutoRunParams) == null ? void 0 : _a[0], false);
}
/**
* 自动流程缓存的作用域标识;fork 实例可覆盖以区分缓存。
*/
getAutoFlowCacheScope() {
return "autoFlow";
}
setParent(parent) {
const isValidParent = parent && (parent.constructor === _FlowModel || (0, import_utils.isInheritedFrom)(parent.constructor, _FlowModel));
if (!isValidParent) {
throw new Error("Parent must be an instance of FlowModel.");
}
this.parent = parent;
this._options.parentId = parent.uid;
if (this._options.delegateToParent !== false) {
this.context.addDelegate(this.parent.context);
}
}
removeParentDelegate() {
if (!this.parent) {
return;
}
this.context.removeDelegate(this.parent.context);
}
addSubModel(subKey, options) {
var _a;
const actualParent = this["master"] || this;
let model;
if (options instanceof _FlowModel) {
const hasParent = !!options.parent;
const parentUid = (_a = options.parent) == null ? void 0 : _a.uid;
if (hasParent && parentUid && parentUid !== actualParent.uid) {
throw new Error("Sub model already has a parent.");
}
model = options;
} else {
model = actualParent.flowEngine.createModel({
...options,
parentId: actualParent.uid,
subKey,
subType: "array"
});
}
model.setParent(actualParent);
const subModels = actualParent.subModels;
if (!Array.isArray(subModels[subKey])) {
subModels[subKey] = import_reactive.observable.shallow([]);
}
const maxSortIndex = Math.max(...subModels[subKey].map((item) => item.sortIndex || 0), 0);
model.sortIndex = maxSortIndex + 1;
subModels[subKey].push(model);
actualParent.emitter.emit("onSubModelAdded", model);
return model;
}
setSubModel(subKey, options) {
var _a;
const actualParent = this["master"] || this;
let model;
if (options instanceof _FlowModel) {
const hasParent = !!options.parent;
const parentUid = (_a = options.parent) == null ? void 0 : _a.uid;
if (hasParent && parentUid && parentUid !== actualParent.uid) {
throw new Error("Sub model already has a parent.");
}
model = options;
} else {
model = actualParent.flowEngine.createModel({
...options,
parentId: actualParent.uid,
subKey,
subType: "object"
});
}
model.setParent(actualParent);
actualParent.subModels[subKey] = model;
actualParent.emitter.emit("onSubModelAdded", model);
return model;
}
filterSubModels(subKey, callback) {
const model = this.subModels[subKey];
if (!model) {
return [];
}
const results = [];
import_lodash.default.castArray(model).sort((a, b) => (a.sortIndex || 0) - (b.sortIndex || 0)).forEach((item, index) => {
const result = callback(item, index);
if (result) {
results.push(item);
}
});
return results;
}
mapSubModels(subKey, callback) {
const model = this.subModels[subKey];
if (!model) {
return [];
}
const results = [];
import_lodash.default.castArray(model).sort((a, b) => (a.sortIndex || 0) - (b.sortIndex || 0)).forEach((item, index) => {
const result = callback(item, index);
results.push(result);
});
return results;
}
hasSubModel(subKey) {
const subModel = this.subModels[subKey];
if (!subModel) {
return false;
}
return import_lodash.default.castArray(subModel).length > 0;
}
findSubModel(subKey, callback) {
const model = this.subModels[subKey];
if (!model) {
return null;
}
return import_lodash.default.castArray(model).find((item) => {
return callback(item);
}) || null;
}
createRootModel(options) {
return this.flowEngine.createModel(options);
}
async applySubModelsAutoFlows(subKey, inputArgs, shared) {
await Promise.all(
this.mapSubModels(subKey, async (sub) => {
await sub.applyAutoFlows(inputArgs);
})
);
}
/**
* 创建一个 fork 实例,实现"一份数据(master)多视图(fork)"的能力。
* @param {IModelComponentProps} [localProps={}] fork 专属的局部 props,优先级高于 master.props
* @param {string} [key] 可选的 key,用于复用 fork 实例。如果提供了 key,会尝试复用已存在的 fork
* @returns {ForkFlowModel<this>} 创建的 fork 实例
*/
createFork(localProps, key, options) {
if (key) {
const cachedFork = this.forkCache.get(key);
if (cachedFork && !cachedFork.disposed) {
cachedFork.setProps(localProps || {});
return cachedFork;
}
}
const forkId = this.forks.size;
const fork = new import_forkFlowModel.ForkFlowModel(this, localProps, forkId);
if ((options == null ? void 0 : options.register) !== false) {
this.forks.add(fork);
}
if (key && (options == null ? void 0 : options.register) !== false) {
this.forkCache.set(key, fork);
}
return fork;
}
clearForks() {
var _a;
console.log(`FlowModel ${this.uid} clearing all forks.`);
if ((_a = this.forks) == null ? void 0 : _a.size) {
this.forks.forEach((fork) => fork.dispose());
this.forks.clear();
}
this.forkCache.clear();
}
getFork(key) {
return this.forkCache.get(key);
}
/**
* 移动当前模型到目标模型的位置
* @param {FlowModel} targetModel 目标模型
* @param {PersistOptions} [options] 可选的持久化选项
* @returns {boolean} 是否成功移动
*/
moveTo(targetModel, options) {
if (!this.flowEngine) {
throw new Error("FlowEngine is not set on this model. Please set flowEngine before saving.");
}
return this.flowEngine.moveModel(this.uid, targetModel.uid, options);
}
remove() {
if (!this.flowEngine) {
throw new Error("FlowEngine is not set on this model. Please set flowEngine before saving.");
}
this.observerDispose();
this.invalidateAutoFlowCache(true);
return this.flowEngine.removeModel(this.uid);
}
async save() {
if (!this.flowEngine) {
throw new Error("FlowEngine is not set on this model. Please set flowEngine before saving.");
}
return this.flowEngine.saveModel(this);
}
async saveStepParams() {
return this.flowEngine.saveModel(this, { onlyStepParams: true });
}
async destroy() {
if (!this.flowEngine) {
throw new Error("FlowEngine is not set on this model. Please set flowEngine before deleting.");
}
this.observerDispose();
this.invalidateAutoFlowCache(true);
return this.flowEngine.destroyModel(this.uid);
}
/**
* @deprecated
* 打开步骤设置对话框
* 用于配置流程中特定步骤的参数和设置
* @param {string} flowKey 流程的唯一标识符
* @param {string} stepKey 步骤的唯一标识符
* @returns {void}
*/
openStepSettingsDialog(flowKey, stepKey) {
var _a;
const flow = this.getFlow(flowKey);
const step = (_a = flow == null ? void 0 : flow.steps) == null ? void 0 : _a[stepKey];
if (!flow || !step) {
console.error(`Flow ${flowKey} or step ${stepKey} not found`);
return;
}
const ctx = new import_flowContext.FlowRuntimeContext(this, flowKey, "settings");
(0, import_utils.setupRuntimeContextSteps)(ctx, flow.steps, this, flowKey);
ctx.defineProperty("currentStep", { value: step });
return (0, import_StepSettingsDialog.openStepSettingsDialog)({
model: this,
flowKey,
stepKey,
ctx
});
}
/**
* 配置必填步骤参数
* 用于在一个分步表单中配置所有需要参数的步骤
* @param {number | string} [dialogWidth=800] 对话框宽度,默认为800
* @param {string} [dialogTitle='步骤参数配置'] 对话框标题,默认为'步骤参数配置'
* @returns {Promise<any>} 返回表单提交的值
*/
async configureRequiredSteps(dialogWidth, dialogTitle) {
return (0, import_StepRequiredSettingsDialog.openRequiredParamsStepFormDialog)({
model: this,
dialogWidth,
dialogTitle
});
}
/**
* @deprecated
* @param dialogWidth
* @param dialogTitle
* @returns
*/
async openPresetStepSettingsDialog(dialogWidth, dialogTitle) {
return this.configureRequiredSteps(dialogWidth, dialogTitle);
}
async openFlowStepSettingsDialog(options) {
}
get translate() {
return this.flowEngine.translate.bind(this.flowEngine);
}
// TODO: 不完整,需要考虑 sub-model 的情况
serialize() {
const data = {
uid: this.uid,
...import_lodash.default.omit(this._options, ["flowEngine"]),
stepParams: this.stepParams,
sortIndex: this.sortIndex
};
const subModels = this.subModels;
for (const subModelKey in subModels) {
data.subModels = data.subModels || {};
if (Array.isArray(subModels[subModelKey])) {
data.subModels[subModelKey] = subModels[subModelKey].map((model, index) => ({
...model.serialize(),
sortIndex: index
}));
} else if (subModels[subModelKey] instanceof _FlowModel) {
data.subModels[subModelKey] = subModels[subModelKey].serialize();
}
}
for (const [key, flow] of this.flowRegistry.getFlows()) {
data["flowRegistry"] = data["flowRegistry"] || {};
data["flowRegistry"][key] = flow.toData();
}
return data;
}
/**
* Opens the flow settings dialog for this flow model.
* @param options - Configuration options for opening flow settings, excluding the model property
* @returns A promise that resolves when the flow settings dialog is opened
*/
async openFlowSettings(options) {
return this.flowEngine.flowSettings.open({
model: this,
...options
});
}
// =============================
// Dynamic flows (disabled)
// The following APIs are kept as comments to preserve context
// =============================
/*
async openDynamicFlowsEditor(
options?: Omit<FlowSettingsOpenOptions, 'model' | 'flowKey' | 'flowKeys' | 'stepKey' | 'preset'>,
) {
return this.flowEngine.flowSettings.openDynamicFlowsEditor({
model: this,
...options,
});
}
#dynamicFlows: FlowDefinition[] = [];
async loadDynamicFlows(): Promise<FlowDefinition[]> {
return JSON.parse(localStorage.getItem('DYNAMIC_FLOWS') || '[]');
}
async saveDynamicFlows(): Promise<void> {
localStorage.setItem('DYNAMIC_FLOWS', JSON.stringify(this.#dynamicFlows));
}
setDynamicFlows(flows: FlowDefinition[]): void {
this.#dynamicFlows = flows;
flows.forEach((flow) => {
// @ts-ignore
this.constructor.registerFlow(flow);
});
}
getDynamicFlows(): FlowDefinitionOptions[] {
return this.#dynamicFlows;
}
*/
};
_flowContext = new WeakMap();
__name(_FlowModel, "FlowModel");
/**
* 声明渲染模式:
* - 'renderElement': render 返回 React 节点,框架会用 observer 包装以获得响应式;
* - 'renderFunction': render 返回渲染函数(例如表格单元格渲染器),不做包装也不预调用;
*/
__publicField(_FlowModel, "renderMode", "reactElement" /* ReactElement */);
let FlowModel = _FlowModel;
const _ErrorFlowModel = class _ErrorFlowModel extends FlowModel {
errorMessage;
setErrorMessage(msg) {
this.errorMessage = msg;
}
render() {
return /* @__PURE__ */ import_react.default.createElement(import_lib.Typography.Text, { type: "danger" }, this.errorMessage);
}
};
__name(_ErrorFlowModel, "ErrorFlowModel");
let ErrorFlowModel = _ErrorFlowModel;
function defineFlow(definition) {
return definition;
}
__name(defineFlow, "defineFlow");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ErrorFlowModel,
FlowModel,
ModelRenderMode,
defineFlow
});