@nocobase/flow-engine
Version:
A standalone flow engine for NocoBase, managing workflows, models, and actions.
222 lines (220 loc) • 10.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 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
});