@nocobase/flow-engine 2.2.0-beta.6 → 2.2.0-beta.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.
Files changed (51) hide show
  1. package/lib/components/MobilePopup.style.js +16 -5
  2. package/lib/components/dnd/index.js +9 -2
  3. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +86 -32
  4. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +20 -0
  5. package/lib/flowContext.d.ts +1 -1
  6. package/lib/flowContext.js +32 -8
  7. package/lib/locale/en-US.json +1 -0
  8. package/lib/locale/index.d.ts +2 -0
  9. package/lib/locale/zh-CN.json +1 -0
  10. package/lib/resources/apiResource.js +2 -1
  11. package/lib/resources/baseRecordResource.js +6 -17
  12. package/lib/resources/multiRecordResource.js +13 -3
  13. package/lib/resources/singleRecordResource.js +7 -2
  14. package/lib/utils/dataSourceDirty.d.ts +20 -0
  15. package/lib/utils/dataSourceDirty.js +139 -0
  16. package/lib/utils/dirtyAwareApiClient.d.ts +11 -0
  17. package/lib/utils/dirtyAwareApiClient.js +378 -0
  18. package/lib/utils/index.d.ts +1 -0
  19. package/lib/utils/index.js +11 -0
  20. package/lib/utils/openViewRouteState.d.ts +28 -0
  21. package/lib/utils/openViewRouteState.js +125 -0
  22. package/lib/utils/parsePathnameToViewParams.d.ts +3 -0
  23. package/lib/utils/parsePathnameToViewParams.js +18 -1
  24. package/lib/views/ViewNavigation.js +5 -0
  25. package/package.json +4 -4
  26. package/src/__tests__/flowContext.test.ts +131 -0
  27. package/src/__tests__/flowEngine.dataSourceDirty.test.ts +51 -0
  28. package/src/__tests__/runjsRuntimeFeatures.test.ts +15 -2
  29. package/src/components/MobilePopup.style.ts +22 -6
  30. package/src/components/__tests__/MobilePopup.style.test.tsx +103 -0
  31. package/src/components/dnd/index.tsx +11 -2
  32. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +105 -35
  33. package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +381 -12
  34. package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +28 -0
  35. package/src/flowContext.ts +45 -8
  36. package/src/locale/en-US.json +1 -0
  37. package/src/locale/zh-CN.json +1 -0
  38. package/src/resources/apiResource.ts +2 -1
  39. package/src/resources/baseRecordResource.ts +6 -23
  40. package/src/resources/multiRecordResource.ts +13 -3
  41. package/src/resources/singleRecordResource.ts +6 -1
  42. package/src/utils/__tests__/dirtyAwareApiClient.test.ts +392 -0
  43. package/src/utils/__tests__/openViewRouteState.test.ts +40 -0
  44. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +36 -0
  45. package/src/utils/dataSourceDirty.ts +126 -0
  46. package/src/utils/dirtyAwareApiClient.ts +430 -0
  47. package/src/utils/index.ts +10 -0
  48. package/src/utils/openViewRouteState.ts +107 -0
  49. package/src/utils/parsePathnameToViewParams.ts +23 -1
  50. package/src/views/ViewNavigation.ts +6 -1
  51. package/src/views/__tests__/ViewNavigation.test.ts +15 -0
@@ -96,9 +96,17 @@ const genStyleHook = /* @__PURE__ */ __name((component, styleFn) => {
96
96
  return [genCommonStyle(token, prefixCls), styleInterpolation];
97
97
  }
98
98
  );
