@nocobase/flow-engine
Version:
A standalone flow engine for NocoBase, managing workflows, models, and actions.
288 lines (286 loc) • 11.1 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 __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 utils_exports = {};
__export(utils_exports, {
buildItems: () => buildItems,
buildSubModelGroups: () => buildSubModelGroups,
buildSubModelItem: () => buildSubModelItem,
buildSubModelItems: () => buildSubModelItems,
buildWrapperFieldChildren: () => buildWrapperFieldChildren
});
module.exports = __toCommonJS(utils_exports);
var _ = __toESM(require("lodash"));
var import_utils = require("../../utils");
function buildSubModelItem(M, ctx, skipHide = false) {
const meta = M.meta ?? {};
if (meta.hide && !skipHide) {
return;
}
const item = {
key: M.name,
label: meta.label || M.name,
// 子菜单级搜索:仅尊重模型 meta 显式配置,避免在工具层做类型耦合判断
searchable: !!meta.searchable,
searchPlaceholder: meta.searchPlaceholder,
// Ensure toggleable models can be detected and toggled in menus
// Meta.toggleable indicates the item should behave like a switch (unique per parent)
// Add corresponding flags so AddSubModelButton can compute toggle state and removal
toggleable: meta.toggleable,
// Use the model class name for toggle detection (engine.getModelClass)
// This is required by AddSubModelButton to locate existing instances
useModel: M.name,
sort: meta.sort || 1e3,
children: buildSubModelChildren(M, ctx)
};
item["createModelOptions"] = meta.createModelOptions || {
use: M.name
//TODO: this is wrong after code minized, we need to fix this
};
return item;
}
__name(buildSubModelItem, "buildSubModelItem");
function buildSubModelChildren(M, ctx) {
const meta = M.meta ?? {};
let children;
if (meta.children === false) {
return false;
}
if (meta.children) {
children = meta.children;
}
if (M["defineChildren"]) {
children = M["defineChildren"].bind(M);
}
if (typeof children === "function") {
const orininalChildren = children;
children = /* @__PURE__ */ __name(async () => {
const resolved = await orininalChildren(ctx);
const wrap = /* @__PURE__ */ __name((nodes) => nodes == null ? void 0 : nodes.map((n) => {
const node = { ...n };
if (node.children) {
node.children = Array.isArray(node.children) ? wrap(node.children) : node.children;
} else if (node.createModelOptions) {
const src = node.createModelOptions;
node.createModelOptions = async (...args) => {
const extraArg = args && args.length > 0 ? args[args.length - 1] : void 0;
const defaultOpts = await (0, import_utils.resolveCreateModelOptions)(meta == null ? void 0 : meta.createModelOptions, ctx, extraArg);
const childOpts = await (0, import_utils.resolveCreateModelOptions)(src, ctx, extraArg);
return _.merge({}, _.cloneDeep(defaultOpts), childOpts);
};
}
return node;
}), "wrap");
return wrap(resolved);
}, "children");
}
return children;
}
__name(buildSubModelChildren, "buildSubModelChildren");
function buildItems(subModelBaseClass) {
return async (ctx) => {
const items = await buildSubModelGroups([subModelBaseClass])(ctx);
if (items.length === 0) {
return [];
}
const children = items.shift().children;
if (typeof children === "function") {
return children(ctx);
}
return children;
};
}
__name(buildItems, "buildItems");
function buildSubModelItems(subModelBaseClass, exclude = []) {
return async (ctx) => {
var _a;
const SubModelClasses = ctx.engine.getSubclassesOf(subModelBaseClass);
let candidates = Array.from(SubModelClasses.values()).filter((C) => {
var _a2;
return !((_a2 = C.meta) == null ? void 0 : _a2.hide);
}).filter((C) => {
for (const P of exclude) {
if (typeof P === "string") {
if (C.name === P) return false;
} else if (C === P || (0, import_utils.isInheritedFrom)(C, P)) {
return false;
}
}
return true;
}).sort((A, B) => {
var _a2, _b;
return (((_a2 = A.meta) == null ? void 0 : _a2.sort) ?? 1e3) - (((_b = B.meta) == null ? void 0 : _b.sort) ?? 1e3);
});
if (candidates.length === 0) {
const BaseClass = typeof subModelBaseClass === "string" ? ctx.engine.getModelClass(subModelBaseClass) : subModelBaseClass;
if (BaseClass && !((_a = BaseClass.meta) == null ? void 0 : _a.hide)) {
candidates = [BaseClass];
}
}
const items = [];
for (const M of candidates) {
const item = buildSubModelItem(M, ctx);
if (item) items.push(item);
}
return items;
};
}
__name(buildSubModelItems, "buildSubModelItems");
function buildSubModelGroups(subModelBaseClasses = []) {
return async (ctx) => {
var _a, _b, _c;
const items = [];
const exclude = [];
for (const subModelBaseClass of subModelBaseClasses) {
const BaseClass = typeof subModelBaseClass === "string" ? ctx.engine.getModelClass(subModelBaseClass) : subModelBaseClass;
if (!BaseClass) {
continue;
}
let children = buildSubModelChildren(BaseClass, ctx);
if (!children) {
children = await buildSubModelItems(subModelBaseClass, exclude)(ctx);
}
exclude.push(BaseClass);
let hasChildren = false;
if (typeof children === "function") {
try {
const resolved = await children(ctx);
hasChildren = Array.isArray(resolved) ? resolved.length > 0 : !!resolved;
} catch (e) {
hasChildren = false;
}
} else if (Array.isArray(children)) {
hasChildren = children.length > 0;
} else {
hasChildren = !!children;
}
if (!hasChildren) continue;
const groupLabel = ((_a = BaseClass == null ? void 0 : BaseClass.meta) == null ? void 0 : _a.label) || (typeof subModelBaseClass === "string" ? subModelBaseClass : BaseClass.name);
const baseKey = typeof subModelBaseClass === "string" ? subModelBaseClass : BaseClass.name;
const menuType = ((_b = BaseClass == null ? void 0 : BaseClass.meta) == null ? void 0 : _b.menuType) || "group";
const groupSort = ((_c = BaseClass == null ? void 0 : BaseClass.meta) == null ? void 0 : _c.sort) ?? 1e3;
if (menuType === "submenu") {
items.push({
key: baseKey,
label: groupLabel,
sort: groupSort,
children
});
} else {
items.push({
key: baseKey,
type: "group",
label: groupLabel,
sort: groupSort,
children
});
}
}
return items.sort((a, b) => ((a == null ? void 0 : a.sort) ?? 1e3) - ((b == null ? void 0 : b.sort) ?? 1e3));
};
}
__name(buildSubModelGroups, "buildSubModelGroups");
function buildWrapperFieldChildren(ctx, options) {
var _a;
const { useModel, fieldUseModel, associationPathName, refreshTargets } = options;
const collection = options.collection || ctx.model["collection"] || ctx.collection;
const fields = collection.getFields();
const defaultItemKeys = ["fieldSettings", "init"];
const children = [];
for (const f of fields) {
if (!((_a = f == null ? void 0 : f.options) == null ? void 0 : _a.interface)) continue;
const fieldPath = associationPathName ? `${associationPathName}.${f.name}` : f.name;
const childUse = typeof fieldUseModel === "function" ? fieldUseModel(f) : fieldUseModel ?? "FieldModel";
if (childUse) {
const stepPayload = {
dataSourceKey: collection.dataSourceKey,
collectionName: collection.name,
fieldPath: f.name,
associationPathName
};
children.push({
key: fieldPath,
label: f.title,
toggleable: /* @__PURE__ */ __name((subModel) => {
const { associationPathName: associationPathName2, fieldPath: fieldName } = subModel.getStepParams("fieldSettings", "init") || {};
return (associationPathName2 ? `${associationPathName2}.${fieldName}` : fieldName) === fieldPath;
}, "toggleable"),
useModel,
refreshTargets,
createModelOptions: /* @__PURE__ */ __name(() => ({
use: useModel,
stepParams: {
fieldSettings: {
init: stepPayload
}
},
subModels: {
field: {
use: childUse,
stepParams: {
fieldSettings: {
init: stepPayload
}
}
}
}
}), "createModelOptions")
});
}
}
const groupKey = `addField_${collection.name}`;
const finalSearchPlaceholder = ctx.t("Search fields");
return [
{
key: groupKey,
label: "",
// 这个是为了搜索框的占位group, 如果写入内容,会导致出现两层group labels, 本问题的本质是 subModelBaseClass 构建的goup没地方指定是否允许搜索
type: "group",
searchable: true,
searchPlaceholder: finalSearchPlaceholder,
children: children.filter(Boolean)
}
];
}
__name(buildWrapperFieldChildren, "buildWrapperFieldChildren");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
buildItems,
buildSubModelGroups,
buildSubModelItem,
buildSubModelItems,
buildWrapperFieldChildren
});