UNPKG

@nocobase/flow-engine

Version:

A standalone flow engine for NocoBase, managing workflows, models, and actions.

288 lines (286 loc) 11.1 kB
/** * 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 });