@nocobase/flow-engine 2.2.0-alpha.8 → 2.2.0-alpha.9
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 +4 -2
- package/lib/components/variables/VariableTag.js +5 -4
- package/lib/components/variables/types.d.ts +1 -0
- package/lib/types.d.ts +3 -1
- package/lib/types.js +1 -0
- package/package.json +4 -4
- package/src/components/variables/VariableInput.tsx +6 -10
- package/src/components/variables/VariableTag.tsx +4 -3
- package/src/components/variables/__tests__/VariableInput.test.tsx +46 -0
- package/src/components/variables/types.ts +1 -0
- package/src/types.ts +2 -0
|
@@ -194,12 +194,12 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
194
194
|
const ValueComponent = (0, import_react.useMemo)(() => {
|
|
195
195
|
const Component = renderInputComponent == null ? void 0 : renderInputComponent(resolvedMetaTreeNode);
|
|
196
196
|
const CustomComponent = resolvedMetaTreeNode == null ? void 0 : resolvedMetaTreeNode.render;
|
|
197
|
-
const shouldRenderVariableTag = (0, import_utils.isVariableValue)(innerValue) ||
|
|
197
|
+
const shouldRenderVariableTag = (0, import_utils.isVariableValue)(innerValue) || Array.isArray(resolvedPath) && resolvedPath.length > 0 && !Component && !CustomComponent;
|
|
198
198
|
const finalComponent = shouldRenderVariableTag ? import_VariableTag.VariableTag : Component || CustomComponent || import_antd.Input;
|
|
199
199
|
return finalComponent;
|
|
200
200
|
}, [renderInputComponent, resolvedMetaTreeNode, innerValue, resolvedPath]);
|
|
201
201
|
const isVariableActive = (0, import_react.useMemo)(() => {
|
|
202
|
-
return (0, import_utils.isVariableValue)(innerValue) ||
|
|
202
|
+
return (0, import_utils.isVariableValue)(innerValue) || Array.isArray(resolvedPath) && resolvedPath.length > 0 && !(renderInputComponent == null ? void 0 : renderInputComponent(resolvedMetaTreeNode)) && !(resolvedMetaTreeNode == null ? void 0 : resolvedMetaTreeNode.render);
|
|
203
203
|
}, [innerValue, renderInputComponent, resolvedMetaTreeNode, resolvedPath]);
|
|
204
204
|
(0, import_react.useEffect)(() => {
|
|
205
205
|
if (!resolvedMetaTreeNode) return;
|
|
@@ -288,6 +288,7 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
288
288
|
allowCustomTagInput: false,
|
|
289
289
|
metaTreeNode: resolvedMetaTreeNode,
|
|
290
290
|
metaTree,
|
|
291
|
+
resolvedPath,
|
|
291
292
|
style: stableProps.style
|
|
292
293
|
};
|
|
293
294
|
}
|
|
@@ -308,6 +309,7 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
308
309
|
disabled,
|
|
309
310
|
handleClear,
|
|
310
311
|
resolvedMetaTreeNode,
|
|
312
|
+
resolvedPath,
|
|
311
313
|
metaTree,
|
|
312
314
|
ValueComponent,
|
|
313
315
|
stableProps
|
|
@@ -56,7 +56,8 @@ const VariableTagComponent = /* @__PURE__ */ __name(({
|
|
|
56
56
|
className,
|
|
57
57
|
style,
|
|
58
58
|
metaTreeNode,
|
|
59
|
-
metaTree
|
|
59
|
+
metaTree,
|
|
60
|
+
resolvedPath
|
|
60
61
|
}) => {
|
|
61
62
|
const { resolvedMetaTree } = (0, import_useResolvedMetaTree.useResolvedMetaTree)(metaTree);
|
|
62
63
|
const ctx = (0, import_FlowContextProvider.useFlowContext)();
|
|
@@ -102,7 +103,7 @@ const VariableTagComponent = /* @__PURE__ */ __name(({
|
|
|
102
103
|
};
|
|
103
104
|
}
|
|
104
105
|
if (metaTreeNode) {
|
|
105
|
-
const rawPath2 = (0, import_utils.parseValueToPath)(value) || metaTreeNode.paths;
|
|
106
|
+
const rawPath2 = resolvedPath || (0, import_utils.parseValueToPath)(value) || metaTreeNode.paths;
|
|
106
107
|
const result2 = await resolveLabelFromPath(rawPath2);
|
|
107
108
|
if (result2.resolved && result2.label != null) {
|
|
108
109
|
return { text: result2.label, invalid: false };
|
|
@@ -113,7 +114,7 @@ const VariableTagComponent = /* @__PURE__ */ __name(({
|
|
|
113
114
|
return { text: ctx.t(metaTreeNode.title) ?? "", invalid: false };
|
|
114
115
|
}
|
|
115
116
|
if (!value) return { text: String(value), invalid: false };
|
|
116
|
-
const rawPath = (0, import_utils.parseValueToPath)(value);
|
|
117
|
+
const rawPath = resolvedPath || (0, import_utils.parseValueToPath)(value);
|
|
117
118
|
const result = await resolveLabelFromPath(rawPath);
|
|
118
119
|
if (result.resolved && result.label != null) {
|
|
119
120
|
return { text: result.label, invalid: false };
|
|
@@ -123,7 +124,7 @@ const VariableTagComponent = /* @__PURE__ */ __name(({
|
|
|
123
124
|
}
|
|
124
125
|
return { text: Array.isArray(rawPath) ? rawPath.join("/") : String(value), invalid: false };
|
|
125
126
|
},
|
|
126
|
-
{ refreshDeps: [resolvedMetaTree, value, metaTreeNode] }
|
|
127
|
+
{ refreshDeps: [resolvedMetaTree, resolvedPath, value, metaTreeNode] }
|
|
127
128
|
);
|
|
128
129
|
const { token } = import_antd.theme.useToken();
|
|
129
130
|
const shrinkableOverflowItem = import_css.css`
|
package/lib/types.d.ts
CHANGED
|
@@ -122,7 +122,9 @@ export declare enum ActionScene {
|
|
|
122
122
|
/** 动态事件流可用 */
|
|
123
123
|
DYNAMIC_EVENT_FLOW = 6,
|
|
124
124
|
/** 菜单项联动规则可用 */
|
|
125
|
-
MENU_LINKAGE_RULES = 7
|
|
125
|
+
MENU_LINKAGE_RULES = 7,
|
|
126
|
+
/** 标签页联动规则可用 */
|
|
127
|
+
TAB_LINKAGE_RULES = 8
|
|
126
128
|
}
|
|
127
129
|
/**
|
|
128
130
|
* Defines a reusable action with generic model type support.
|
package/lib/types.js
CHANGED
|
@@ -37,6 +37,7 @@ var ActionScene = /* @__PURE__ */ ((ActionScene2) => {
|
|
|
37
37
|
ActionScene2[ActionScene2["ACTION_LINKAGE_RULES"] = 5] = "ACTION_LINKAGE_RULES";
|
|
38
38
|
ActionScene2[ActionScene2["DYNAMIC_EVENT_FLOW"] = 6] = "DYNAMIC_EVENT_FLOW";
|
|
39
39
|
ActionScene2[ActionScene2["MENU_LINKAGE_RULES"] = 7] = "MENU_LINKAGE_RULES";
|
|
40
|
+
ActionScene2[ActionScene2["TAB_LINKAGE_RULES"] = 8] = "TAB_LINKAGE_RULES";
|
|
40
41
|
return ActionScene2;
|
|
41
42
|
})(ActionScene || {});
|
|
42
43
|
// Annotate the CommonJS export names for ESM import in node:
|
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.9",
|
|
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.9",
|
|
12
|
+
"@nocobase/shared": "2.2.0-alpha.9",
|
|
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": "4949bf5ebcd92d77a3a0a718ed578c270e4bd570"
|
|
41
41
|
}
|
|
@@ -201,16 +201,11 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
201
201
|
const Component = renderInputComponent?.(resolvedMetaTreeNode);
|
|
202
202
|
const CustomComponent = resolvedMetaTreeNode?.render;
|
|
203
203
|
// Some domains (workflow) persist variables as `{{$context...}}` rather than the core `{{ ctx... }}` form.
|
|
204
|
-
//
|
|
205
|
-
//
|
|
206
|
-
// render as the labelled pill instead of falling back to the raw input text.
|
|
204
|
+
// When a custom converter recognizes such a value as a variable path, render VariableTag even if the path no longer
|
|
205
|
+
// exists in the current meta tree. VariableTag will then show either the resolved label or the parsing-failed state.
|
|
207
206
|
const shouldRenderVariableTag =
|
|
208
207
|
isVariableValue(innerValue) ||
|
|
209
|
-
(
|
|
210
|
-
Array.isArray(resolvedPath) &&
|
|
211
|
-
resolvedPath.length > 0 &&
|
|
212
|
-
!Component &&
|
|
213
|
-
!CustomComponent);
|
|
208
|
+
(Array.isArray(resolvedPath) && resolvedPath.length > 0 && !Component && !CustomComponent);
|
|
214
209
|
const finalComponent = shouldRenderVariableTag ? VariableTag : Component || CustomComponent || Input;
|
|
215
210
|
return finalComponent;
|
|
216
211
|
}, [renderInputComponent, resolvedMetaTreeNode, innerValue, resolvedPath]);
|
|
@@ -218,8 +213,7 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
218
213
|
const isVariableActive = useMemo(() => {
|
|
219
214
|
return (
|
|
220
215
|
isVariableValue(innerValue) ||
|
|
221
|
-
(
|
|
222
|
-
Array.isArray(resolvedPath) &&
|
|
216
|
+
(Array.isArray(resolvedPath) &&
|
|
223
217
|
resolvedPath.length > 0 &&
|
|
224
218
|
!renderInputComponent?.(resolvedMetaTreeNode) &&
|
|
225
219
|
!resolvedMetaTreeNode?.render)
|
|
@@ -332,6 +326,7 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
332
326
|
allowCustomTagInput: false,
|
|
333
327
|
metaTreeNode: resolvedMetaTreeNode,
|
|
334
328
|
metaTree,
|
|
329
|
+
resolvedPath,
|
|
335
330
|
style: stableProps.style,
|
|
336
331
|
};
|
|
337
332
|
}
|
|
@@ -354,6 +349,7 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
354
349
|
disabled,
|
|
355
350
|
handleClear,
|
|
356
351
|
resolvedMetaTreeNode,
|
|
352
|
+
resolvedPath,
|
|
357
353
|
metaTree,
|
|
358
354
|
ValueComponent,
|
|
359
355
|
stableProps,
|
|
@@ -28,6 +28,7 @@ const VariableTagComponent: React.FC<VariableTagProps> = ({
|
|
|
28
28
|
style,
|
|
29
29
|
metaTreeNode,
|
|
30
30
|
metaTree,
|
|
31
|
+
resolvedPath,
|
|
31
32
|
}) => {
|
|
32
33
|
const { resolvedMetaTree } = useResolvedMetaTree(metaTree);
|
|
33
34
|
const ctx = useFlowContext();
|
|
@@ -87,7 +88,7 @@ const VariableTagComponent: React.FC<VariableTagProps> = ({
|
|
|
87
88
|
|
|
88
89
|
// 2) metaTreeNode 存在但缺少 parentTitles:尝试根据 value/metaTreeNode.paths 从 metaTree 还原完整路径
|
|
89
90
|
if (metaTreeNode) {
|
|
90
|
-
const rawPath = parseValueToPath(value) || metaTreeNode.paths;
|
|
91
|
+
const rawPath = resolvedPath || parseValueToPath(value) || metaTreeNode.paths;
|
|
91
92
|
const result = await resolveLabelFromPath(rawPath as any);
|
|
92
93
|
if (result.resolved && result.label != null) {
|
|
93
94
|
return { text: result.label, invalid: false };
|
|
@@ -100,7 +101,7 @@ const VariableTagComponent: React.FC<VariableTagProps> = ({
|
|
|
100
101
|
|
|
101
102
|
// 3) 无 metaTreeNode:从 value 还原路径并拼接标题链;若找不到任何前缀则回退原始路径字符串
|
|
102
103
|
if (!value) return { text: String(value), invalid: false };
|
|
103
|
-
const rawPath = parseValueToPath(value);
|
|
104
|
+
const rawPath = resolvedPath || parseValueToPath(value);
|
|
104
105
|
const result = await resolveLabelFromPath(rawPath as any);
|
|
105
106
|
if (result.resolved && result.label != null) {
|
|
106
107
|
return { text: result.label, invalid: false };
|
|
@@ -110,7 +111,7 @@ const VariableTagComponent: React.FC<VariableTagProps> = ({
|
|
|
110
111
|
}
|
|
111
112
|
return { text: Array.isArray(rawPath) ? rawPath.join('/') : String(value), invalid: false };
|
|
112
113
|
},
|
|
113
|
-
{ refreshDeps: [resolvedMetaTree, value, metaTreeNode] },
|
|
114
|
+
{ refreshDeps: [resolvedMetaTree, resolvedPath, value, metaTreeNode] },
|
|
114
115
|
);
|
|
115
116
|
|
|
116
117
|
const { token } = theme.useToken();
|
|
@@ -155,6 +155,52 @@ describe('VariableInput', () => {
|
|
|
155
155
|
expect(selectorButton.className).toContain('ant-btn-primary');
|
|
156
156
|
});
|
|
157
157
|
|
|
158
|
+
it('renders a parsing failure tag when a custom variable path is missing from the meta tree', async () => {
|
|
159
|
+
const flowContext = createTestFlowContext();
|
|
160
|
+
const workflowMetaTree = [
|
|
161
|
+
{
|
|
162
|
+
name: '$context',
|
|
163
|
+
title: 'Trigger variables',
|
|
164
|
+
type: 'object',
|
|
165
|
+
paths: ['$context'],
|
|
166
|
+
children: [
|
|
167
|
+
{
|
|
168
|
+
name: 'data',
|
|
169
|
+
title: 'Trigger data',
|
|
170
|
+
type: 'object',
|
|
171
|
+
paths: ['$context', 'data'],
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
render(
|
|
178
|
+
<TestFlowContextWrapper context={flowContext}>
|
|
179
|
+
<VariableInput
|
|
180
|
+
value="{{$context.data.id}}"
|
|
181
|
+
metaTree={workflowMetaTree}
|
|
182
|
+
converters={{
|
|
183
|
+
resolvePathFromValue: (currentValue) =>
|
|
184
|
+
currentValue === '{{$context.data.id}}' ? ['$context', 'data', 'id'] : undefined,
|
|
185
|
+
resolveValueFromPath: () => undefined,
|
|
186
|
+
}}
|
|
187
|
+
/>
|
|
188
|
+
</TestFlowContextWrapper>,
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
await waitFor(
|
|
192
|
+
() => {
|
|
193
|
+
const variableTag = screen.getByText('Variable parsing failed');
|
|
194
|
+
expect(variableTag).toBeInTheDocument();
|
|
195
|
+
expect(variableTag.closest('.ant-tag')).toHaveClass('ant-tag-error');
|
|
196
|
+
},
|
|
197
|
+
{ timeout: 3000 },
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
expect(screen.queryByDisplayValue('{{$context.data.id}}')).not.toBeInTheDocument();
|
|
201
|
+
expect(screen.getByRole('button').className).toContain('ant-btn-primary');
|
|
202
|
+
});
|
|
203
|
+
|
|
158
204
|
it('disables custom tag input when rendering a selected variable', async () => {
|
|
159
205
|
const flowContext = createTestFlowContext();
|
|
160
206
|
const { container } = render(
|