UNPKG

@nocobase/flow-engine

Version:

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

222 lines (220 loc) 10.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 FlowContextSelector_exports = {}; __export(FlowContextSelector_exports, { FlowContextSelector: () => FlowContextSelector }); module.exports = __toCommonJS(FlowContextSelector_exports); var import_react = __toESM(require("react")); var import_antd = require("antd"); var import_icons = require("@ant-design/icons"); var import_utils = require("./variables/utils"); var import_useResolvedMetaTree = require("./variables/useResolvedMetaTree"); var import_FlowContextProvider = require("../FlowContextProvider"); const defaultButtonStyle = { fontStyle: "italic", fontFamily: "New York, Times New Roman, Times, serif" }; const FlowContextSelectorComponent = /* @__PURE__ */ __name(({ value, onChange, children, metaTree, showSearch = false, parseValueToPath: customParseValueToPath = import_utils.parseValueToPath, formatPathToValue: customFormatPathToValue, open, onlyLeafSelectable = false, ...cascaderProps }) => { const lastSelectedRef = (0, import_react.useRef)(null); const { resolvedMetaTree, loading } = (0, import_useResolvedMetaTree.useResolvedMetaTree)(metaTree); const flowCtx = (0, import_FlowContextProvider.useFlowContext)(); const translateOptions = (0, import_react.useCallback)( (items) => { if (!items) return []; return items.map((o) => { const meta = o.meta; const disabled = meta ? !!(typeof meta.disabled === "function" ? meta.disabled() : meta.disabled) : false; const disabledReason = meta ? typeof meta.disabledReason === "function" ? meta.disabledReason() : meta.disabledReason : void 0; const baseLabel = typeof o.label === "string" ? flowCtx.t(o.label) : o.label; const label = disabled ? /* @__PURE__ */ import_react.default.createElement("span", null, baseLabel, /* @__PURE__ */ import_react.default.createElement( import_antd.Tooltip, { title: disabledReason || flowCtx.t("This variable is not available"), placement: "right", overlayClassName: "flow-variable-disabled-tip", destroyTooltipOnHide: true }, /* @__PURE__ */ import_react.default.createElement(import_icons.QuestionCircleOutlined, { style: { marginLeft: 6, color: "rgba(0,0,0,0.35)" } }) )) : baseLabel; return { ...o, label, disabled, children: Array.isArray(o.children) ? translateOptions(o.children) : o.children }; }); }, [flowCtx] ); const [updateFlag, setUpdateFlag] = (0, import_react.useState)(0); const triggerUpdate = (0, import_react.useCallback)(() => setUpdateFlag((prev) => prev + 1), []); const options = (0, import_react.useMemo)(() => { if (!resolvedMetaTree) return []; const base = (0, import_utils.buildContextSelectorItems)(resolvedMetaTree); return translateOptions(base); }, [resolvedMetaTree, updateFlag, translateOptions]); const [tempSelectedPath, setTempSelectedPath] = (0, import_react.useState)([]); const handleLoadData = (0, import_react.useCallback)( async (selectedOptions) => { const targetOption = selectedOptions[selectedOptions.length - 1]; if (!targetOption || targetOption.children || targetOption.isLeaf) { return; } const targetMetaNode = targetOption.meta; if (!targetMetaNode || !targetMetaNode.children) { return; } if (Array.isArray(targetMetaNode.children)) { const childNodes = targetMetaNode.children; const childOptions = translateOptions((0, import_utils.buildContextSelectorItems)(childNodes)); targetOption.children = childOptions; targetOption.isLeaf = !childOptions || childOptions.length === 0; triggerUpdate(); return; } try { setTempSelectedPath(selectedOptions.map((o) => String(o.value))); targetOption.loading = true; triggerUpdate(); const childNodes = await targetMetaNode.children(); targetMetaNode.children = childNodes; const childOptions = translateOptions((0, import_utils.buildContextSelectorItems)(childNodes)); targetOption.children = childOptions; targetOption.isLeaf = !childOptions || childOptions.length === 0; } catch (error) { console.error("Failed to load children:", error); } finally { targetOption.loading = false; triggerUpdate(); } }, [triggerUpdate] ); const currentPath = (0, import_react.useMemo)(() => { return customParseValueToPath(value); }, [value, customParseValueToPath]); const effectivePath = (0, import_react.useMemo)(() => { if (!currentPath || currentPath.length === 0) return currentPath; const topValues = new Set(options.map((o) => String(o.value))); const needTrim = !topValues.has(String(currentPath[0])); const fixed = needTrim ? currentPath.slice(1) : currentPath; return fixed; }, [currentPath, options]); const pathToPreload = (0, import_react.useMemo)(() => { const finalPath = effectivePath && effectivePath.length > 0 ? effectivePath : tempSelectedPath; return Array.isArray(finalPath) ? finalPath : []; }, [effectivePath, tempSelectedPath]); (0, import_react.useEffect)(() => { if (pathToPreload.length === 0 || !(options == null ? void 0 : options.length)) return; (0, import_utils.preloadContextSelectorPath)(options, pathToPreload, triggerUpdate); }, [options, pathToPreload, triggerUpdate]); const defaultChildren = (0, import_react.useMemo)(() => { const hasSelected = currentPath && currentPath.length > 0; return /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { type: hasSelected ? "primary" : "default", style: defaultButtonStyle }, "x"); }, [currentPath]); const handleChange = (0, import_react.useCallback)( (selectedValues, selectedOptions) => { const lastOption = selectedOptions == null ? void 0 : selectedOptions[selectedOptions.length - 1]; if (!selectedValues || selectedValues.length === 0) { onChange == null ? void 0 : onChange("", lastOption == null ? void 0 : lastOption.meta); setTempSelectedPath([]); return; } const path = selectedValues.map(String); const pathString = path.join("."); const isLeaf = lastOption == null ? void 0 : lastOption.isLeaf; const now = Date.now(); let formattedValue; if (customFormatPathToValue) { formattedValue = customFormatPathToValue(lastOption == null ? void 0 : lastOption.meta); if (formattedValue === void 0) { formattedValue = (0, import_utils.formatPathToValue)(lastOption == null ? void 0 : lastOption.meta); } } else { formattedValue = (0, import_utils.formatPathToValue)(lastOption == null ? void 0 : lastOption.meta); } if (isLeaf) { onChange == null ? void 0 : onChange(formattedValue, lastOption == null ? void 0 : lastOption.meta); setTempSelectedPath([]); return; } const lastSelected = lastSelectedRef.current; const isDoubleClick = !onlyLeafSelectable && (lastSelected == null ? void 0 : lastSelected.path) === pathString && now - lastSelected.time < 300; if (isDoubleClick) { onChange == null ? void 0 : onChange(formattedValue, lastOption == null ? void 0 : lastOption.meta); lastSelectedRef.current = null; } else { lastSelectedRef.current = { path: pathString, time: now }; setTempSelectedPath(path); } }, [onChange, customFormatPathToValue, onlyLeafSelectable] ); return /* @__PURE__ */ import_react.default.createElement( import_antd.Cascader, { ...cascaderProps, options, value: tempSelectedPath && tempSelectedPath.length > 0 ? tempSelectedPath : effectivePath, onChange: handleChange, loadData: handleLoadData, loading, changeOnSelect: !onlyLeafSelectable, expandTrigger: "click", open, showSearch: children === null }, children === null ? null : children || defaultChildren ); }, "FlowContextSelectorComponent"); const FlowContextSelector = import_react.default.memo(FlowContextSelectorComponent); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { FlowContextSelector });