@nocobase/flow-engine 2.2.0-alpha.7 → 2.2.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/variables/VariableInput.js +15 -7
- package/lib/components/variables/VariableTag.js +43 -32
- package/lib/components/variables/types.d.ts +2 -0
- package/lib/utils/dirtyAwareApiClient.js +267 -13
- package/package.json +4 -4
- package/src/components/variables/VariableInput.tsx +34 -7
- package/src/components/variables/VariableTag.tsx +47 -34
- package/src/components/variables/__tests__/VariableInput.test.tsx +93 -1
- package/src/components/variables/__tests__/VariableTag.test.tsx +80 -0
- package/src/components/variables/types.ts +2 -0
- package/src/utils/__tests__/dirtyAwareApiClient.test.ts +321 -0
- package/src/utils/dirtyAwareApiClient.ts +325 -13
|
@@ -132,16 +132,18 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
132
132
|
},
|
|
133
133
|
[onChange]
|
|
134
134
|
);
|
|
135
|
+
const resolvedPath = (0, import_react.useMemo)(() => {
|
|
136
|
+
return resolvePathFromValue == null ? void 0 : resolvePathFromValue(innerValue);
|
|
137
|
+
}, [innerValue, resolvePathFromValue]);
|
|
135
138
|
const resolvedMetaTreeNode = (0, import_react.useMemo)(() => {
|
|
136
139
|
if (currentMetaTreeNode) return currentMetaTreeNode;
|
|
137
140
|
if (Array.isArray(resolvedMetaTree)) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return findMetaTreeNodeByPath(resolvedMetaTree, path);
|
|
141
|
+
if (resolvedPath) {
|
|
142
|
+
return findMetaTreeNodeByPath(resolvedMetaTree, resolvedPath);
|
|
141
143
|
}
|
|
142
144
|
}
|
|
143
145
|
return null;
|
|
144
|
-
}, [currentMetaTreeNode,
|
|
146
|
+
}, [currentMetaTreeNode, resolvedMetaTree, resolvedPath]);
|
|
145
147
|
(0, import_react.useEffect)(() => {
|
|
146
148
|
const restoreFromValue = /* @__PURE__ */ __name(async () => {
|
|
147
149
|
if (!Array.isArray(resolvedMetaTree) || value == null) return;
|
|
@@ -192,9 +194,13 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
192
194
|
const ValueComponent = (0, import_react.useMemo)(() => {
|
|
193
195
|
const Component = renderInputComponent == null ? void 0 : renderInputComponent(resolvedMetaTreeNode);
|
|
194
196
|
const CustomComponent = resolvedMetaTreeNode == null ? void 0 : resolvedMetaTreeNode.render;
|
|
195
|
-
const
|
|
197
|
+
const shouldRenderVariableTag = (0, import_utils.isVariableValue)(innerValue) || Boolean(resolvedMetaTreeNode) && Array.isArray(resolvedPath) && resolvedPath.length > 0 && !Component && !CustomComponent;
|
|
198
|
+
const finalComponent = shouldRenderVariableTag ? import_VariableTag.VariableTag : Component || CustomComponent || import_antd.Input;
|
|
196
199
|
return finalComponent;
|
|
197
|
-
}, [renderInputComponent, resolvedMetaTreeNode, innerValue]);
|
|
200
|
+
}, [renderInputComponent, resolvedMetaTreeNode, innerValue, resolvedPath]);
|
|
201
|
+
const isVariableActive = (0, import_react.useMemo)(() => {
|
|
202
|
+
return (0, import_utils.isVariableValue)(innerValue) || Boolean(resolvedMetaTreeNode) && Array.isArray(resolvedPath) && resolvedPath.length > 0 && !(renderInputComponent == null ? void 0 : renderInputComponent(resolvedMetaTreeNode)) && !(resolvedMetaTreeNode == null ? void 0 : resolvedMetaTreeNode.render);
|
|
203
|
+
}, [innerValue, renderInputComponent, resolvedMetaTreeNode, resolvedPath]);
|
|
198
204
|
(0, import_react.useEffect)(() => {
|
|
199
205
|
if (!resolvedMetaTreeNode) return;
|
|
200
206
|
if (!Array.isArray(resolvedMetaTree) || innerValue == null) return;
|
|
@@ -278,6 +284,8 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
278
284
|
return {
|
|
279
285
|
...baseProps,
|
|
280
286
|
onClear: handleClear,
|
|
287
|
+
disabled,
|
|
288
|
+
allowCustomTagInput: false,
|
|
281
289
|
metaTreeNode: resolvedMetaTreeNode,
|
|
282
290
|
metaTree,
|
|
283
291
|
style: stableProps.style
|
|
@@ -325,7 +333,7 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
325
333
|
{
|
|
326
334
|
metaTree: resolvedMetaTree,
|
|
327
335
|
value: innerValue,
|
|
328
|
-
active:
|
|
336
|
+
active: isVariableActive,
|
|
329
337
|
disabled,
|
|
330
338
|
onChange: handleVariableSelect,
|
|
331
339
|
parseValueToPath: resolvePathFromValue,
|
|
@@ -47,9 +47,12 @@ var import_utils = require("./utils");
|
|
|
47
47
|
var import_useResolvedMetaTree = require("./useResolvedMetaTree");
|
|
48
48
|
var import_ahooks = require("ahooks");
|
|
49
49
|
var import_FlowContextProvider = require("../../FlowContextProvider");
|
|
50
|
+
const VARIABLE_PARSING_FAILED_TEXT = "Variable parsing failed";
|
|
50
51
|
const VariableTagComponent = /* @__PURE__ */ __name(({
|
|
51
52
|
value,
|
|
52
53
|
onClear,
|
|
54
|
+
disabled = false,
|
|
55
|
+
allowCustomTagInput = true,
|
|
53
56
|
className,
|
|
54
57
|
style,
|
|
55
58
|
metaTreeNode,
|
|
@@ -57,25 +60,23 @@ const VariableTagComponent = /* @__PURE__ */ __name(({
|
|
|
57
60
|
}) => {
|
|
58
61
|
const { resolvedMetaTree } = (0, import_useResolvedMetaTree.useResolvedMetaTree)(metaTree);
|
|
59
62
|
const ctx = (0, import_FlowContextProvider.useFlowContext)();
|
|
60
|
-
const { data:
|
|
63
|
+
const { data: displayState } = (0, import_ahooks.useRequest)(
|
|
61
64
|
async () => {
|
|
62
65
|
const resolveLabelFromPath = /* @__PURE__ */ __name(async (rawPath2) => {
|
|
63
|
-
if (!rawPath2) return null;
|
|
64
|
-
if (!Array.isArray(rawPath2)) return null;
|
|
65
|
-
if (!Array.isArray(resolvedMetaTree)) return null;
|
|
66
|
+
if (!rawPath2) return { label: null, resolved: false, attempted: false };
|
|
67
|
+
if (!Array.isArray(rawPath2)) return { label: null, resolved: false, attempted: false };
|
|
68
|
+
if (!Array.isArray(resolvedMetaTree)) return { label: null, resolved: false, attempted: false };
|
|
66
69
|
const topNames = new Set((resolvedMetaTree || []).map((n) => String(n == null ? void 0 : n.name)));
|
|
67
70
|
const path = !topNames.has(String(rawPath2[0])) ? rawPath2.slice(1) : rawPath2;
|
|
68
|
-
if (!path.length) return "";
|
|
71
|
+
if (!path.length) return { label: "", resolved: true, attempted: true };
|
|
69
72
|
let nodes = resolvedMetaTree;
|
|
70
73
|
const titleChain = [];
|
|
71
|
-
let matchedCount = 0;
|
|
72
74
|
for (let i = 0; i < path.length; i++) {
|
|
73
|
-
if (!nodes)
|
|
75
|
+
if (!nodes) return { label: null, resolved: false, attempted: true };
|
|
74
76
|
const seg = String(path[i]);
|
|
75
77
|
const node = nodes.find((n) => String(n == null ? void 0 : n.name) === seg);
|
|
76
|
-
if (!node)
|
|
78
|
+
if (!node) return { label: null, resolved: false, attempted: true };
|
|
77
79
|
titleChain.push(String(node.title ?? node.name ?? seg));
|
|
78
|
-
matchedCount = i + 1;
|
|
79
80
|
if (i < path.length - 1) {
|
|
80
81
|
if (Array.isArray(node.children)) {
|
|
81
82
|
nodes = node.children;
|
|
@@ -92,27 +93,35 @@ const VariableTagComponent = /* @__PURE__ */ __name(({
|
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
|
-
|
|
96
|
-
let label2 = titleChain.map(ctx.t).join("/");
|
|
97
|
-
if (matchedCount < path.length) {
|
|
98
|
-
const tail = path.slice(matchedCount).join("/");
|
|
99
|
-
label2 = tail ? `${label2}/${tail}` : label2;
|
|
100
|
-
}
|
|
101
|
-
return label2;
|
|
96
|
+
return { label: titleChain.map(ctx.t).join("/"), resolved: true, attempted: true };
|
|
102
97
|
}, "resolveLabelFromPath");
|
|
103
98
|
if (metaTreeNode == null ? void 0 : metaTreeNode.parentTitles) {
|
|
104
|
-
return
|
|
99
|
+
return {
|
|
100
|
+
text: [...metaTreeNode.parentTitles, metaTreeNode.title].map(ctx.t).join("/"),
|
|
101
|
+
invalid: false
|
|
102
|
+
};
|
|
105
103
|
}
|
|
106
104
|
if (metaTreeNode) {
|
|
107
105
|
const rawPath2 = (0, import_utils.parseValueToPath)(value) || metaTreeNode.paths;
|
|
108
|
-
const
|
|
109
|
-
|
|
106
|
+
const result2 = await resolveLabelFromPath(rawPath2);
|
|
107
|
+
if (result2.resolved && result2.label != null) {
|
|
108
|
+
return { text: result2.label, invalid: false };
|
|
109
|
+
}
|
|
110
|
+
if (result2.attempted) {
|
|
111
|
+
return { text: VARIABLE_PARSING_FAILED_TEXT, invalid: true, rawValue: String(value ?? "") };
|
|
112
|
+
}
|
|
113
|
+
return { text: ctx.t(metaTreeNode.title) ?? "", invalid: false };
|
|
110
114
|
}
|
|
111
|
-
if (!value) return String(value);
|
|
115
|
+
if (!value) return { text: String(value), invalid: false };
|
|
112
116
|
const rawPath = (0, import_utils.parseValueToPath)(value);
|
|
113
|
-
const
|
|
114
|
-
if (label != null)
|
|
115
|
-
|
|
117
|
+
const result = await resolveLabelFromPath(rawPath);
|
|
118
|
+
if (result.resolved && result.label != null) {
|
|
119
|
+
return { text: result.label, invalid: false };
|
|
120
|
+
}
|
|
121
|
+
if (result.attempted) {
|
|
122
|
+
return { text: VARIABLE_PARSING_FAILED_TEXT, invalid: true, rawValue: String(value ?? "") };
|
|
123
|
+
}
|
|
124
|
+
return { text: Array.isArray(rawPath) ? rawPath.join("/") : String(value), invalid: false };
|
|
116
125
|
},
|
|
117
126
|
{ refreshDeps: [resolvedMetaTree, value, metaTreeNode] }
|
|
118
127
|
);
|
|
@@ -129,12 +138,12 @@ const VariableTagComponent = /* @__PURE__ */ __name(({
|
|
|
129
138
|
}
|
|
130
139
|
`;
|
|
131
140
|
const customTagRender = /* @__PURE__ */ __name((props) => {
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
return /* @__PURE__ */ import_react.default.createElement(import_antd.Tooltip, { title:
|
|
141
|
+
const fullText = (displayState == null ? void 0 : displayState.text) || (typeof props.label === "string" ? props.label : String(props.label));
|
|
142
|
+
const tooltipText = (displayState == null ? void 0 : displayState.invalid) ? displayState.rawValue || fullText : fullText;
|
|
143
|
+
return /* @__PURE__ */ import_react.default.createElement(import_antd.Tooltip, { title: tooltipText, placement: "top", getPopupContainer: () => document.body }, /* @__PURE__ */ import_react.default.createElement(
|
|
135
144
|
import_antd.Tag,
|
|
136
145
|
{
|
|
137
|
-
color: "blue",
|
|
146
|
+
color: (displayState == null ? void 0 : displayState.invalid) ? "error" : "blue",
|
|
138
147
|
style: {
|
|
139
148
|
margin: `0 ${token.marginXXS || token.marginXS}px`,
|
|
140
149
|
borderRadius: token.borderRadiusSM,
|
|
@@ -175,12 +184,14 @@ const VariableTagComponent = /* @__PURE__ */ __name(({
|
|
|
175
184
|
flex: "1 1 auto",
|
|
176
185
|
...style
|
|
177
186
|
},
|
|
178
|
-
value:
|
|
179
|
-
mode: "tags",
|
|
187
|
+
value: (displayState == null ? void 0 : displayState.text) ? [displayState.text] : [],
|
|
188
|
+
mode: allowCustomTagInput ? "tags" : "multiple",
|
|
180
189
|
open: false,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
190
|
+
showSearch: allowCustomTagInput,
|
|
191
|
+
searchValue: allowCustomTagInput ? void 0 : "",
|
|
192
|
+
allowClear: !disabled && !!onClear,
|
|
193
|
+
onClear: disabled ? void 0 : onClear,
|
|
194
|
+
disabled: disabled || !onClear,
|
|
184
195
|
variant: "outlined",
|
|
185
196
|
suffixIcon: null,
|
|
186
197
|
tagRender: customTagRender,
|
|
@@ -87,6 +87,8 @@ export interface VariableInputProps {
|
|
|
87
87
|
export interface VariableTagProps {
|
|
88
88
|
value?: string;
|
|
89
89
|
onClear?: () => void;
|
|
90
|
+
disabled?: boolean;
|
|
91
|
+
allowCustomTagInput?: boolean;
|
|
90
92
|
className?: string;
|
|
91
93
|
style?: React.CSSProperties;
|
|
92
94
|
metaTreeNode?: MetaTreeNode | null;
|
|
@@ -31,8 +31,10 @@ __export(dirtyAwareApiClient_exports, {
|
|
|
31
31
|
getDirtyAwareApiClient: () => getDirtyAwareApiClient
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(dirtyAwareApiClient_exports);
|
|
34
|
+
var import_sdk = require("@nocobase/sdk");
|
|
34
35
|
var import_dataSourceDirty = require("./dataSourceDirty");
|
|
35
36
|
const SKIP_DATA_SOURCE_DIRTY = "__nocobaseSkipDataSourceDirty";
|
|
37
|
+
const DIRTY_DISPATCH_TOKEN = Symbol("nocobaseDirtyDispatchToken");
|
|
36
38
|
const dirtyAwareApiClientCache = /* @__PURE__ */ new WeakMap();
|
|
37
39
|
const dirtyAwareApiClientProxies = /* @__PURE__ */ new WeakSet();
|
|
38
40
|
const MUTATING_RESOURCE_ACTIONS = [
|
|
@@ -288,6 +290,43 @@ function resolveDirtyResourceAction(options, context) {
|
|
|
288
290
|
return parseDirtyResourceActionFromUrl(options == null ? void 0 : options.url, context);
|
|
289
291
|
}
|
|
290
292
|
__name(resolveDirtyResourceAction, "resolveDirtyResourceAction");
|
|
293
|
+
function getDirtyResourceActionDispatchKey(dirtyResourceAction, headers) {
|
|
294
|
+
if (!dirtyResourceAction) {
|
|
295
|
+
return void 0;
|
|
296
|
+
}
|
|
297
|
+
return JSON.stringify([
|
|
298
|
+
dirtyResourceAction.dataSourceKey || (0, import_dataSourceDirty.getDataSourceKeyFromHeaders)(headers),
|
|
299
|
+
dirtyResourceAction.resourceName,
|
|
300
|
+
dirtyResourceAction.actionName
|
|
301
|
+
]);
|
|
302
|
+
}
|
|
303
|
+
__name(getDirtyResourceActionDispatchKey, "getDirtyResourceActionDispatchKey");
|
|
304
|
+
function getRequestDispatchKey(options, context) {
|
|
305
|
+
return getDirtyResourceActionDispatchKey(resolveDirtyResourceAction(options, context), options.headers);
|
|
306
|
+
}
|
|
307
|
+
__name(getRequestDispatchKey, "getRequestDispatchKey");
|
|
308
|
+
function getResourceDispatchKey(name, of, headers) {
|
|
309
|
+
const resourceName = String(name ?? "").trim();
|
|
310
|
+
if (!resourceName) {
|
|
311
|
+
return void 0;
|
|
312
|
+
}
|
|
313
|
+
return JSON.stringify([resourceName, String(of ?? ""), (0, import_dataSourceDirty.getDataSourceKeyFromHeaders)(headers)]);
|
|
314
|
+
}
|
|
315
|
+
__name(getResourceDispatchKey, "getResourceDispatchKey");
|
|
316
|
+
function getMatchingRequestToken(token, requestKey) {
|
|
317
|
+
if (!token || !requestKey || token.requestKey && token.requestKey !== requestKey) {
|
|
318
|
+
return void 0;
|
|
319
|
+
}
|
|
320
|
+
return token;
|
|
321
|
+
}
|
|
322
|
+
__name(getMatchingRequestToken, "getMatchingRequestToken");
|
|
323
|
+
function getMatchingResourceToken(token, resourceKey) {
|
|
324
|
+
if (!token || !resourceKey || token.resourceKey && token.resourceKey !== resourceKey) {
|
|
325
|
+
return void 0;
|
|
326
|
+
}
|
|
327
|
+
return token;
|
|
328
|
+
}
|
|
329
|
+
__name(getMatchingResourceToken, "getMatchingResourceToken");
|
|
291
330
|
function markResourceActionDataSourceDirty(context, dirtyResourceAction, headers) {
|
|
292
331
|
(0, import_dataSourceDirty.markDataSourceDirty)({
|
|
293
332
|
engine: context.engine,
|
|
@@ -297,7 +336,19 @@ function markResourceActionDataSourceDirty(context, dirtyResourceAction, headers
|
|
|
297
336
|
});
|
|
298
337
|
}
|
|
299
338
|
__name(markResourceActionDataSourceDirty, "markResourceActionDataSourceDirty");
|
|
300
|
-
function
|
|
339
|
+
function markResourceActionDataSourceDirtyOnce(token, context, dirtyResourceAction, headers) {
|
|
340
|
+
if (token.skip || token.marked || !dirtyResourceAction || !isMutatingResourceAction(dirtyResourceAction.actionName)) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
token.marked = true;
|
|
344
|
+
markResourceActionDataSourceDirty(context, dirtyResourceAction, headers);
|
|
345
|
+
}
|
|
346
|
+
__name(markResourceActionDataSourceDirtyOnce, "markResourceActionDataSourceDirtyOnce");
|
|
347
|
+
function isObjectRecord(value) {
|
|
348
|
+
return !!value && typeof value === "object";
|
|
349
|
+
}
|
|
350
|
+
__name(isObjectRecord, "isObjectRecord");
|
|
351
|
+
function createDirtyAwareResource(context, resource, resourceName, resourceOf, headers, requestTokenStack, parentToken) {
|
|
301
352
|
return new Proxy(resource, {
|
|
302
353
|
get(target, prop, receiver) {
|
|
303
354
|
const original = Reflect.get(target, prop, receiver);
|
|
@@ -306,10 +357,38 @@ function createDirtyAwareResource(context, resource, resourceName, resourceOf, h
|
|
|
306
357
|
}
|
|
307
358
|
const action = original;
|
|
308
359
|
return async (...args) => {
|
|
309
|
-
const
|
|
360
|
+
const actionOptions = isObjectRecord(args[1]) ? args[1] : void 0;
|
|
310
361
|
const dirtyResourceAction = resolveDirtyResourceActionFromResource(resourceName, resourceOf, prop, context);
|
|
311
|
-
|
|
312
|
-
|
|
362
|
+
const requestKey = getDirtyResourceActionDispatchKey(dirtyResourceAction, headers);
|
|
363
|
+
const resourceKey = getResourceDispatchKey(resourceName, resourceOf, headers);
|
|
364
|
+
const inheritedToken = getMatchingRequestToken(
|
|
365
|
+
actionOptions == null ? void 0 : actionOptions[DIRTY_DISPATCH_TOKEN],
|
|
366
|
+
requestKey
|
|
367
|
+
) || getMatchingRequestToken(parentToken, requestKey);
|
|
368
|
+
const token = inheritedToken || { marked: false, skip: false };
|
|
369
|
+
const ownsToken = !inheritedToken;
|
|
370
|
+
token.requestKey ||= requestKey;
|
|
371
|
+
token.resourceKey ||= resourceKey;
|
|
372
|
+
if (actionOptions == null ? void 0 : actionOptions[SKIP_DATA_SOURCE_DIRTY]) {
|
|
373
|
+
token.skip = true;
|
|
374
|
+
}
|
|
375
|
+
const forwardedArgs = actionOptions || args[1] == null ? [
|
|
376
|
+
args[0],
|
|
377
|
+
{
|
|
378
|
+
...actionOptions,
|
|
379
|
+
[DIRTY_DISPATCH_TOKEN]: token
|
|
380
|
+
}
|
|
381
|
+
] : args;
|
|
382
|
+
let actionResult;
|
|
383
|
+
requestTokenStack.push({ key: requestKey, token });
|
|
384
|
+
try {
|
|
385
|
+
actionResult = Reflect.apply(action, receiver, forwardedArgs);
|
|
386
|
+
} finally {
|
|
387
|
+
requestTokenStack.pop();
|
|
388
|
+
}
|
|
389
|
+
const result = await actionResult;
|
|
390
|
+
if (ownsToken) {
|
|
391
|
+
markResourceActionDataSourceDirtyOnce(token, context, dirtyResourceAction, headers);
|
|
313
392
|
}
|
|
314
393
|
return result;
|
|
315
394
|
};
|
|
@@ -318,31 +397,206 @@ function createDirtyAwareResource(context, resource, resourceName, resourceOf, h
|
|
|
318
397
|
}
|
|
319
398
|
__name(createDirtyAwareResource, "createDirtyAwareResource");
|
|
320
399
|
function createDirtyAwareApiClient(api, context) {
|
|
400
|
+
const baseResource = api.resource;
|
|
401
|
+
const baseRequest = api.request;
|
|
402
|
+
const shouldUseResourceDispatchReceiver = baseResource === import_sdk.APIClient.prototype.resource;
|
|
403
|
+
const shouldUseRequestDispatchReceiver = baseRequest === import_sdk.APIClient.prototype.request;
|
|
404
|
+
const resourceTokenStack = [];
|
|
405
|
+
const requestTokenStack = [];
|
|
406
|
+
let hasResourceOverride = false;
|
|
407
|
+
let resourceOverride;
|
|
408
|
+
let hasRequestOverride = false;
|
|
409
|
+
let requestOverride;
|
|
410
|
+
const getCurrentResource = /* @__PURE__ */ __name(() => hasResourceOverride ? resourceOverride : resource, "getCurrentResource");
|
|
411
|
+
const getCurrentRequest = /* @__PURE__ */ __name(() => hasRequestOverride ? requestOverride : request, "getCurrentRequest");
|
|
412
|
+
const dispatchResource = /* @__PURE__ */ __name((token, args) => {
|
|
413
|
+
const resourceKey = getResourceDispatchKey(args[0], args[1], args[2]);
|
|
414
|
+
const activeToken = getMatchingResourceToken(token, resourceKey);
|
|
415
|
+
const shouldWrapActions = !!activeToken && hasResourceOverride;
|
|
416
|
+
if (activeToken) {
|
|
417
|
+
activeToken.resourceKey ||= resourceKey;
|
|
418
|
+
resourceTokenStack.push({ key: resourceKey, token: activeToken });
|
|
419
|
+
}
|
|
420
|
+
try {
|
|
421
|
+
const resourceInstance = Reflect.apply(getCurrentResource(), proxy, args);
|
|
422
|
+
if (!shouldWrapActions || !activeToken) {
|
|
423
|
+
return resourceInstance;
|
|
424
|
+
}
|
|
425
|
+
return new Proxy(resourceInstance, {
|
|
426
|
+
get(target, prop, receiver) {
|
|
427
|
+
const original = Reflect.get(target, prop, receiver);
|
|
428
|
+
if (typeof prop !== "string" || typeof original !== "function" || !isMutatingResourceAction(prop)) {
|
|
429
|
+
return original;
|
|
430
|
+
}
|
|
431
|
+
const action = original;
|
|
432
|
+
return (...actionArgs) => {
|
|
433
|
+
const actionOptions = isObjectRecord(actionArgs[1]) ? actionArgs[1] : void 0;
|
|
434
|
+
const forwardedArgs = actionOptions || actionArgs[1] == null ? [
|
|
435
|
+
actionArgs[0],
|
|
436
|
+
{
|
|
437
|
+
...actionOptions,
|
|
438
|
+
[DIRTY_DISPATCH_TOKEN]: activeToken
|
|
439
|
+
}
|
|
440
|
+
] : actionArgs;
|
|
441
|
+
resourceTokenStack.push({ key: resourceKey, token: activeToken });
|
|
442
|
+
requestTokenStack.push({ key: activeToken.requestKey, token: activeToken });
|
|
443
|
+
try {
|
|
444
|
+
return Reflect.apply(action, receiver, forwardedArgs);
|
|
445
|
+
} finally {
|
|
446
|
+
requestTokenStack.pop();
|
|
447
|
+
resourceTokenStack.pop();
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
} finally {
|
|
453
|
+
if (activeToken) {
|
|
454
|
+
resourceTokenStack.pop();
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}, "dispatchResource");
|
|
458
|
+
const createDispatchReceiver = /* @__PURE__ */ __name((token) => {
|
|
459
|
+
const receiver = Object.create(api);
|
|
460
|
+
Object.defineProperties(receiver, {
|
|
461
|
+
request: {
|
|
462
|
+
configurable: true,
|
|
463
|
+
value: /* @__PURE__ */ __name((config) => {
|
|
464
|
+
const options = config;
|
|
465
|
+
const requestKey = getRequestDispatchKey(options, context);
|
|
466
|
+
const stackFrame = requestTokenStack.at(-1);
|
|
467
|
+
const activeToken = getMatchingRequestToken(options == null ? void 0 : options[DIRTY_DISPATCH_TOKEN], requestKey) || (requestKey && (stackFrame == null ? void 0 : stackFrame.key) === requestKey ? stackFrame.token : void 0) || getMatchingRequestToken(token, requestKey);
|
|
468
|
+
const { [DIRTY_DISPATCH_TOKEN]: _dirtyDispatchToken, ...cleanOptions } = options;
|
|
469
|
+
const configWithToken = activeToken ? { ...cleanOptions, [DIRTY_DISPATCH_TOKEN]: activeToken } : cleanOptions;
|
|
470
|
+
if (activeToken) {
|
|
471
|
+
activeToken.requestKey ||= requestKey;
|
|
472
|
+
requestTokenStack.push({ key: requestKey, token: activeToken });
|
|
473
|
+
}
|
|
474
|
+
try {
|
|
475
|
+
return Reflect.apply(getCurrentRequest(), proxy, [configWithToken]);
|
|
476
|
+
} finally {
|
|
477
|
+
if (activeToken) {
|
|
478
|
+
requestTokenStack.pop();
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}, "value")
|
|
482
|
+
},
|
|
483
|
+
resource: {
|
|
484
|
+
configurable: true,
|
|
485
|
+
value: /* @__PURE__ */ __name((...args) => {
|
|
486
|
+
const resourceKey = getResourceDispatchKey(args[0], args[1], args[2]);
|
|
487
|
+
const stackFrame = resourceTokenStack.at(-1);
|
|
488
|
+
const activeToken = getMatchingResourceToken(token, resourceKey) || (resourceKey && (stackFrame == null ? void 0 : stackFrame.key) === resourceKey ? stackFrame.token : void 0);
|
|
489
|
+
return dispatchResource(activeToken, args);
|
|
490
|
+
}, "value")
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
return receiver;
|
|
494
|
+
}, "createDispatchReceiver");
|
|
321
495
|
const resource = /* @__PURE__ */ __name((name, of, headers, cancel) => {
|
|
322
|
-
const
|
|
323
|
-
|
|
496
|
+
const resourceKey = getResourceDispatchKey(name, of, headers);
|
|
497
|
+
const stackFrame = resourceTokenStack.at(-1);
|
|
498
|
+
const parentToken = resourceKey && (stackFrame == null ? void 0 : stackFrame.key) === resourceKey ? stackFrame.token : void 0;
|
|
499
|
+
const receiver = createDispatchReceiver(parentToken);
|
|
500
|
+
const resourceInstance = Reflect.apply(baseResource, shouldUseResourceDispatchReceiver ? receiver : api, [
|
|
501
|
+
name,
|
|
502
|
+
of,
|
|
503
|
+
headers,
|
|
504
|
+
cancel
|
|
505
|
+
]);
|
|
506
|
+
return createDirtyAwareResource(context, resourceInstance, name, of, headers, requestTokenStack, parentToken);
|
|
324
507
|
}, "resource");
|
|
325
508
|
const request = /* @__PURE__ */ __name((config) => {
|
|
326
509
|
const options = config;
|
|
510
|
+
const requestKey = getRequestDispatchKey(options, context);
|
|
511
|
+
const stackFrame = requestTokenStack.at(-1);
|
|
512
|
+
const inheritedToken = getMatchingRequestToken(options == null ? void 0 : options[DIRTY_DISPATCH_TOKEN], requestKey) || (requestKey && (stackFrame == null ? void 0 : stackFrame.key) === requestKey ? stackFrame.token : void 0);
|
|
513
|
+
const token = inheritedToken || { marked: false, skip: false };
|
|
514
|
+
const ownsToken = !inheritedToken;
|
|
515
|
+
token.requestKey ||= requestKey;
|
|
516
|
+
if (typeof options.resource === "string") {
|
|
517
|
+
token.resourceKey ||= getResourceDispatchKey(options.resource, options.resourceOf, options.headers);
|
|
518
|
+
}
|
|
327
519
|
const skipDataSourceDirty = options == null ? void 0 : options[SKIP_DATA_SOURCE_DIRTY];
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
520
|
+
if (skipDataSourceDirty) {
|
|
521
|
+
token.skip = true;
|
|
522
|
+
}
|
|
523
|
+
const dirtyResourceAction = resolveDirtyResourceAction(options, context);
|
|
524
|
+
const {
|
|
525
|
+
[DIRTY_DISPATCH_TOKEN]: _dirtyDispatchToken,
|
|
526
|
+
[SKIP_DATA_SOURCE_DIRTY]: _skipDataSourceDirty,
|
|
527
|
+
...cleanConfig
|
|
528
|
+
} = options;
|
|
529
|
+
const receiver = createDispatchReceiver(token);
|
|
530
|
+
return Reflect.apply(baseRequest, shouldUseRequestDispatchReceiver ? receiver : api, [cleanConfig]).then((result) => {
|
|
531
|
+
if (ownsToken) {
|
|
532
|
+
markResourceActionDataSourceDirtyOnce(token, context, dirtyResourceAction, options.headers);
|
|
333
533
|
}
|
|
334
534
|
return result;
|
|
335
535
|
});
|
|
336
536
|
}, "request");
|
|
537
|
+
const isLockedOwnProperty = /* @__PURE__ */ __name((target, prop) => {
|
|
538
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
|
|
539
|
+
return !!descriptor && !descriptor.configurable;
|
|
540
|
+
}, "isLockedOwnProperty");
|
|
337
541
|
const proxy = new Proxy(api, {
|
|
338
542
|
get(target, prop, receiver) {
|
|
339
543
|
if (prop === "resource") {
|
|
340
|
-
|
|
544
|
+
if (isLockedOwnProperty(target, prop)) {
|
|
545
|
+
return Reflect.get(target, prop, receiver);
|
|
546
|
+
}
|
|
547
|
+
return hasResourceOverride ? resourceOverride : resource;
|
|
341
548
|
}
|
|
342
549
|
if (prop === "request") {
|
|
343
|
-
|
|
550
|
+
if (isLockedOwnProperty(target, prop)) {
|
|
551
|
+
return Reflect.get(target, prop, receiver);
|
|
552
|
+
}
|
|
553
|
+
return hasRequestOverride ? requestOverride : request;
|
|
344
554
|
}
|
|
345
555
|
return Reflect.get(target, prop, receiver);
|
|
556
|
+
},
|
|
557
|
+
set(target, prop, value, receiver) {
|
|
558
|
+
if (prop === "resource") {
|
|
559
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
|
|
560
|
+
if (descriptor && (!descriptor.configurable || !Reflect.isExtensible(target))) {
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
hasResourceOverride = true;
|
|
564
|
+
resourceOverride = value;
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
if (prop === "request") {
|
|
568
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
|
|
569
|
+
if (descriptor && (!descriptor.configurable || !Reflect.isExtensible(target))) {
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
hasRequestOverride = true;
|
|
573
|
+
requestOverride = value;
|
|
574
|
+
return true;
|
|
575
|
+
}
|
|
576
|
+
return Reflect.set(target, prop, value, receiver);
|
|
577
|
+
},
|
|
578
|
+
deleteProperty(target, prop) {
|
|
579
|
+
if (prop !== "resource" && prop !== "request") {
|
|
580
|
+
return Reflect.deleteProperty(target, prop);
|
|
581
|
+
}
|
|
582
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
|
|
583
|
+
if (descriptor && (!descriptor.configurable || !Reflect.isExtensible(target))) {
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
if (prop === "resource") {
|
|
587
|
+
hasResourceOverride = false;
|
|
588
|
+
resourceOverride = void 0;
|
|
589
|
+
} else {
|
|
590
|
+
hasRequestOverride = false;
|
|
591
|
+
requestOverride = void 0;
|
|
592
|
+
}
|
|
593
|
+
return true;
|
|
594
|
+
},
|
|
595
|
+
defineProperty(target, prop, descriptor) {
|
|
596
|
+
if (prop === "resource" || prop === "request") {
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
return Reflect.defineProperty(target, prop, descriptor);
|
|
346
600
|
}
|
|
347
601
|
});
|
|
348
602
|
dirtyAwareApiClientProxies.add(proxy);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/flow-engine",
|
|
3
|
-
"version": "2.2.0-alpha.
|
|
3
|
+
"version": "2.2.0-alpha.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A standalone flow engine for NocoBase, managing workflows, models, and actions.",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@formily/antd-v5": "1.x",
|
|
10
10
|
"@formily/reactive": "2.x",
|
|
11
|
-
"@nocobase/sdk": "2.2.0-alpha.
|
|
12
|
-
"@nocobase/shared": "2.2.0-alpha.
|
|
11
|
+
"@nocobase/sdk": "2.2.0-alpha.8",
|
|
12
|
+
"@nocobase/shared": "2.2.0-alpha.8",
|
|
13
13
|
"ahooks": "^3.7.2",
|
|
14
14
|
"axios": "^1.7.0",
|
|
15
15
|
"dayjs": "^1.11.9",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
],
|
|
38
38
|
"author": "NocoBase Team",
|
|
39
39
|
"license": "Apache-2.0",
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "810c81e5963966bda7ec03b6453a3a80fe60e027"
|
|
41
41
|
}
|
|
@@ -125,16 +125,19 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
125
125
|
[onChange],
|
|
126
126
|
);
|
|
127
127
|
|
|
128
|
+
const resolvedPath = useMemo(() => {
|
|
129
|
+
return resolvePathFromValue?.(innerValue);
|
|
130
|
+
}, [innerValue, resolvePathFromValue]);
|
|
131
|
+
|
|
128
132
|
const resolvedMetaTreeNode = useMemo(() => {
|
|
129
133
|
if (currentMetaTreeNode) return currentMetaTreeNode;
|
|
130
134
|
if (Array.isArray(resolvedMetaTree)) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return findMetaTreeNodeByPath(resolvedMetaTree, path);
|
|
135
|
+
if (resolvedPath) {
|
|
136
|
+
return findMetaTreeNodeByPath(resolvedMetaTree, resolvedPath);
|
|
134
137
|
}
|
|
135
138
|
}
|
|
136
139
|
return null;
|
|
137
|
-
}, [currentMetaTreeNode,
|
|
140
|
+
}, [currentMetaTreeNode, resolvedMetaTree, resolvedPath]);
|
|
138
141
|
|
|
139
142
|
// 当 value 存在但 currentMetaTreeNode 还未恢复,尝试按路径逐级加载(支持 children 为函数的场景)
|
|
140
143
|
useEffect(() => {
|
|
@@ -197,9 +200,31 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
197
200
|
const ValueComponent = useMemo(() => {
|
|
198
201
|
const Component = renderInputComponent?.(resolvedMetaTreeNode);
|
|
199
202
|
const CustomComponent = resolvedMetaTreeNode?.render;
|
|
200
|
-
|
|
203
|
+
// Some domains (workflow) persist variables as `{{$context...}}` rather than the core `{{ ctx... }}` form.
|
|
204
|
+
// Those values are not recognized by `isVariableValue`, but if the active converters can resolve them back to a
|
|
205
|
+
// real meta-tree path and that path maps to a plain variable node (not Constant / Null / RunJS), they should still
|
|
206
|
+
// render as the labelled pill instead of falling back to the raw input text.
|
|
207
|
+
const shouldRenderVariableTag =
|
|
208
|
+
isVariableValue(innerValue) ||
|
|
209
|
+
(Boolean(resolvedMetaTreeNode) &&
|
|
210
|
+
Array.isArray(resolvedPath) &&
|
|
211
|
+
resolvedPath.length > 0 &&
|
|
212
|
+
!Component &&
|
|
213
|
+
!CustomComponent);
|
|
214
|
+
const finalComponent = shouldRenderVariableTag ? VariableTag : Component || CustomComponent || Input;
|
|
201
215
|
return finalComponent;
|
|
202
|
-
}, [renderInputComponent, resolvedMetaTreeNode, innerValue]);
|
|
216
|
+
}, [renderInputComponent, resolvedMetaTreeNode, innerValue, resolvedPath]);
|
|
217
|
+
|
|
218
|
+
const isVariableActive = useMemo(() => {
|
|
219
|
+
return (
|
|
220
|
+
isVariableValue(innerValue) ||
|
|
221
|
+
(Boolean(resolvedMetaTreeNode) &&
|
|
222
|
+
Array.isArray(resolvedPath) &&
|
|
223
|
+
resolvedPath.length > 0 &&
|
|
224
|
+
!renderInputComponent?.(resolvedMetaTreeNode) &&
|
|
225
|
+
!resolvedMetaTreeNode?.render)
|
|
226
|
+
);
|
|
227
|
+
}, [innerValue, renderInputComponent, resolvedMetaTreeNode, resolvedPath]);
|
|
203
228
|
|
|
204
229
|
useEffect(() => {
|
|
205
230
|
if (!resolvedMetaTreeNode) return;
|
|
@@ -303,6 +328,8 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
303
328
|
return {
|
|
304
329
|
...baseProps,
|
|
305
330
|
onClear: handleClear,
|
|
331
|
+
disabled,
|
|
332
|
+
allowCustomTagInput: false,
|
|
306
333
|
metaTreeNode: resolvedMetaTreeNode,
|
|
307
334
|
metaTree,
|
|
308
335
|
style: stableProps.style,
|
|
@@ -356,7 +383,7 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
356
383
|
<FlowContextSelector
|
|
357
384
|
metaTree={resolvedMetaTree}
|
|
358
385
|
value={innerValue}
|
|
359
|
-
active={
|
|
386
|
+
active={isVariableActive}
|
|
360
387
|
disabled={disabled}
|
|
361
388
|
onChange={handleVariableSelect}
|
|
362
389
|
parseValueToPath={resolvePathFromValue}
|