@nocobase/flow-engine
Version:
A standalone flow engine for NocoBase, managing workflows, models, and actions.
323 lines (321 loc) • 12.2 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 VariableInput_exports = {};
__export(VariableInput_exports, {
VariableInput: () => VariableInput
});
module.exports = __toCommonJS(VariableInput_exports);
var import_react = __toESM(require("react"));
var import_antd = require("antd");
var import_FlowContextSelector = require("../FlowContextSelector");
var import_VariableTag = require("./VariableTag");
var import_utils = require("./utils");
var import_utils2 = require("./utils");
var import_ahooks = require("ahooks");
const compactStyle = {
display: "flex",
alignItems: "flex-start"
};
const findMetaTreeNodeByPath = /* @__PURE__ */ __name((metaTree, targetPath) => {
if (!targetPath || targetPath.length === 0) return null;
const searchInNodes = /* @__PURE__ */ __name((nodes, path) => {
for (const node of nodes) {
if (node.paths && arraysEqual(node.paths, path)) {
return node;
}
if (node.paths && isPathPrefix(node.paths, path) && node.children) {
if (Array.isArray(node.children)) {
const found = searchInNodes(node.children, path);
if (found) return found;
}
}
}
return null;
}, "searchInNodes");
const direct = searchInNodes(metaTree, targetPath);
if (direct) return direct;
const topNames = new Set((metaTree || []).map((n) => String(n.name)));
if (!topNames.has(String(targetPath[0]))) {
const trimmed = targetPath.slice(1);
if (trimmed.length > 0) {
return searchInNodes(metaTree, trimmed);
}
}
return null;
}, "findMetaTreeNodeByPath");
const arraysEqual = /* @__PURE__ */ __name((a, b) => {
if (a.length !== b.length) return false;
return a.every((val, index) => val === b[index]);
}, "arraysEqual");
const isPathPrefix = /* @__PURE__ */ __name((pathA, pathB) => {
if (pathA.length >= pathB.length) return false;
return pathA.every((val, index) => val === pathB[index]);
}, "isPathPrefix");
const VariableInputComponent = /* @__PURE__ */ __name(({
value,
onChange,
converters: propConverters,
metaTree,
showValueComponent = true,
onlyLeafSelectable = false,
clearValue,
...restProps
}) => {
const [currentMetaTreeNode, setCurrentMetaTreeNode] = (0, import_react.useState)(null);
const lastEmitRef = (0, import_react.useRef)(null);
const [innerValue, setInnerValue] = (0, import_react.useState)(value);
(0, import_react.useEffect)(() => {
setInnerValue(value);
}, [value]);
const { resolveValueFromPath, resolvePathFromValue, renderInputComponent } = (0, import_react.useMemo)(() => {
return (0, import_utils2.createFinalConverters)(propConverters);
}, [propConverters]);
const { data: resolvedMetaTree, loading } = (0, import_ahooks.useRequest)(
async () => {
if (typeof metaTree === "function") {
const ret = await metaTree();
if (typeof ret === "function") {
return await ret();
}
return ret;
}
return metaTree;
},
{ refreshDeps: [metaTree] }
);
const emitChange = (0, import_react.useCallback)(
(nextValue, meta) => {
const nextPath = (meta == null ? void 0 : meta.paths) ? meta.paths.join(".") : void 0;
const last = lastEmitRef.current;
if (last && last.value === nextValue && last.path === nextPath) {
return false;
}
lastEmitRef.current = { value: nextValue, path: nextPath };
onChange == null ? void 0 : onChange(nextValue, meta);
return true;
},
[onChange]
);
const resolvedMetaTreeNode = (0, import_react.useMemo)(() => {
if (currentMetaTreeNode) return currentMetaTreeNode;
if (Array.isArray(resolvedMetaTree)) {
const path = resolvePathFromValue == null ? void 0 : resolvePathFromValue(innerValue);
if (path) {
return findMetaTreeNodeByPath(resolvedMetaTree, path);
}
}
return null;
}, [currentMetaTreeNode, innerValue, resolvedMetaTree, resolvePathFromValue]);
(0, import_react.useEffect)(() => {
const restoreFromValue = /* @__PURE__ */ __name(async () => {
if (!Array.isArray(resolvedMetaTree) || !value) return;
if (currentMetaTreeNode) {
return;
}
const rawPath = resolvePathFromValue == null ? void 0 : resolvePathFromValue(value);
if (!rawPath || rawPath.length === 0) return;
const topNames = new Set(resolvedMetaTree.map((n) => String(n.name)));
const path = !topNames.has(String(rawPath[0])) ? rawPath.slice(1) : rawPath;
if (path.length === 0) return;
let nodes = resolvedMetaTree;
let found = null;
for (let i = 0; i < path.length; i++) {
if (!nodes) {
found = null;
break;
}
const seg = String(path[i]);
const node = nodes.find((n) => String(n == null ? void 0 : n.name) === seg);
if (!node) {
found = null;
break;
}
found = node;
if (i < path.length - 1) {
if (Array.isArray(node.children)) {
nodes = node.children;
} else if (typeof node.children === "function") {
try {
const childNodes = await node.children();
node.children = childNodes;
nodes = childNodes;
} catch {
nodes = void 0;
}
} else {
nodes = void 0;
}
}
}
if (found) {
setCurrentMetaTreeNode(found);
}
}, "restoreFromValue");
restoreFromValue();
}, [resolvedMetaTree, innerValue, resolvePathFromValue, currentMetaTreeNode]);
const ValueComponent = (0, import_react.useMemo)(() => {
const Component = renderInputComponent == null ? void 0 : renderInputComponent(resolvedMetaTreeNode);
const CustomComponent = resolvedMetaTreeNode == null ? void 0 : resolvedMetaTreeNode.render;
const finalComponent = (0, import_utils.isVariableValue)(innerValue) ? import_VariableTag.VariableTag : Component || CustomComponent || import_antd.Input;
return finalComponent;
}, [renderInputComponent, resolvedMetaTreeNode, innerValue]);
(0, import_react.useEffect)(() => {
if (!resolvedMetaTreeNode) return;
if (!Array.isArray(resolvedMetaTree) || !innerValue) return;
const finalValue = (resolveValueFromPath == null ? void 0 : resolveValueFromPath(resolvedMetaTreeNode)) || innerValue;
emitChange(finalValue, resolvedMetaTreeNode);
setCurrentMetaTreeNode(resolvedMetaTreeNode);
}, [resolvedMetaTreeNode]);
const composingRef = (0, import_react.useRef)(false);
const handleComposition = (0, import_react.useCallback)(
(e) => {
var _a;
if ((e == null ? void 0 : e.type) === "compositionend") {
composingRef.current = false;
const newValue = ((_a = e == null ? void 0 : e.target) == null ? void 0 : _a.value) !== void 0 ? e.target.value : e;
setInnerValue(newValue);
emitChange(newValue);
} else {
composingRef.current = true;
}
},
[emitChange]
);
const handleInputChange = (0, import_react.useCallback)(
(e) => {
var _a;
const newValue = ((_a = e == null ? void 0 : e.target) == null ? void 0 : _a.value) !== void 0 ? e.target.value : e;
setInnerValue(newValue);
const isComposing = composingRef.current || (e == null ? void 0 : e.nativeEvent) && e.nativeEvent.isComposing;
if (isComposing) return;
emitChange(newValue);
},
[emitChange]
);
const handleVariableSelect = (0, import_react.useCallback)(
(variableValue, metaTreeNode) => {
setCurrentMetaTreeNode(metaTreeNode);
const finalValue = (resolveValueFromPath == null ? void 0 : resolveValueFromPath(metaTreeNode)) || variableValue;
setInnerValue(finalValue);
emitChange(finalValue, metaTreeNode);
},
[emitChange, resolveValueFromPath]
);
const { disabled } = restProps;
const handleClear = (0, import_react.useCallback)(() => {
if (disabled) {
return;
}
setCurrentMetaTreeNode(null);
const cleared = clearValue !== void 0 ? clearValue : null;
setInnerValue(cleared);
emitChange(cleared);
}, [emitChange, disabled, clearValue]);
const stableProps = (0, import_react.useMemo)(() => {
const { style, onFocus, onBlur, disabled: disabled2, ...otherProps } = restProps;
return { style, onFocus, onBlur, otherProps };
}, [restProps]);
const inputProps = (0, import_react.useMemo)(() => {
const baseProps = {
value: innerValue || "",
onChange: handleInputChange,
disabled
};
if (ValueComponent === import_VariableTag.VariableTag) {
return {
...baseProps,
onClear: handleClear,
metaTreeNode: resolvedMetaTreeNode,
metaTree,
style: stableProps.style
};
}
const { value: _ignoredValue, onChange: _ignoredOnChange, ...restOthers } = stableProps.otherProps || {};
const props = {
...baseProps,
...restOthers,
// Ensure IME composition works correctly for text inputs
onCompositionStart: handleComposition,
onCompositionUpdate: handleComposition,
onCompositionEnd: handleComposition
};
return props;
}, [
innerValue,
handleInputChange,
handleComposition,
disabled,
handleClear,
resolvedMetaTreeNode,
metaTree,
ValueComponent,
stableProps
]);
const finalStyle = (0, import_react.useMemo)(
() => ({
...compactStyle,
...restProps.style
}),
[restProps.style]
);
if (loading) {
return null;
}
return /* @__PURE__ */ import_react.default.createElement(import_antd.Space.Compact, { style: finalStyle }, showValueComponent && /* @__PURE__ */ import_react.default.createElement(
ValueComponent,
{
style: { width: "100%", minWidth: 0, ...inputProps["style"] },
...inputProps
}
), /* @__PURE__ */ import_react.default.createElement(
import_FlowContextSelector.FlowContextSelector,
{
metaTree: resolvedMetaTree,
value: innerValue,
onChange: handleVariableSelect,
parseValueToPath: resolvePathFromValue,
formatPathToValue: resolveValueFromPath,
onlyLeafSelectable,
...!showValueComponent && { children: null, placeholder: restProps == null ? void 0 : restProps.placeholder }
}
));
}, "VariableInputComponent");
const VariableInput = import_react.default.memo(VariableInputComponent);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
VariableInput
});