@nocobase/flow-engine 2.1.0-alpha.40 → 2.1.0-alpha.46
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/FlowContextProvider.d.ts +5 -1
- package/lib/FlowContextProvider.js +9 -2
- package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +84 -32
- package/lib/components/subModel/LazyDropdown.js +208 -16
- package/lib/components/subModel/utils.d.ts +1 -0
- package/lib/components/subModel/utils.js +6 -2
- package/lib/data-source/index.d.ts +9 -0
- package/lib/data-source/index.js +12 -0
- package/lib/executor/FlowExecutor.js +0 -3
- package/lib/flowContext.d.ts +6 -1
- package/lib/flowContext.js +38 -6
- package/lib/flowEngine.d.ts +4 -3
- package/lib/flowEngine.js +72 -40
- package/lib/models/flowModel.js +48 -16
- package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +4 -3
- package/lib/runjs-context/contexts/JSBlockRunJSContext.js +4 -15
- package/lib/runjs-context/contexts/JSColumnRunJSContext.js +5 -2
- package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.js +5 -8
- package/lib/runjs-context/contexts/JSFieldRunJSContext.js +4 -3
- package/lib/runjs-context/contexts/JSItemRunJSContext.js +4 -3
- package/lib/runjs-context/contexts/base.js +464 -29
- package/lib/runjs-context/contexts/elementDoc.d.ts +11 -0
- package/lib/runjs-context/contexts/elementDoc.js +152 -0
- package/lib/utils/loadedPageCache.d.ts +24 -0
- package/lib/utils/loadedPageCache.js +139 -0
- package/lib/utils/parsePathnameToViewParams.d.ts +5 -1
- package/lib/utils/parsePathnameToViewParams.js +28 -4
- package/lib/views/ViewNavigation.d.ts +12 -2
- package/lib/views/ViewNavigation.js +22 -7
- package/lib/views/createViewMeta.js +114 -50
- package/lib/views/inheritLayoutContext.d.ts +10 -0
- package/lib/views/inheritLayoutContext.js +50 -0
- package/lib/views/useDialog.js +2 -0
- package/lib/views/useDrawer.js +2 -0
- package/lib/views/usePage.js +2 -0
- package/package.json +4 -4
- package/src/FlowContextProvider.tsx +9 -1
- package/src/__tests__/createViewMeta.popup.test.ts +115 -1
- package/src/__tests__/flowContext.test.ts +23 -0
- package/src/__tests__/flowEngine.moveModel.test.ts +81 -1
- package/src/__tests__/flowEngine.removeModel.test.ts +47 -3
- package/src/__tests__/runjsContext.test.ts +18 -0
- package/src/__tests__/runjsContextImplementations.test.ts +9 -2
- package/src/__tests__/runjsLocales.test.ts +6 -5
- package/src/__tests__/viewScopedFlowEngine.test.ts +133 -0
- package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +90 -38
- package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +155 -5
- package/src/components/subModel/LazyDropdown.tsx +237 -16
- package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +254 -1
- package/src/components/subModel/utils.ts +6 -1
- package/src/data-source/index.ts +18 -0
- package/src/executor/FlowExecutor.ts +0 -3
- package/src/executor/__tests__/flowExecutor.test.ts +26 -0
- package/src/flowContext.ts +43 -6
- package/src/flowEngine.ts +75 -38
- package/src/models/__tests__/flowEngine.resolveUse.test.ts +0 -15
- package/src/models/__tests__/flowModel.test.ts +46 -62
- package/src/models/flowModel.tsx +65 -32
- package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +4 -3
- package/src/runjs-context/contexts/JSBlockRunJSContext.ts +4 -15
- package/src/runjs-context/contexts/JSColumnRunJSContext.ts +4 -2
- package/src/runjs-context/contexts/JSEditableFieldRunJSContext.ts +5 -9
- package/src/runjs-context/contexts/JSFieldRunJSContext.ts +4 -3
- package/src/runjs-context/contexts/JSItemRunJSContext.ts +4 -3
- package/src/runjs-context/contexts/base.ts +467 -31
- package/src/runjs-context/contexts/elementDoc.ts +130 -0
- package/src/utils/__tests__/parsePathnameToViewParams.test.ts +21 -0
- package/src/utils/loadedPageCache.ts +147 -0
- package/src/utils/parsePathnameToViewParams.ts +45 -5
- package/src/views/ViewNavigation.ts +40 -7
- package/src/views/__tests__/ViewNavigation.test.ts +52 -0
- package/src/views/__tests__/inheritLayoutContext.test.ts +53 -0
- package/src/views/createViewMeta.ts +106 -34
- package/src/views/inheritLayoutContext.ts +26 -0
- package/src/views/useDialog.tsx +2 -0
- package/src/views/useDrawer.tsx +2 -0
- package/src/views/usePage.tsx +2 -0
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import React from 'react';
|
|
10
10
|
import { FlowContext, FlowEngineContext } from './flowContext';
|
|
11
|
-
import { FlowView } from './views/FlowView';
|
|
11
|
+
import { FlowView, FlowViewer } from './views/FlowView';
|
|
12
12
|
export declare const FlowReactContext: React.Context<FlowContext>;
|
|
13
13
|
export declare const FlowViewContext: React.Context<FlowContext>;
|
|
14
14
|
export declare function FlowContextProvider(props: {
|
|
@@ -22,3 +22,7 @@ export declare const FlowViewContextProvider: React.MemoExoticComponent<(props:
|
|
|
22
22
|
export declare function useFlowContext<T = FlowEngineContext>(): T;
|
|
23
23
|
export declare function useFlowViewContext<T = FlowEngineContext>(): T;
|
|
24
24
|
export declare function useFlowView(): FlowView;
|
|
25
|
+
/**
|
|
26
|
+
* Access the `FlowViewer` that opens new drawers / modals / pages (`viewer.drawer({...})`, `viewer.modal({...})`, etc.). This is the counterpart to `useFlowView()`: `useFlowView()` returns the *current* mounted view (use it to close yourself, render Header/Footer slots, etc.), while `useFlowViewer()` returns the surface that lets you open a *new* view from inside any flow-context subtree.
|
|
27
|
+
*/
|
|
28
|
+
export declare function useFlowViewer(): FlowViewer;
|
|
@@ -43,7 +43,8 @@ __export(FlowContextProvider_exports, {
|
|
|
43
43
|
FlowViewContextProvider: () => FlowViewContextProvider,
|
|
44
44
|
useFlowContext: () => useFlowContext,
|
|
45
45
|
useFlowView: () => useFlowView,
|
|
46
|
-
useFlowViewContext: () => useFlowViewContext
|
|
46
|
+
useFlowViewContext: () => useFlowViewContext,
|
|
47
|
+
useFlowViewer: () => useFlowViewer
|
|
47
48
|
});
|
|
48
49
|
module.exports = __toCommonJS(FlowContextProvider_exports);
|
|
49
50
|
var import_react = __toESM(require("react"));
|
|
@@ -70,6 +71,11 @@ function useFlowView() {
|
|
|
70
71
|
return ctx.view;
|
|
71
72
|
}
|
|
72
73
|
__name(useFlowView, "useFlowView");
|
|
74
|
+
function useFlowViewer() {
|
|
75
|
+
const ctx = useFlowContext();
|
|
76
|
+
return ctx.viewer;
|
|
77
|
+
}
|
|
78
|
+
__name(useFlowViewer, "useFlowViewer");
|
|
73
79
|
// Annotate the CommonJS export names for ESM import in node:
|
|
74
80
|
0 && (module.exports = {
|
|
75
81
|
FlowContextProvider,
|
|
@@ -78,5 +84,6 @@ __name(useFlowView, "useFlowView");
|
|
|
78
84
|
FlowViewContextProvider,
|
|
79
85
|
useFlowContext,
|
|
80
86
|
useFlowView,
|
|
81
|
-
useFlowViewContext
|
|
87
|
+
useFlowViewContext,
|
|
88
|
+
useFlowViewer
|
|
82
89
|
});
|
|
@@ -183,6 +183,13 @@ const getToolbarPopupContainer = /* @__PURE__ */ __name((triggerNode) => {
|
|
|
183
183
|
}
|
|
184
184
|
return triggerNode.closest(TOOLBAR_ICONS_SELECTOR) || triggerNode.closest(TOOLBAR_CONTAINER_SELECTOR);
|
|
185
185
|
}, "getToolbarPopupContainer");
|
|
186
|
+
const removeExtraMenuItemClickHandlers = /* @__PURE__ */ __name((item) => {
|
|
187
|
+
const { onClick: _onClick, children, ...rest } = item;
|
|
188
|
+
return {
|
|
189
|
+
...rest,
|
|
190
|
+
children: (children == null ? void 0 : children.length) ? children.map(removeExtraMenuItemClickHandlers) : void 0
|
|
191
|
+
};
|
|
192
|
+
}, "removeExtraMenuItemClickHandlers");
|
|
186
193
|
const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
187
194
|
model,
|
|
188
195
|
showDeleteButton = true,
|
|
@@ -200,8 +207,17 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
200
207
|
const [visible, setVisible] = (0, import_react.useState)(false);
|
|
201
208
|
const [refreshTick, setRefreshTick] = (0, import_react.useState)(0);
|
|
202
209
|
const [extraMenuItems, setExtraMenuItems] = (0, import_react.useState)([]);
|
|
210
|
+
const [extraMenuItemsLoaded, setExtraMenuItemsLoaded] = (0, import_react.useState)(false);
|
|
203
211
|
const [configurableFlowsAndSteps, setConfigurableFlowsAndSteps] = (0, import_react.useState)([]);
|
|
204
212
|
const [isLoading, setIsLoading] = (0, import_react.useState)(true);
|
|
213
|
+
const commonExtras = (0, import_react.useMemo)(
|
|
214
|
+
() => extraMenuItems.filter((it) => it.group === "common-actions").sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0)),
|
|
215
|
+
[extraMenuItems]
|
|
216
|
+
);
|
|
217
|
+
const hasCommonActions = showCopyUidButton || showDeleteButton || commonExtras.length > 0;
|
|
218
|
+
const shouldDeferConfigLoading = flattenSubMenus && menuLevels > 1 && hasCommonActions;
|
|
219
|
+
const shouldWaitForCommonActionProbe = flattenSubMenus && menuLevels > 1 && !showCopyUidButton && !showDeleteButton && !extraMenuItemsLoaded;
|
|
220
|
+
const canRenderIcon = hasCommonActions || !isLoading && configurableFlowsAndSteps.length > 0;
|
|
205
221
|
const closeDropdown = (0, import_react.useCallback)(() => {
|
|
206
222
|
setVisible(false);
|
|
207
223
|
onDropdownVisibleChange == null ? void 0 : onDropdownVisibleChange(false);
|
|
@@ -233,24 +249,28 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
233
249
|
let mounted = true;
|
|
234
250
|
const loadExtras = /* @__PURE__ */ __name(async () => {
|
|
235
251
|
var _a;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
modelsToProcess
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
252
|
+
setExtraMenuItemsLoaded(false);
|
|
253
|
+
try {
|
|
254
|
+
const allExtras = [];
|
|
255
|
+
const modelsToProcess = [];
|
|
256
|
+
walkSubModels(model, { maxDepth: menuLevels, arrayLimit: 50, mode: "stack" }, (targetModel, { modelKey }) => {
|
|
257
|
+
modelsToProcess.push({ model: targetModel, modelKey });
|
|
258
|
+
});
|
|
259
|
+
for (const { model: targetModel, modelKey } of modelsToProcess) {
|
|
260
|
+
const Cls = targetModel.constructor;
|
|
261
|
+
const extras = await ((_a = Cls.getExtraMenuItems) == null ? void 0 : _a.call(Cls, targetModel, t));
|
|
262
|
+
if (extras == null ? void 0 : extras.length) {
|
|
263
|
+
allExtras.push(
|
|
264
|
+
...extras.map((item) => ({
|
|
265
|
+
...item,
|
|
266
|
+
key: modelKey ? `${modelKey}:${item.key}` : item.key
|
|
267
|
+
}))
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (!mounted) {
|
|
272
|
+
return;
|
|
251
273
|
}
|
|
252
|
-
}
|
|
253
|
-
if (mounted) {
|
|
254
274
|
const seen = /* @__PURE__ */ new Set();
|
|
255
275
|
const dedupedExtras = allExtras.filter((item) => {
|
|
256
276
|
if (seen.has(`${item.key}`)) {
|
|
@@ -260,15 +280,22 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
260
280
|
return true;
|
|
261
281
|
});
|
|
262
282
|
setExtraMenuItems(dedupedExtras);
|
|
283
|
+
} catch (error) {
|
|
284
|
+
console.error("Failed to load extra menu items:", error);
|
|
285
|
+
if (mounted) {
|
|
286
|
+
setExtraMenuItems([]);
|
|
287
|
+
}
|
|
288
|
+
} finally {
|
|
289
|
+
if (mounted) {
|
|
290
|
+
setExtraMenuItemsLoaded(true);
|
|
291
|
+
}
|
|
263
292
|
}
|
|
264
293
|
}, "loadExtras");
|
|
265
|
-
|
|
266
|
-
loadExtras();
|
|
267
|
-
}
|
|
294
|
+
loadExtras();
|
|
268
295
|
return () => {
|
|
269
296
|
mounted = false;
|
|
270
297
|
};
|
|
271
|
-
}, [model, menuLevels, t, refreshTick
|
|
298
|
+
}, [model, menuLevels, t, refreshTick]);
|
|
272
299
|
const copyUidToClipboard = (0, import_react.useCallback)(
|
|
273
300
|
async (uid) => {
|
|
274
301
|
var _a;
|
|
@@ -513,7 +540,7 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
513
540
|
return [];
|
|
514
541
|
}
|
|
515
542
|
},
|
|
516
|
-
[]
|
|
543
|
+
[t]
|
|
517
544
|
);
|
|
518
545
|
const getConfigurableFlowsAndSteps = (0, import_react.useCallback)(async () => {
|
|
519
546
|
const result = [];
|
|
@@ -551,20 +578,47 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
551
578
|
};
|
|
552
579
|
}, [model, menuLevels, refreshTick]);
|
|
553
580
|
(0, import_react.useEffect)(() => {
|
|
581
|
+
let mounted = true;
|
|
554
582
|
const loadConfigurableFlowsAndSteps = /* @__PURE__ */ __name(async () => {
|
|
555
583
|
setIsLoading(true);
|
|
584
|
+
if (shouldDeferConfigLoading) {
|
|
585
|
+
setConfigurableFlowsAndSteps([]);
|
|
586
|
+
}
|
|
556
587
|
try {
|
|
557
588
|
const flows = await getConfigurableFlowsAndSteps();
|
|
558
|
-
|
|
589
|
+
if (mounted) {
|
|
590
|
+
setConfigurableFlowsAndSteps(flows);
|
|
591
|
+
}
|
|
559
592
|
} catch (error) {
|
|
560
593
|
console.error("Failed to load configurable flows and steps:", error);
|
|
561
|
-
|
|
594
|
+
if (mounted) {
|
|
595
|
+
setConfigurableFlowsAndSteps([]);
|
|
596
|
+
}
|
|
562
597
|
} finally {
|
|
563
|
-
|
|
598
|
+
if (mounted) {
|
|
599
|
+
setIsLoading(false);
|
|
600
|
+
}
|
|
564
601
|
}
|
|
565
602
|
}, "loadConfigurableFlowsAndSteps");
|
|
603
|
+
if (shouldWaitForCommonActionProbe) {
|
|
604
|
+
setConfigurableFlowsAndSteps([]);
|
|
605
|
+
setIsLoading(false);
|
|
606
|
+
return () => {
|
|
607
|
+
mounted = false;
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
if (!visible && shouldDeferConfigLoading) {
|
|
611
|
+
setConfigurableFlowsAndSteps([]);
|
|
612
|
+
setIsLoading(false);
|
|
613
|
+
return () => {
|
|
614
|
+
mounted = false;
|
|
615
|
+
};
|
|
616
|
+
}
|
|
566
617
|
loadConfigurableFlowsAndSteps();
|
|
567
|
-
|
|
618
|
+
return () => {
|
|
619
|
+
mounted = false;
|
|
620
|
+
};
|
|
621
|
+
}, [getConfigurableFlowsAndSteps, refreshTick, shouldDeferConfigLoading, shouldWaitForCommonActionProbe, visible]);
|
|
568
622
|
const menuItems = (0, import_react.useMemo)(() => {
|
|
569
623
|
const items = [];
|
|
570
624
|
const keyCounter = /* @__PURE__ */ new Map();
|
|
@@ -689,16 +743,15 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
689
743
|
}
|
|
690
744
|
}
|
|
691
745
|
return items;
|
|
692
|
-
}, [configurableFlowsAndSteps, disabledIconColor, flattenSubMenus, t]);
|
|
746
|
+
}, [configurableFlowsAndSteps, disabledIconColor, flattenSubMenus, message, model, t]);
|
|
693
747
|
const finalMenuItems = (0, import_react.useMemo)(() => {
|
|
694
748
|
const items = [...menuItems];
|
|
695
|
-
const commonExtras = extraMenuItems.filter((it) => it.group === "common-actions").sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0));
|
|
696
749
|
if (showCopyUidButton || showDeleteButton || commonExtras.length > 0) {
|
|
697
750
|
items.push({
|
|
698
751
|
type: "divider"
|
|
699
752
|
});
|
|
700
753
|
if (commonExtras.length > 0) {
|
|
701
|
-
items.push(...commonExtras);
|
|
754
|
+
items.push(...commonExtras.map(removeExtraMenuItemClickHandlers));
|
|
702
755
|
}
|
|
703
756
|
if (showCopyUidButton && model.uid) {
|
|
704
757
|
items.push({
|
|
@@ -714,9 +767,8 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
714
767
|
}
|
|
715
768
|
}
|
|
716
769
|
return items;
|
|
717
|
-
}, [menuItems, showCopyUidButton, showDeleteButton, model.uid, model.destroy, t
|
|
718
|
-
|
|
719
|
-
if (isLoading || configurableFlowsAndSteps.length === 0 && !showDeleteButton && !showCopyUidButton && !hasExtras) {
|
|
770
|
+
}, [menuItems, showCopyUidButton, showDeleteButton, commonExtras, model.uid, model.destroy, t]);
|
|
771
|
+
if (!canRenderIcon) {
|
|
720
772
|
return null;
|
|
721
773
|
}
|
|
722
774
|
if (!model || !model.uid) {
|
|
@@ -169,16 +169,66 @@ const useKeepDropdownOpen = /* @__PURE__ */ __name(() => {
|
|
|
169
169
|
}, "useKeepDropdownOpen");
|
|
170
170
|
const useMenuSearch = /* @__PURE__ */ __name(() => {
|
|
171
171
|
const [searchValues, setSearchValues] = (0, import_react.useState)({});
|
|
172
|
+
const [inputValues, setInputValues] = (0, import_react.useState)({});
|
|
172
173
|
const [isSearching, setIsSearching] = (0, import_react.useState)(false);
|
|
174
|
+
const [composingCount, setComposingCount] = (0, import_react.useState)(0);
|
|
175
|
+
const composingKeysRef = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
173
176
|
const searchTimeoutRef = (0, import_react.useRef)(null);
|
|
174
|
-
const updateSearchValue =
|
|
177
|
+
const updateSearchValue = (0, import_react.useCallback)((key, value) => {
|
|
175
178
|
setIsSearching(true);
|
|
179
|
+
setInputValues((prev) => ({ ...prev, [key]: value }));
|
|
176
180
|
setSearchValues((prev) => ({ ...prev, [key]: value }));
|
|
177
181
|
if (searchTimeoutRef.current) {
|
|
178
182
|
clearTimeout(searchTimeoutRef.current);
|
|
179
183
|
}
|
|
180
184
|
searchTimeoutRef.current = setTimeout(() => setIsSearching(false), 300);
|
|
181
|
-
},
|
|
185
|
+
}, []);
|
|
186
|
+
const startComposition = (0, import_react.useCallback)((key) => {
|
|
187
|
+
composingKeysRef.current.add(key);
|
|
188
|
+
setIsSearching(true);
|
|
189
|
+
setComposingCount(composingKeysRef.current.size);
|
|
190
|
+
if (searchTimeoutRef.current) {
|
|
191
|
+
clearTimeout(searchTimeoutRef.current);
|
|
192
|
+
searchTimeoutRef.current = null;
|
|
193
|
+
}
|
|
194
|
+
}, []);
|
|
195
|
+
const endComposition = (0, import_react.useCallback)(
|
|
196
|
+
(key, value) => {
|
|
197
|
+
composingKeysRef.current.delete(key);
|
|
198
|
+
setComposingCount(composingKeysRef.current.size);
|
|
199
|
+
updateSearchValue(key, value);
|
|
200
|
+
},
|
|
201
|
+
[updateSearchValue]
|
|
202
|
+
);
|
|
203
|
+
const updateInputValue = (0, import_react.useCallback)((key, value) => {
|
|
204
|
+
setInputValues((prev) => ({ ...prev, [key]: value }));
|
|
205
|
+
}, []);
|
|
206
|
+
const clearSearchValue = (0, import_react.useCallback)((key) => {
|
|
207
|
+
composingKeysRef.current.delete(key);
|
|
208
|
+
setComposingCount(composingKeysRef.current.size);
|
|
209
|
+
setInputValues((prev) => {
|
|
210
|
+
if (!(key in prev)) return prev;
|
|
211
|
+
const next = { ...prev };
|
|
212
|
+
delete next[key];
|
|
213
|
+
return next;
|
|
214
|
+
});
|
|
215
|
+
setSearchValues((prev) => {
|
|
216
|
+
if (!(key in prev)) return prev;
|
|
217
|
+
const next = { ...prev };
|
|
218
|
+
delete next[key];
|
|
219
|
+
return next;
|
|
220
|
+
});
|
|
221
|
+
}, []);
|
|
222
|
+
const clearAllSearchValues = (0, import_react.useCallback)(() => {
|
|
223
|
+
composingKeysRef.current.clear();
|
|
224
|
+
setComposingCount(0);
|
|
225
|
+
setInputValues({});
|
|
226
|
+
setSearchValues({});
|
|
227
|
+
setIsSearching(false);
|
|
228
|
+
}, []);
|
|
229
|
+
const isComposing = (0, import_react.useCallback)((key) => {
|
|
230
|
+
return key ? composingKeysRef.current.has(key) : composingKeysRef.current.size > 0;
|
|
231
|
+
}, []);
|
|
182
232
|
(0, import_react.useEffect)(() => {
|
|
183
233
|
return () => {
|
|
184
234
|
if (searchTimeoutRef.current) {
|
|
@@ -188,8 +238,15 @@ const useMenuSearch = /* @__PURE__ */ __name(() => {
|
|
|
188
238
|
}, []);
|
|
189
239
|
return {
|
|
190
240
|
searchValues,
|
|
191
|
-
|
|
192
|
-
|
|
241
|
+
inputValues,
|
|
242
|
+
isSearching: isSearching || composingCount > 0,
|
|
243
|
+
updateSearchValue,
|
|
244
|
+
updateInputValue,
|
|
245
|
+
startComposition,
|
|
246
|
+
endComposition,
|
|
247
|
+
clearSearchValue,
|
|
248
|
+
clearAllSearchValues,
|
|
249
|
+
isComposing
|
|
193
250
|
};
|
|
194
251
|
}, "useMenuSearch");
|
|
195
252
|
const useSubmenuStyles = /* @__PURE__ */ __name((menuVisible, dropdownMaxHeight) => {
|
|
@@ -275,10 +332,10 @@ const getLabelSearchText = /* @__PURE__ */ __name((label) => {
|
|
|
275
332
|
}
|
|
276
333
|
return "";
|
|
277
334
|
}, "getLabelSearchText");
|
|
278
|
-
const createSearchItem = /* @__PURE__ */ __name((item, searchKey, currentSearchValue, menuVisible, t,
|
|
335
|
+
const createSearchItem = /* @__PURE__ */ __name((item, searchKey, currentSearchValue, menuVisible, t, searchHandlers, activateSearchSubmenu, deactivateSearchSubmenu, shouldActivateSearchSubmenu) => ({
|
|
279
336
|
key: `${searchKey}-search`,
|
|
280
337
|
type: "group",
|
|
281
|
-
label: /* @__PURE__ */ import_react.default.createElement("div",
|
|
338
|
+
label: /* @__PURE__ */ import_react.default.createElement("div", { onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ import_react.default.createElement(
|
|
282
339
|
SearchInputWithAutoFocus,
|
|
283
340
|
{
|
|
284
341
|
visible: menuVisible,
|
|
@@ -286,11 +343,50 @@ const createSearchItem = /* @__PURE__ */ __name((item, searchKey, currentSearchV
|
|
|
286
343
|
allowClear: true,
|
|
287
344
|
placeholder: t(item.searchPlaceholder || "Search"),
|
|
288
345
|
value: currentSearchValue,
|
|
346
|
+
onFocus: (e) => {
|
|
347
|
+
e.stopPropagation();
|
|
348
|
+
},
|
|
289
349
|
onChange: (e) => {
|
|
350
|
+
var _a;
|
|
351
|
+
e.stopPropagation();
|
|
352
|
+
const value = e.target.value;
|
|
353
|
+
if (shouldActivateSearchSubmenu) {
|
|
354
|
+
activateSearchSubmenu(searchKey);
|
|
355
|
+
}
|
|
356
|
+
if (((_a = e.nativeEvent) == null ? void 0 : _a.isComposing) || searchHandlers.isComposing(searchKey)) {
|
|
357
|
+
searchHandlers.updateInputValue(searchKey, value);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
if (!value && shouldActivateSearchSubmenu) {
|
|
361
|
+
deactivateSearchSubmenu(searchKey);
|
|
362
|
+
}
|
|
363
|
+
searchHandlers.updateSearchValue(searchKey, value);
|
|
364
|
+
},
|
|
365
|
+
onCompositionStart: (e) => {
|
|
366
|
+
e.stopPropagation();
|
|
367
|
+
if (shouldActivateSearchSubmenu) {
|
|
368
|
+
activateSearchSubmenu(searchKey);
|
|
369
|
+
}
|
|
370
|
+
searchHandlers.startComposition(searchKey);
|
|
371
|
+
},
|
|
372
|
+
onCompositionEnd: (e) => {
|
|
373
|
+
e.stopPropagation();
|
|
374
|
+
const value = e.currentTarget.value;
|
|
375
|
+
if (shouldActivateSearchSubmenu) {
|
|
376
|
+
if (value) {
|
|
377
|
+
activateSearchSubmenu(searchKey);
|
|
378
|
+
} else {
|
|
379
|
+
deactivateSearchSubmenu(searchKey);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
searchHandlers.endComposition(searchKey, value);
|
|
383
|
+
},
|
|
384
|
+
onClick: (e) => {
|
|
385
|
+
e.stopPropagation();
|
|
386
|
+
},
|
|
387
|
+
onKeyDown: (e) => {
|
|
290
388
|
e.stopPropagation();
|
|
291
|
-
updateSearchValue(searchKey, e.target.value);
|
|
292
389
|
},
|
|
293
|
-
onClick: (e) => e.stopPropagation(),
|
|
294
390
|
onMouseDown: (e) => {
|
|
295
391
|
e.stopPropagation();
|
|
296
392
|
},
|
|
@@ -313,13 +409,21 @@ const KEEP_OPEN_LABEL_STYLE = {
|
|
|
313
409
|
width: "100%"
|
|
314
410
|
};
|
|
315
411
|
const DROPDOWN_PERSIST_TTL_MS = 350;
|
|
412
|
+
const SUBMENU_CLOSE_DELAY = 0.05;
|
|
413
|
+
const SUBMENU_MOTION_DISABLED = {
|
|
414
|
+
motionEnter: false,
|
|
415
|
+
motionLeave: false
|
|
416
|
+
};
|
|
316
417
|
const dropdownPersistRegistry = /* @__PURE__ */ new Map();
|
|
317
418
|
const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
318
419
|
const engine = (0, import_provider.useFlowEngine)();
|
|
319
420
|
const [menuVisible, setMenuVisible] = (0, import_react.useState)(false);
|
|
320
421
|
const [openKeys, setOpenKeys] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
422
|
+
const [activeSearchKey, setActiveSearchKey] = (0, import_react.useState)(null);
|
|
321
423
|
const [rootItems, setRootItems] = (0, import_react.useState)([]);
|
|
322
424
|
const [rootLoading, setRootLoading] = (0, import_react.useState)(false);
|
|
425
|
+
const closeByOutsideClickRef = (0, import_react.useRef)(false);
|
|
426
|
+
const skipPreserveActiveSearchRef = (0, import_react.useRef)(false);
|
|
323
427
|
const dropdownMaxHeight = useNiceDropdownMaxHeight();
|
|
324
428
|
const t = engine.translate.bind(engine);
|
|
325
429
|
const { items: menuItems, keepDropdownOpen, persistKey, stateVersion, refreshKeys, ...dropdownMenuProps } = menu;
|
|
@@ -330,22 +434,89 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
330
434
|
openKeys,
|
|
331
435
|
refreshKeys
|
|
332
436
|
);
|
|
333
|
-
const
|
|
437
|
+
const searchHandlers = useMenuSearch();
|
|
438
|
+
const { searchValues, inputValues, clearSearchValue, clearAllSearchValues } = searchHandlers;
|
|
334
439
|
const { requestKeepOpen, shouldPreventClose } = useKeepDropdownOpen();
|
|
335
440
|
useSubmenuStyles(menuVisible, dropdownMaxHeight);
|
|
441
|
+
const closeMenu = (0, import_react.useCallback)(() => {
|
|
442
|
+
setMenuVisible(false);
|
|
443
|
+
setActiveSearchKey(null);
|
|
444
|
+
setOpenKeys(/* @__PURE__ */ new Set());
|
|
445
|
+
clearAllSearchValues();
|
|
446
|
+
}, [clearAllSearchValues]);
|
|
447
|
+
const activateSearchSubmenu = (0, import_react.useCallback)((key) => {
|
|
448
|
+
setActiveSearchKey(key);
|
|
449
|
+
setOpenKeys((prev) => {
|
|
450
|
+
if (prev.has(key)) return prev;
|
|
451
|
+
const next = new Set(prev);
|
|
452
|
+
next.add(key);
|
|
453
|
+
return next;
|
|
454
|
+
});
|
|
455
|
+
}, []);
|
|
456
|
+
const deactivateSearchSubmenu = (0, import_react.useCallback)((key) => {
|
|
457
|
+
setActiveSearchKey((prev) => prev === key ? null : prev);
|
|
458
|
+
}, []);
|
|
459
|
+
const closeActiveSearchForPath = (0, import_react.useCallback)(
|
|
460
|
+
(keyPath) => {
|
|
461
|
+
if (!activeSearchKey || keyPath === activeSearchKey || keyPath.startsWith(`${activeSearchKey}/`) || activeSearchKey.startsWith(`${keyPath}/`)) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
skipPreserveActiveSearchRef.current = true;
|
|
465
|
+
clearSearchValue(activeSearchKey);
|
|
466
|
+
setActiveSearchKey(null);
|
|
467
|
+
setOpenKeys((prev) => {
|
|
468
|
+
const next = new Set(prev);
|
|
469
|
+
next.delete(activeSearchKey);
|
|
470
|
+
return next;
|
|
471
|
+
});
|
|
472
|
+
},
|
|
473
|
+
[activeSearchKey, clearSearchValue]
|
|
474
|
+
);
|
|
336
475
|
const handleMenuOpenChange = (0, import_react.useCallback)(
|
|
337
476
|
(nextOpenKeys) => {
|
|
338
477
|
var _a, _b;
|
|
339
|
-
|
|
478
|
+
let normalized = normalizeOpenKeys(nextOpenKeys);
|
|
479
|
+
if (activeSearchKey && openKeys.has(activeSearchKey) && !normalized.includes(activeSearchKey)) {
|
|
480
|
+
if (normalized.length || skipPreserveActiveSearchRef.current) {
|
|
481
|
+
clearSearchValue(activeSearchKey);
|
|
482
|
+
setActiveSearchKey(null);
|
|
483
|
+
} else {
|
|
484
|
+
normalized = [activeSearchKey];
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (!normalized.length && shouldPreventClose()) {
|
|
340
488
|
(_a = dropdownMenuProps.onOpenChange) == null ? void 0 : _a.call(dropdownMenuProps, Array.from(openKeys));
|
|
489
|
+
skipPreserveActiveSearchRef.current = false;
|
|
341
490
|
return;
|
|
342
491
|
}
|
|
343
|
-
|
|
492
|
+
Array.from(openKeys).forEach((key) => {
|
|
493
|
+
if (!normalized.includes(key)) {
|
|
494
|
+
clearSearchValue(key);
|
|
495
|
+
}
|
|
496
|
+
});
|
|
344
497
|
setOpenKeys(new Set(normalized));
|
|
345
498
|
(_b = dropdownMenuProps.onOpenChange) == null ? void 0 : _b.call(dropdownMenuProps, normalized);
|
|
499
|
+
skipPreserveActiveSearchRef.current = false;
|
|
346
500
|
},
|
|
347
|
-
[dropdownMenuProps, openKeys, shouldPreventClose]
|
|
501
|
+
[activeSearchKey, clearSearchValue, dropdownMenuProps, openKeys, shouldPreventClose]
|
|
348
502
|
);
|
|
503
|
+
(0, import_react.useEffect)(() => {
|
|
504
|
+
if (!menuVisible) return;
|
|
505
|
+
const markOutsideClick = /* @__PURE__ */ __name((event) => {
|
|
506
|
+
const target = event.target;
|
|
507
|
+
const isOutside = !(target == null ? void 0 : target.closest(".ant-dropdown, .ant-dropdown-menu, .ant-dropdown-menu-submenu-popup"));
|
|
508
|
+
closeByOutsideClickRef.current = isOutside;
|
|
509
|
+
if (isOutside) {
|
|
510
|
+
closeMenu();
|
|
511
|
+
}
|
|
512
|
+
}, "markOutsideClick");
|
|
513
|
+
document.addEventListener("pointerdown", markOutsideClick, true);
|
|
514
|
+
document.addEventListener("mousedown", markOutsideClick, true);
|
|
515
|
+
return () => {
|
|
516
|
+
document.removeEventListener("pointerdown", markOutsideClick, true);
|
|
517
|
+
document.removeEventListener("mousedown", markOutsideClick, true);
|
|
518
|
+
};
|
|
519
|
+
}, [closeMenu, menuVisible]);
|
|
349
520
|
(0, import_react.useEffect)(() => {
|
|
350
521
|
if (!persistKey) return;
|
|
351
522
|
const until = dropdownPersistRegistry.get(persistKey) || 0;
|
|
@@ -391,6 +562,8 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
391
562
|
function buildSearchChildren(children, item, keyPath, path, menuVisible2, resolve) {
|
|
392
563
|
const searchKey = keyPath;
|
|
393
564
|
const currentSearchValue = searchValues[searchKey] || "";
|
|
565
|
+
const currentInputValue = inputValues[searchKey] ?? currentSearchValue;
|
|
566
|
+
const shouldActivateSearchSubmenu = !(item.type === "group" && path.length === 0);
|
|
394
567
|
const filteredChildren = currentSearchValue ? (/* @__PURE__ */ __name(function deepFilter(items2) {
|
|
395
568
|
const searchText = currentSearchValue.toLowerCase();
|
|
396
569
|
return items2.map((child) => {
|
|
@@ -407,7 +580,17 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
407
580
|
}).filter(Boolean);
|
|
408
581
|
}, "deepFilter"))(children) : children;
|
|
409
582
|
const resolvedFiltered = resolve(filteredChildren, [...path, item.key]);
|
|
410
|
-
const searchItem = createSearchItem(
|
|
583
|
+
const searchItem = createSearchItem(
|
|
584
|
+
item,
|
|
585
|
+
searchKey,
|
|
586
|
+
currentInputValue,
|
|
587
|
+
menuVisible2,
|
|
588
|
+
t,
|
|
589
|
+
searchHandlers,
|
|
590
|
+
activateSearchSubmenu,
|
|
591
|
+
deactivateSearchSubmenu,
|
|
592
|
+
shouldActivateSearchSubmenu
|
|
593
|
+
);
|
|
411
594
|
const dividerItem = { key: `${keyPath}-search-divider`, type: "divider" };
|
|
412
595
|
if (currentSearchValue && resolvedFiltered.length === 0) {
|
|
413
596
|
return [searchItem, dividerItem, createEmptyItem(keyPath, t)];
|
|
@@ -466,6 +649,7 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
466
649
|
label,
|
|
467
650
|
onClick: /* @__PURE__ */ __name((info) => {
|
|
468
651
|
}, "onClick"),
|
|
652
|
+
onMouseEnter: /* @__PURE__ */ __name(() => closeActiveSearchForPath(keyPath), "onMouseEnter"),
|
|
469
653
|
children: buildSearchChildren(children, item, keyPath, path, menuVisible, resolveItems)
|
|
470
654
|
};
|
|
471
655
|
}
|
|
@@ -513,6 +697,7 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
513
697
|
onClick: /* @__PURE__ */ __name((info) => {
|
|
514
698
|
if (!itemShouldKeepOpen) handleLeafClick(info);
|
|
515
699
|
}, "onClick"),
|
|
700
|
+
onMouseEnter: /* @__PURE__ */ __name(() => closeActiveSearchForPath(keyPath), "onMouseEnter"),
|
|
516
701
|
onMouseDown: /* @__PURE__ */ __name(() => {
|
|
517
702
|
if (!itemShouldKeepOpen) {
|
|
518
703
|
return;
|
|
@@ -555,6 +740,8 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
555
740
|
...dropdownMenuProps,
|
|
556
741
|
openKeys: Array.from(openKeys),
|
|
557
742
|
items,
|
|
743
|
+
subMenuCloseDelay: dropdownMenuProps.subMenuCloseDelay ?? SUBMENU_CLOSE_DELAY,
|
|
744
|
+
motion: dropdownMenuProps.motion ?? SUBMENU_MOTION_DISABLED,
|
|
558
745
|
onClick: /* @__PURE__ */ __name(() => {
|
|
559
746
|
}, "onClick"),
|
|
560
747
|
onOpenChange: handleMenuOpenChange,
|
|
@@ -564,14 +751,19 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
564
751
|
...dropdownMenuProps == null ? void 0 : dropdownMenuProps.style
|
|
565
752
|
}
|
|
566
753
|
},
|
|
567
|
-
onOpenChange: (visible) => {
|
|
568
|
-
if (!visible &&
|
|
754
|
+
onOpenChange: (visible, info) => {
|
|
755
|
+
if (!visible && activeSearchKey && (info == null ? void 0 : info.source) === "trigger" && !closeByOutsideClickRef.current) {
|
|
569
756
|
return;
|
|
570
757
|
}
|
|
571
758
|
if (!visible && shouldPreventClose()) {
|
|
572
759
|
return;
|
|
573
760
|
}
|
|
574
|
-
|
|
761
|
+
if (!visible) {
|
|
762
|
+
closeMenu();
|
|
763
|
+
} else {
|
|
764
|
+
setMenuVisible(visible);
|
|
765
|
+
}
|
|
766
|
+
closeByOutsideClickRef.current = false;
|
|
575
767
|
}
|
|
576
768
|
},
|
|
577
769
|
props.children
|
|
@@ -231,14 +231,18 @@ function buildSubModelGroups(subModelBaseClasses = []) {
|
|
|
231
231
|
}
|
|
232
232
|
__name(buildSubModelGroups, "buildSubModelGroups");
|
|
233
233
|
function buildWrapperFieldChildren(ctx, options) {
|
|
234
|
-
var _a;
|
|
235
|
-
const { useModel, fieldUseModel, associationPathName, refreshTargets } = options;
|
|
234
|
+
var _a, _b;
|
|
235
|
+
const { useModel, fieldUseModel, associationPathName, refreshTargets, maxAssociationFieldDepth = 2 } = options;
|
|
236
236
|
const collection = options.collection || ctx.model["collection"] || ctx.collection;
|
|
237
237
|
const fields = collection.getFields();
|
|
238
238
|
const defaultItemKeys = ["fieldSettings", "init"];
|
|
239
239
|
const children = [];
|
|
240
|
+
const associationDepth = associationPathName ? associationPathName.split(".").filter(Boolean).length : 0;
|
|
240
241
|
for (const f of fields) {
|
|
241
242
|
if (!((_a = f == null ? void 0 : f.options) == null ? void 0 : _a.interface)) continue;
|
|
243
|
+
if (associationDepth >= maxAssociationFieldDepth && (((_b = f.isAssociationField) == null ? void 0 : _b.call(f)) || f.target || f.targetCollection)) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
242
246
|
const fieldPath = associationPathName ? `${associationPathName}.${f.name}` : f.name;
|
|
243
247
|
const childUse = typeof fieldUseModel === "function" ? fieldUseModel(f) : fieldUseModel ?? "FieldModel";
|
|
244
248
|
if (childUse) {
|
|
@@ -38,7 +38,13 @@ export declare class DataSourceManager {
|
|
|
38
38
|
}>) => void;
|
|
39
39
|
addFieldInterfaceComponentOption?: (name: string, option: any) => void;
|
|
40
40
|
addFieldInterfaceOperator?: (name: string, operator: any) => void;
|
|
41
|
+
registerFieldFilterOperator?: (operator: any) => void;
|
|
42
|
+
registerFieldFilterOperatorGroup?: (name: string, operators?: any[]) => void;
|
|
43
|
+
addFieldFilterOperatorsToGroup?: (name: string, operators?: any[]) => void;
|
|
41
44
|
getFieldInterface?: (name: string) => any;
|
|
45
|
+
registerFieldInterfaceConfigure?: (options: unknown) => void;
|
|
46
|
+
getFieldInterfaceConfigure?: (name: string, collectionInfo?: unknown) => unknown;
|
|
47
|
+
getFieldInterfaceConfigureProperties?: (name: string, collectionInfo?: any) => Record<string, any>;
|
|
42
48
|
};
|
|
43
49
|
loaders: Map<string, DataSourceLoader>;
|
|
44
50
|
loadedKeys: Set<string>;
|
|
@@ -56,6 +62,9 @@ export declare class DataSourceManager {
|
|
|
56
62
|
}>): void;
|
|
57
63
|
addFieldInterfaceComponentOption(name: string, option: any): void;
|
|
58
64
|
addFieldInterfaceOperator(name: string, operator: any): void;
|
|
65
|
+
registerFieldFilterOperator(operator: any): void;
|
|
66
|
+
registerFieldFilterOperatorGroup(name: string, operators?: any[]): void;
|
|
67
|
+
addFieldFilterOperatorsToGroup(name: string, operators?: any[]): void;
|
|
59
68
|
registerLoader(key: string, loader: DataSourceLoader): void;
|
|
60
69
|
removeLoader(key: string): void;
|
|
61
70
|
addDataSource(ds: DataSource | DataSourceOptions): void;
|
package/lib/data-source/index.js
CHANGED
|
@@ -89,6 +89,18 @@ const _DataSourceManager = class _DataSourceManager {
|
|
|
89
89
|
var _a, _b;
|
|
90
90
|
(_b = (_a = this.collectionFieldInterfaceManager) == null ? void 0 : _a.addFieldInterfaceOperator) == null ? void 0 : _b.call(_a, name, operator);
|
|
91
91
|
}
|
|
92
|
+
registerFieldFilterOperator(operator) {
|
|
93
|
+
var _a, _b;
|
|
94
|
+
(_b = (_a = this.collectionFieldInterfaceManager) == null ? void 0 : _a.registerFieldFilterOperator) == null ? void 0 : _b.call(_a, operator);
|
|
95
|
+
}
|
|
96
|
+
registerFieldFilterOperatorGroup(name, operators = []) {
|
|
97
|
+
var _a, _b;
|
|
98
|
+
(_b = (_a = this.collectionFieldInterfaceManager) == null ? void 0 : _a.registerFieldFilterOperatorGroup) == null ? void 0 : _b.call(_a, name, operators);
|
|
99
|
+
}
|
|
100
|
+
addFieldFilterOperatorsToGroup(name, operators = []) {
|
|
101
|
+
var _a, _b;
|
|
102
|
+
(_b = (_a = this.collectionFieldInterfaceManager) == null ? void 0 : _a.addFieldFilterOperatorsToGroup) == null ? void 0 : _b.call(_a, name, operators);
|
|
103
|
+
}
|
|
92
104
|
registerLoader(key, loader) {
|
|
93
105
|
this.loaders.set(key, loader);
|
|
94
106
|
}
|
|
@@ -153,9 +153,6 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
153
153
|
const stepDefaultParams = await (0, import_utils.resolveDefaultParams)(step.defaultParams, runtimeCtx);
|
|
154
154
|
combinedParams = { ...stepDefaultParams };
|
|
155
155
|
} else {
|
|
156
|
-
flowContext.logger.warn(
|
|
157
|
-
`BaseModel.applyFlow: Step '${stepKey}' in flow '${flowKey}' has neither 'use' nor 'handler'. Skipping.`
|
|
158
|
-
);
|
|
159
156
|
continue;
|
|
160
157
|
}
|
|
161
158
|
const modelStepParams = model.getStepParams(flowKey, stepKey);
|