99
- const memoizedWrapSSR = (0, import_react.useMemo)(() => {
100
- return wrapSSR;
101
- }, [theme2, token, hashId, prefixCls, iconPrefixCls, rootPrefixCls, props]);
99
+ const wrapSSRDeps = [theme2, token, hashId, prefixCls, iconPrefixCls, rootPrefixCls, props];
100
+ const wrapSSRCacheRef = (0, import_react.useRef)();
101
+ const currentCache = wrapSSRCacheRef.current;
102
+ let memoizedWrapSSR = (currentCache == null ? void 0 : currentCache.wrapSSR) || wrapSSR;
103
+ if (!currentCache || wrapSSRDeps.some((dep, index) => dep !== currentCache.deps[index])) {
104
+ wrapSSRCacheRef.current = {
105
+ deps: wrapSSRDeps,
106
+ wrapSSR
107
+ };
108
+ memoizedWrapSSR = wrapSSR;
109
+ }
102
110
  return {
103
111
  wrapSSR: memoizedWrapSSR,
104
112
  hashId,
@@ -112,7 +120,7 @@ const useMobileActionDrawerStyle = genStyleHook("nb-mobile-action-drawer", (toke
112
120
  return {
113
121
  [componentCls]: {
114
122
  ".nb-mobile-action-drawer-header": {
115
- height: "var(--nb-mobile-page-header-height)",
123
+ height: "var(--nb-mobile-page-header-height, 46px)",
116
124
  display: "flex",
117
125
  alignItems: "center",
118
126
  justifyContent: "space-between",
@@ -139,7 +147,10 @@ const useMobileActionDrawerStyle = genStyleHook("nb-mobile-action-drawer", (toke
139
147
  ".nb-mobile-action-drawer-body": {
140
148
  borderTopLeftRadius: 8,
141
149
  borderTopRightRadius: 8,
142
- maxHeight: "calc(100% - var(--nb-mobile-page-header-height))",
150
+ maxHeight: "calc(100vh - var(--nb-mobile-page-header-height, 46px))",
151
+ "@supports (height: 100dvh)": {
152
+ maxHeight: "calc(100dvh - var(--nb-mobile-page-header-height, 46px))"
153
+ },
143
154
  overflowY: "auto",
144
155
  overflowX: "hidden",
145
156
  backgroundColor: token.colorBgLayout,
@@ -57,6 +57,10 @@ const EMPTY_COLUMN_UID = "EMPTY_COLUMN";
57
57
  const TOOLBAR_DRAG_ACTIVITY_EVENT = "nb-toolbar-drag-activity";
58
58
  const TOOLBAR_DRAG_ANCHOR_EVENT = "nb-toolbar-drag-anchor";
59
59
  const MENU_SUBMENU_POPUP_SELECTOR = ".ant-menu-submenu-popup";
60
+ const getToolbarModelUidFromNode = /* @__PURE__ */ __name((node) => {
61
+ var _a;
62
+ return ((_a = node == null ? void 0 : node.closest(".nb-toolbar-container[data-model-uid]")) == null ? void 0 : _a.getAttribute("data-model-uid")) || null;
63
+ }, "getToolbarModelUidFromNode");
60
64
  const resolveOverlayAnchorTransform = /* @__PURE__ */ __name(({
61
65
  activeId,
62
66
  active,
@@ -76,7 +80,7 @@ const resolveOverlayAnchorTransform = /* @__PURE__ */ __name(({
76
80
  const resolveDraggableHostNode = /* @__PURE__ */ __name((activatorNode) => {
77
81
  const ownerDocument = activatorNode == null ? void 0 : activatorNode.ownerDocument;
78
82
  const floatToolbarContainer = activatorNode == null ? void 0 : activatorNode.closest(".nb-toolbar-container[data-model-uid]");
79
- const toolbarModelUid = floatToolbarContainer == null ? void 0 : floatToolbarContainer.getAttribute("data-model-uid");
83
+ const toolbarModelUid = getToolbarModelUidFromNode(activatorNode);
80
84
  if (!ownerDocument || !toolbarModelUid) {
81
85
  return activatorNode;
82
86
  }
@@ -99,6 +103,7 @@ const DragHandler = /* @__PURE__ */ __name(({
99
103
  const dragHandlerRef = (0, import_react.useRef)(null);
100
104
  const draggableNodeRef = (0, import_react.useRef)(null);
101
105
  const pointerPressCleanupRef = (0, import_react.useRef)(null);
106
+ const toolbarDragModelUidRef = (0, import_react.useRef)(null);
102
107
  const isDraggingRef = (0, import_react.useRef)(isDragging);
103
108
  const isPointerPressActiveRef = (0, import_react.useRef)(false);
104
109
  const isToolbarDragActiveRef = (0, import_react.useRef)(false);
@@ -128,9 +133,11 @@ const DragHandler = /* @__PURE__ */ __name(({
128
133
  if (!ownerDocument) {
129
134
  return;
130
135
  }
136
+ const toolbarModelUid = getToolbarModelUidFromNode(dragHandlerRef.current) || toolbarDragModelUidRef.current || model.uid;
137
+ toolbarDragModelUidRef.current = active ? toolbarModelUid : null;
131
138
  ownerDocument.dispatchEvent(
132
139
  new CustomEvent(TOOLBAR_DRAG_ACTIVITY_EVENT, {
133
- detail: { active, modelUid: model.uid }
140
+ detail: { active, modelUid: toolbarModelUid }
134
141
  })
135
142
  );
136
143
  },
@@ -44,6 +44,7 @@ var import_react = __toESM(require("react"));
44
44
  var import_react_dom = require("react-dom");
45
45
  var import_antd = require("antd");
46
46
  var import_css = require("@emotion/css");
47
+ var import_ahooks = require("ahooks");
47
48
  var import_hooks = require("../../../../hooks");
48
49
  var import_provider = require("../../../../provider");
49
50
  var import_utils = require("../../../../utils");
@@ -312,6 +313,38 @@ const buildToolbarContainerStyle = /* @__PURE__ */ __name((portalRect, toolbarSt
312
313
  const isModelByIdProps = /* @__PURE__ */ __name((props) => {
313
314
  return "uid" in props && "modelClassName" in props && Boolean(props.uid) && Boolean(props.modelClassName);
314
315
  }, "isModelByIdProps");
316
+ const stopResizeInteractionEvent = /* @__PURE__ */ __name((event) => {
317
+ var _a;
318
+ if (!event) {
319
+ return;
320
+ }
321
+ event.preventDefault();
322
+ event.stopPropagation();
323
+ const nativeEvent = "nativeEvent" in event ? event.nativeEvent : event;
324
+ (_a = nativeEvent.stopImmediatePropagation) == null ? void 0 : _a.call(nativeEvent);
325
+ }, "stopResizeInteractionEvent");
326
+ const pendingResizeClickSuppressions = /* @__PURE__ */ new WeakMap();
327
+ const clearPendingResizeClickSuppression = /* @__PURE__ */ __name((ownerDocument) => {
328
+ const pending = pendingResizeClickSuppressions.get(ownerDocument);
329
+ if (!pending) {
330
+ return;
331
+ }
332
+ ownerDocument.removeEventListener("click", pending.listener, true);
333
+ (ownerDocument.defaultView || window).clearTimeout(pending.timer);
334
+ pendingResizeClickSuppressions.delete(ownerDocument);
335
+ }, "clearPendingResizeClickSuppression");
336
+ const suppressNextResizeClick = /* @__PURE__ */ __name((ownerDocument) => {
337
+ clearPendingResizeClickSuppression(ownerDocument);
338
+ const listener = /* @__PURE__ */ __name((event) => {
339
+ stopResizeInteractionEvent(event);
340
+ clearPendingResizeClickSuppression(ownerDocument);
341
+ }, "listener");
342
+ const timer = (ownerDocument.defaultView || window).setTimeout(() => {
343
+ clearPendingResizeClickSuppression(ownerDocument);
344
+ }, 0);
345
+ pendingResizeClickSuppressions.set(ownerDocument, { listener, timer });
346
+ ownerDocument.addEventListener("click", listener, true);
347
+ }, "suppressNextResizeClick");
315
348
  const FlowsFloatContextMenu = (0, import_reactive.observer)((props) => {
316
349
  const ctx = (0, import__.useFlowContext)();
317
350
  if (!ctx.flowSettingsEnabled) {
@@ -326,44 +359,64 @@ const ResizeHandles = /* @__PURE__ */ __name((props) => {
326
359
  const isDraggingRef = (0, import_react.useRef)(false);
327
360
  const dragTypeRef = (0, import_react.useRef)(null);
328
361
  const dragStartPosRef = (0, import_react.useRef)({ x: 0, y: 0 });
362
+ const dragOwnerDocumentRef = (0, import_react.useRef)(null);
329
363
  const { onDragStart, onDragEnd } = props;
330
- const handleDragMove = (0, import_react.useCallback)(
331
- (e) => {
332
- if (!isDraggingRef.current || !dragTypeRef.current) return;
333
- const deltaX = e.clientX - dragStartPosRef.current.x;
334
- switch (dragTypeRef.current) {
335
- case "left":
336
- props.model.parent.emitter.emit("onResizeLeft", { resizeDistance: -deltaX, model: props.model });
337
- break;
338
- case "right":
339
- props.model.parent.emitter.emit("onResizeRight", { resizeDistance: deltaX, model: props.model });
340
- break;
341
- }
342
- },
343
- [props.model]
344
- );
345
- const handleDragEnd = (0, import_react.useCallback)(() => {
364
+ const handleDragMove = (0, import_ahooks.useMemoizedFn)((e) => {
365
+ if (!isDraggingRef.current || !dragTypeRef.current) return;
366
+ stopResizeInteractionEvent(e);
367
+ const deltaX = e.clientX - dragStartPosRef.current.x;
368
+ switch (dragTypeRef.current) {
369
+ case "left":
370
+ props.model.parent.emitter.emit("onResizeLeft", { resizeDistance: -deltaX, model: props.model });
371
+ break;
372
+ case "right":
373
+ props.model.parent.emitter.emit("onResizeRight", { resizeDistance: deltaX, model: props.model });
374
+ break;
375
+ }
376
+ });
377
+ const handleDragEnd = (0, import_ahooks.useMemoizedFn)((e) => {
378
+ if (!isDraggingRef.current) {
379
+ return;
380
+ }
381
+ stopResizeInteractionEvent(e);
382
+ const ownerDocument = dragOwnerDocumentRef.current || document;
383
+ ownerDocument.removeEventListener("mousemove", handleDragMove, true);
384
+ ownerDocument.removeEventListener("mouseup", handleDragEnd, true);
385
+ suppressNextResizeClick(ownerDocument);
346
386
  isDraggingRef.current = false;
347
387
  dragTypeRef.current = null;
348
388
  dragStartPosRef.current = { x: 0, y: 0 };
349
- document.removeEventListener("mousemove", handleDragMove);
350
- document.removeEventListener("mouseup", handleDragEnd);
389
+ dragOwnerDocumentRef.current = null;
351
390
  props.model.parent.emitter.emit("onResizeEnd");
352
391
  onDragEnd == null ? void 0 : onDragEnd();
353
- }, [handleDragMove, onDragEnd, props.model]);
354
- const handleDragStart = (0, import_react.useCallback)(
355
- (e, type) => {
356
- e.preventDefault();
357
- e.stopPropagation();
358
- isDraggingRef.current = true;
359
- dragTypeRef.current = type;
360
- dragStartPosRef.current = { x: e.clientX, y: e.clientY };
361
- document.addEventListener("mousemove", handleDragMove);
362
- document.addEventListener("mouseup", handleDragEnd);
363
- onDragStart == null ? void 0 : onDragStart();
364
- },
365
- [handleDragMove, handleDragEnd, onDragStart]
366
- );
392
+ });
393
+ (0, import_react.useEffect)(() => {
394
+ return () => {
395
+ const dragOwnerDocument = dragOwnerDocumentRef.current;
396
+ dragOwnerDocument == null ? void 0 : dragOwnerDocument.removeEventListener("mousemove", handleDragMove, true);
397
+ dragOwnerDocument == null ? void 0 : dragOwnerDocument.removeEventListener("mouseup", handleDragEnd, true);
398
+ if (isDraggingRef.current) {
399
+ suppressNextResizeClick(dragOwnerDocument || document);
400
+ props.model.parent.emitter.emit("onResizeEnd");
401
+ onDragEnd == null ? void 0 : onDragEnd();
402
+ }
403
+ isDraggingRef.current = false;
404
+ dragTypeRef.current = null;
405
+ dragStartPosRef.current = { x: 0, y: 0 };
406
+ dragOwnerDocumentRef.current = null;
407
+ };
408
+ }, [handleDragMove, handleDragEnd, onDragEnd, props.model]);
409
+ const handleDragStart = (0, import_ahooks.useMemoizedFn)((e, type) => {
410
+ stopResizeInteractionEvent(e);
411
+ const ownerDocument = e.currentTarget.ownerDocument;
412
+ isDraggingRef.current = true;
413
+ dragTypeRef.current = type;
414
+ dragStartPosRef.current = { x: e.clientX, y: e.clientY };
415
+ dragOwnerDocumentRef.current = ownerDocument;
416
+ ownerDocument.addEventListener("mousemove", handleDragMove, true);
417
+ ownerDocument.addEventListener("mouseup", handleDragEnd, true);
418
+ onDragStart == null ? void 0 : onDragStart();
419
+ });
367
420
  return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
368
421
  "div",
369
422
  {
@@ -466,6 +519,7 @@ const FlowsFloatContextMenuWithModel = (0, import_reactive.observer)(
466
519
  getPopupContainer,
467
520
  handleSettingsMenuOpenChange,
468
521
  model,
522
+ modelUid,
469
523
  settingsMenuLevel,
470
524
  showCopyUidButton,
471
525
  showDeleteButton,
@@ -44,6 +44,17 @@ const getToolbarModelUidFromTarget = /* @__PURE__ */ __name((target) => {
44
44
  }
45
45
  return ((_a = target.closest(".nb-toolbar-container[data-model-uid]")) == null ? void 0 : _a.getAttribute("data-model-uid")) || null;
46
46
  }, "getToolbarModelUidFromTarget");
47
+ const escapeCssAttributeValue = /* @__PURE__ */ __name((value) => {
48
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\a ").replace(/\r/g, "\\d ").replace(/\f/g, "\\c ");
49
+ }, "escapeCssAttributeValue");
50
+ const isToolbarModelUidRendered = /* @__PURE__ */ __name((ownerDocument, modelUid) => {
51
+ if (!ownerDocument) {
52
+ return false;
53
+ }
54
+ return !!ownerDocument.querySelector(
55
+ `.nb-toolbar-container[data-model-uid="${escapeCssAttributeValue(modelUid)}"]`
56
+ );
57
+ }, "isToolbarModelUidRendered");
47
58
  const isNodeWithinDescendantFloatToolbar = /* @__PURE__ */ __name((target, container, currentModelUid) => {
48
59
  const targetModelUid = getToolbarModelUidFromTarget(target);
49
60
  if (!container || !targetModelUid || targetModelUid === currentModelUid) {
@@ -222,6 +233,15 @@ const useFloatToolbarVisibility = /* @__PURE__ */ __name(({
222
233
  const isCurrentHostTarget = !childWithMenu || childWithMenu === containerRef.current;
223
234
  if (isCurrentHostTarget) {
224
235
  clearHideToolbarTimer();
236
+ setActiveChildToolbarIds((prevIds) => {
237
+ var _a;
238
+ if (!prevIds.length) {
239
+ return prevIds;
240
+ }
241
+ const ownerDocument = ((_a = containerRef.current) == null ? void 0 : _a.ownerDocument) ?? null;
242
+ const nextIds = prevIds.filter((id) => isToolbarModelUidRendered(ownerDocument, id));
243
+ return nextIds.length === prevIds.length ? prevIds : nextIds;
244
+ });
225
245
  setHostHovered(true);
226
246
  }
227
247
  setHideMenu(!!childWithMenu && childWithMenu !== containerRef.current);
@@ -7,7 +7,7 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
  import { ISchema } from '@formily/json-schema';
10
- import { APIClient, RequestOptions } from '@nocobase/sdk';
10
+ import type { APIClient, RequestOptions } from '@nocobase/sdk';
11
11
  import type { Router } from '@remix-run/router';
12
12
  import { MessageInstance } from 'antd/es/message/interface';
13
13
  import type { HookAPI } from 'antd/es/modal/useModal';
@@ -75,6 +75,7 @@ var import_utils = require("./utils");
75
75
  var import_exceptions = require("./utils/exceptions");
76
76
  var import_params_resolvers = require("./utils/params-resolvers");
77
77
  var import_serverContextParams = require("./utils/serverContextParams");
78
+ var import_dirtyAwareApiClient = require("./utils/dirtyAwareApiClient");
78
79
  var import_variablesParams = require("./utils/variablesParams");
79
80
  var import_registry = require("./runjs-context/registry");
80
81
  var import_createEphemeralContext = require("./utils/createEphemeralContext");
@@ -1899,15 +1900,16 @@ const _FlowContext = class _FlowContext {
1899
1900
  const options = this._props[key];
1900
1901
  if (!options) return void 0;
1901
1902
  if ("value" in options) {
1902
- return options.value;
1903
+ return key === "api" ? (0, import_dirtyAwareApiClient.getDirtyAwareApiClient)(options.value, currentContext) : options.value;
1903
1904
  }
1904
1905
  if (options.get) {
1905
1906
  if (options.cache === false) {
1906
- return options.get(currentContext);
1907
+ const value = options.get(currentContext);
1908
+ return key === "api" ? (0, import_dirtyAwareApiClient.getDirtyAwareApiClient)(value, currentContext) : value;
1907
1909
  }
1908
1910
  const cacheKey = options.observable ? "_observableCache" : "_cache";
1909
1911
  if (key in this[cacheKey]) {
1910
- return this[cacheKey][key];
1912
+ return key === "api" ? (0, import_dirtyAwareApiClient.getDirtyAwareApiClient)(this[cacheKey][key], currentContext) : this[cacheKey][key];
1911
1913
  }
1912
1914
  if (this._pending[key]) return this._pending[key];
1913
1915
  const result = options.get(this.createProxy());
@@ -1917,7 +1919,7 @@ const _FlowContext = class _FlowContext {
1917
1919
  (v) => {
1918
1920
  this[cacheKey][key] = v;
1919
1921
  delete this._pending[key];
1920
- return v;
1922
+ return key === "api" ? (0, import_dirtyAwareApiClient.getDirtyAwareApiClient)(v, currentContext) : v;
1921
1923
  },
1922
1924
  (err) => {
1923
1925
  delete this._pending[key];
@@ -1927,7 +1929,7 @@ const _FlowContext = class _FlowContext {
1927
1929
  return this._pending[key];
1928
1930
  }
1929
1931
  this[cacheKey][key] = result;
1930
- return result;
1932
+ return key === "api" ? (0, import_dirtyAwareApiClient.getDirtyAwareApiClient)(result, currentContext) : result;
1931
1933
  }
1932
1934
  return void 0;
1933
1935
  }
@@ -2251,7 +2253,7 @@ const _BaseFlowEngineContext = class _BaseFlowEngineContext extends FlowContext
2251
2253
  this.defineMethod("getModel", (modelName, searchInPreviousEngines) => {
2252
2254
  return this.engine.getModel(modelName, searchInPreviousEngines);
2253
2255
  });
2254
- this.defineMethod("request", (options) => {
2256
+ this.defineMethod("request", function(options) {
2255
2257
  const app = this.app;
2256
2258
  if (typeof (options == null ? void 0 : options.url) === "string" && shouldBypassApiClient(options.url, app)) {
2257
2259
  return import_axios.default.request(options);
@@ -2555,8 +2557,16 @@ const _FlowEngineContext = class _FlowEngineContext extends BaseFlowEngineContex
2555
2557
  });
2556
2558
  this.defineProperty("role", {
2557
2559
  get: /* @__PURE__ */ __name(() => {
2558
- var _a, _b;
2559
- return (_b = (_a = this.api) == null ? void 0 : _a.auth) == null ? void 0 : _b.role;
2560
+ var _a, _b, _c;
2561
+ const currentRole = (_b = (_a = this.api) == null ? void 0 : _a.auth) == null ? void 0 : _b.role;
2562
+ if (currentRole !== "__union__") {
2563
+ return currentRole;
2564
+ }
2565
+ const roles = (_c = this.user) == null ? void 0 : _c.roles;
2566
+ if (!Array.isArray(roles)) {
2567
+ return [];
2568
+ }
2569
+ return roles.map((role) => role == null ? void 0 : role.name).filter((name) => !!name);
2560
2570
  }, "get"),
2561
2571
  cache: false,
2562
2572
  // 注意:使用惰性 meta 工厂,避免在 i18n 尚未注入时提前求值导致无法翻译
@@ -3502,6 +3512,20 @@ const _FlowRunJSContext = class _FlowRunJSContext extends FlowContext {
3502
3512
  ReactDOMShim.__nbRunjsInternalShim = true;
3503
3513
  this.defineProperty("ReactDOM", { value: ReactDOMShim });
3504
3514
  (0, import_runjsLibs.setupRunJSLibs)(this);
3515
+ this.defineMethod("openView", async function(uid, options) {
3516
+ const delegateOpenView = delegate.openView;
3517
+ if (typeof delegateOpenView !== "function") {
3518
+ throw new Error("ctx.openView is not available in current context.");
3519
+ }
3520
+ const routeState = (0, import_utils.createOpenViewRouteState)(options);
3521
+ if (!routeState) {
3522
+ return delegateOpenView(uid, options);
3523
+ }
3524
+ return delegateOpenView(uid, {
3525
+ ...options || {},
3526
+ [import_utils.RUNJS_OPEN_VIEW_ROUTE_STATE]: routeState
3527
+ });
3528
+ });
3505
3529
  this.defineMethod(
3506
3530
  "render",
3507
3531
  function(vnode, container) {
@@ -56,6 +56,7 @@
56
56
  "Replace current block with template?": "Replace current block with template?",
57
57
  "Replaced with template block": "Replaced with template block",
58
58
  "Render failed": "Render failed",
59
+ "Response record": "Response record",
59
60
  "Step configuration": "Step configuration",
60
61
  "Step parameter configuration": "Step parameter configuration",
61
62
  "Step with key {{stepKey}} not found": "Step with key {{stepKey}} not found",
@@ -65,6 +65,7 @@ export declare const locales: {
65
65
  "Replace current block with template?": string;
66
66
  "Replaced with template block": string;
67
67
  "Render failed": string;
68
+ "Response record": string;
68
69
  "Step configuration": string;
69
70
  "Step parameter configuration": string;
70
71
  "Step with key {{stepKey}} not found": string;
@@ -150,6 +151,7 @@ export declare const locales: {
150
151
  "Other blocks": string;
151
152
  "Previous step": string;
152
153
  "Render failed": string;
154
+ "Response record": string;
153
155
  "Step configuration": string;
154
156
  "Step parameter configuration": string;
155
157
  "Step with key {{stepKey}} not found": string;
@@ -60,6 +60,7 @@
60
60
  "Other blocks": "其他区块",
61
61
  "Previous step": "上一步",
62
62
  "Render failed": "渲染失败",
63
+ "Response record": "响应结果记录",
63
64
  "Step configuration": "步骤配置",
64
65
  "Step parameter configuration": "步骤参数配置",
65
66
  "Step with key {{stepKey}} not found": "未找到key为 {{stepKey}} 的步骤",
@@ -30,6 +30,7 @@ __export(apiResource_exports, {
30
30
  APIResource: () => APIResource
31
31
  });
32
32
  module.exports = __toCommonJS(apiResource_exports);
33
+ var import_dirtyAwareApiClient = require("../utils/dirtyAwareApiClient");
33
34
  var import_flowResource = require("./flowResource");
34
35
  const _APIResource = class _APIResource extends import_flowResource.FlowResource {
35
36
  // 请求配置
@@ -49,7 +50,7 @@ const _APIResource = class _APIResource extends import_flowResource.FlowResource
49
50
  }
50
51
  }
51
52
  setAPIClient(api) {
52
- this.api = api;
53
+ this.api = (0, import_dirtyAwareApiClient.getDirtyAwareApiClient)(api, this.context);
53
54
  return this;
54
55
  }
55
56
  getURL() {
@@ -44,7 +44,7 @@ var import_lodash = __toESM(require("lodash"));
44
44
  var import_apiResource = require("./apiResource");
45
45
  var import_filterItem = require("./filterItem");
46
46
  var import_flowResource = require("./flowResource");
47
- var import_viewEvents = require("../views/viewEvents");
47
+ var import_dataSourceDirty = require("../utils/dataSourceDirty");
48
48
  const _BaseRecordResource = class _BaseRecordResource extends import_apiResource.APIResource {
49
49
  resourceName;
50
50
  sourceId = null;
@@ -151,22 +151,11 @@ const _BaseRecordResource = class _BaseRecordResource extends import_apiResource
151
151
  * Used to coordinate "refresh on active" across view stacks.
152
152
  */
153
153
  markDataSourceDirty(resourceName) {
154
- var _a, _b;
155
- const engine = this.context.engine;
156
- if (!engine) return;
157
- const dataSourceKey = this.getDataSourceKey() || "main";
158
- const resName = resourceName || this.getResourceName();
159
- if (!resName) return;
160
- const affectedResourceNames = /* @__PURE__ */ new Set([String(resName)]);
161
- if (typeof resName === "string" && resName.includes(".")) {
162
- affectedResourceNames.add(resName.split(".")[0]);
163
- }
164
- for (const name of affectedResourceNames) {
165
- engine.markDataSourceDirty(dataSourceKey, name);
166
- }
167
- (_b = (_a = engine.emitter) == null ? void 0 : _a.emit) == null ? void 0 : _b.call(_a, import_viewEvents.DATA_SOURCE_DIRTY_EVENT, {
168
- dataSourceKey,
169
- resourceNames: Array.from(affectedResourceNames)
154
+ (0, import_dataSourceDirty.markDataSourceDirty)({
155
+ engine: this.context.engine,
156
+ dataSourceKey: this.getDataSourceKey(),
157
+ resourceName: resourceName || this.getResourceName(),
158
+ includePreviousEngines: true
170
159
  });
171
160
  }
172
161
  setSourceId(sourceId) {
@@ -42,6 +42,7 @@ __export(multiRecordResource_exports, {
42
42
  module.exports = __toCommonJS(multiRecordResource_exports);
43
43
  var import_reactive = require("@formily/reactive");
44
44
  var import_lodash = __toESM(require("lodash"));
45
+ var import_dirtyAwareApiClient = require("../utils/dirtyAwareApiClient");
45
46
  var import_baseRecordResource = require("./baseRecordResource");
46
47
  const _MultiRecordResource = class _MultiRecordResource extends import_baseRecordResource.BaseRecordResource {
47
48
  _data = import_reactive.observable.ref([]);
@@ -130,7 +131,10 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
130
131
  }
131
132
  async create(data, options) {
132
133
  const config = this.mergeRequestConfig({ data }, this.createActionOptions, options);
133
- const res = await this.runAction("create", config);
134
+ const res = await this.runAction("create", {
135
+ ...config,
136
+ [import_dirtyAwareApiClient.SKIP_DATA_SOURCE_DIRTY]: true
137
+ });
134
138
  this.markDataSourceDirty();
135
139
  this.emit("saved", data);
136
140
  if ((options == null ? void 0 : options.refresh) !== false) {
@@ -161,7 +165,10 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
161
165
  this.updateActionOptions,
162
166
  options
163
167
  );
164
- await this.runAction("update", config);
168
+ await this.runAction("update", {
169
+ ...config,
170
+ [import_dirtyAwareApiClient.SKIP_DATA_SOURCE_DIRTY]: true
171
+ });
165
172
  this.markDataSourceDirty();
166
173
  this.emit("saved", data);
167
174
  await this.refresh();
@@ -182,7 +189,10 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
182
189
  },
183
190
  options
184
191
  );
185
- await this.runAction("destroy", config);
192
+ await this.runAction("destroy", {
193
+ ...config,
194
+ [import_dirtyAwareApiClient.SKIP_DATA_SOURCE_DIRTY]: true
195
+ });
186
196
  this.markDataSourceDirty();
187
197
  const currentPage = this.getPage();
188
198
  const lastPage = Math.ceil((this.getCount() - import_lodash.default.castArray(filterByTk).length) / this.getPageSize());
@@ -41,6 +41,7 @@ __export(singleRecordResource_exports, {
41
41
  });
42
42
  module.exports = __toCommonJS(singleRecordResource_exports);
43
43
  var import_lodash = __toESM(require("lodash"));
44
+ var import_dirtyAwareApiClient = require("../utils/dirtyAwareApiClient");
44
45
  var import_baseRecordResource = require("./baseRecordResource");
45
46
  const _SingleRecordResource = class _SingleRecordResource extends import_baseRecordResource.BaseRecordResource {
46
47
  isNewRecord = false;
@@ -68,7 +69,8 @@ const _SingleRecordResource = class _SingleRecordResource extends import_baseRec
68
69
  }
69
70
  const res = await this.runAction(actionName, {
70
71
  ...config,
71
- data: result
72
+ data: result,
73
+ [import_dirtyAwareApiClient.SKIP_DATA_SOURCE_DIRTY]: true
72
74
  });
73
75
  this.markDataSourceDirty();
74
76
  this.emit("saved", data);
@@ -86,7 +88,10 @@ const _SingleRecordResource = class _SingleRecordResource extends import_baseRec
86
88
  },
87
89
  options
88
90
  );
89
- await this.runAction("destroy", config);
91
+ await this.runAction("destroy", {
92
+ ...config,
93
+ [import_dirtyAwareApiClient.SKIP_DATA_SOURCE_DIRTY]: true
94
+ });
90
95
  this.markDataSourceDirty();
91
96
  this.setData(null);
92
97
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import type { FlowEngine } from '../flowEngine';
10
+ type MarkDataSourceDirtyOptions = {
11
+ engine?: FlowEngine;
12
+ dataSourceKey?: unknown;
13
+ resourceName?: unknown;
14
+ includePreviousEngines?: boolean;
15
+ };
16
+ export declare function getHeaderValue(headers: unknown, name: string): unknown;
17
+ export declare function getDataSourceKeyFromHeaders(headers: unknown): string;
18
+ export declare function getAffectedResourceNames(resourceName: unknown): string[];
19
+ export declare function markDataSourceDirty(options: MarkDataSourceDirtyOptions): string[];
20
+ export {};