@nocobase/flow-engine 2.1.0-alpha.2 → 2.1.0-alpha.20

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 (123) hide show
  1. package/LICENSE +201 -661
  2. package/README.md +79 -10
  3. package/lib/JSRunner.d.ts +10 -1
  4. package/lib/JSRunner.js +50 -5
  5. package/lib/ViewScopedFlowEngine.js +5 -1
  6. package/lib/components/FlowModelRenderer.d.ts +1 -1
  7. package/lib/components/MobilePopup.js +6 -5
  8. package/lib/components/dnd/gridDragPlanner.js +6 -2
  9. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.d.ts +3 -0
  10. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +48 -9
  11. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +19 -43
  12. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +332 -296
  13. package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +16 -2
  14. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.d.ts +36 -0
  15. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.js +272 -0
  16. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.d.ts +30 -0
  17. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +247 -0
  18. package/lib/components/subModel/AddSubModelButton.js +27 -1
  19. package/lib/components/subModel/utils.js +2 -2
  20. package/lib/data-source/index.js +6 -0
  21. package/lib/executor/FlowExecutor.js +31 -8
  22. package/lib/flowContext.js +31 -1
  23. package/lib/flowEngine.d.ts +151 -1
  24. package/lib/flowEngine.js +389 -15
  25. package/lib/flowSettings.d.ts +14 -6
  26. package/lib/flowSettings.js +34 -6
  27. package/lib/lazy-helper.d.ts +14 -0
  28. package/lib/lazy-helper.js +71 -0
  29. package/lib/locale/en-US.json +1 -0
  30. package/lib/locale/index.d.ts +2 -0
  31. package/lib/locale/zh-CN.json +1 -0
  32. package/lib/models/flowModel.js +17 -7
  33. package/lib/reactive/observer.js +46 -16
  34. package/lib/runjs-context/registry.d.ts +1 -1
  35. package/lib/runjs-context/setup.js +20 -12
  36. package/lib/runjs-context/snippets/index.js +13 -2
  37. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.d.ts +11 -0
  38. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.js +50 -0
  39. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.d.ts +11 -0
  40. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.js +54 -0
  41. package/lib/scheduler/ModelOperationScheduler.d.ts +5 -1
  42. package/lib/scheduler/ModelOperationScheduler.js +3 -2
  43. package/lib/types.d.ts +47 -1
  44. package/lib/utils/index.d.ts +2 -2
  45. package/lib/utils/index.js +4 -0
  46. package/lib/utils/parsePathnameToViewParams.js +1 -1
  47. package/lib/utils/runjsTemplateCompat.js +1 -1
  48. package/lib/utils/runjsValue.js +41 -11
  49. package/lib/utils/schema-utils.d.ts +7 -1
  50. package/lib/utils/schema-utils.js +19 -0
  51. package/lib/views/FlowView.d.ts +7 -1
  52. package/lib/views/runViewBeforeClose.d.ts +10 -0
  53. package/lib/views/runViewBeforeClose.js +45 -0
  54. package/lib/views/useDialog.d.ts +2 -1
  55. package/lib/views/useDialog.js +20 -3
  56. package/lib/views/useDrawer.d.ts +2 -1
  57. package/lib/views/useDrawer.js +20 -3
  58. package/lib/views/usePage.d.ts +2 -1
  59. package/lib/views/usePage.js +10 -3
  60. package/package.json +6 -5
  61. package/src/JSRunner.ts +68 -4
  62. package/src/ViewScopedFlowEngine.ts +4 -0
  63. package/src/__tests__/JSRunner.test.ts +27 -1
  64. package/src/__tests__/flow-engine.test.ts +166 -0
  65. package/src/__tests__/flowContext.test.ts +65 -1
  66. package/src/__tests__/flowEngine.modelLoaders.test.ts +245 -0
  67. package/src/__tests__/flowSettings.test.ts +94 -15
  68. package/src/__tests__/renderHiddenInConfig.test.tsx +6 -6
  69. package/src/__tests__/runjsContext.test.ts +16 -0
  70. package/src/__tests__/runjsContextRuntime.test.ts +2 -0
  71. package/src/__tests__/runjsPreprocessDefault.test.ts +23 -0
  72. package/src/__tests__/runjsSnippets.test.ts +21 -0
  73. package/src/__tests__/viewScopedFlowEngine.test.ts +3 -3
  74. package/src/components/FlowModelRenderer.tsx +3 -1
  75. package/src/components/MobilePopup.tsx +4 -2
  76. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +20 -10
  77. package/src/components/__tests__/gridDragPlanner.test.ts +88 -0
  78. package/src/components/dnd/gridDragPlanner.ts +8 -2
  79. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +63 -9
  80. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +457 -440
  81. package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +18 -2
  82. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +95 -0
  83. package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +547 -0
  84. package/src/components/settings/wrappers/contextual/useFloatToolbarPortal.ts +358 -0
  85. package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +281 -0
  86. package/src/components/subModel/AddSubModelButton.tsx +32 -2
  87. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +142 -32
  88. package/src/components/subModel/utils.ts +1 -1
  89. package/src/data-source/index.ts +6 -0
  90. package/src/executor/FlowExecutor.ts +34 -9
  91. package/src/executor/__tests__/flowExecutor.test.ts +57 -0
  92. package/src/flowContext.ts +35 -3
  93. package/src/flowEngine.ts +445 -11
  94. package/src/flowSettings.ts +40 -6
  95. package/src/lazy-helper.tsx +57 -0
  96. package/src/locale/en-US.json +1 -0
  97. package/src/locale/zh-CN.json +1 -0
  98. package/src/models/__tests__/dispatchEvent.when.test.ts +214 -0
  99. package/src/models/flowModel.tsx +18 -6
  100. package/src/reactive/__tests__/observer.test.tsx +82 -0
  101. package/src/reactive/observer.tsx +87 -25
  102. package/src/runjs-context/registry.ts +1 -1
  103. package/src/runjs-context/setup.ts +22 -12
  104. package/src/runjs-context/snippets/index.ts +12 -1
  105. package/src/runjs-context/snippets/scene/detail/set-field-style.snippet.ts +30 -0
  106. package/src/runjs-context/snippets/scene/table/set-cell-style.snippet.ts +34 -0
  107. package/src/scheduler/ModelOperationScheduler.ts +14 -3
  108. package/src/types.ts +60 -0
  109. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +7 -0
  110. package/src/utils/__tests__/runjsValue.test.ts +11 -0
  111. package/src/utils/__tests__/utils.test.ts +62 -0
  112. package/src/utils/index.ts +2 -1
  113. package/src/utils/parsePathnameToViewParams.ts +2 -2
  114. package/src/utils/runjsTemplateCompat.ts +1 -1
  115. package/src/utils/runjsValue.ts +50 -11
  116. package/src/utils/schema-utils.ts +30 -1
  117. package/src/views/FlowView.tsx +11 -1
  118. package/src/views/__tests__/runViewBeforeClose.test.ts +30 -0
  119. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +13 -12
  120. package/src/views/runViewBeforeClose.ts +19 -0
  121. package/src/views/useDialog.tsx +25 -3
  122. package/src/views/useDrawer.tsx +25 -3
  123. package/src/views/usePage.tsx +12 -3
@@ -0,0 +1,71 @@
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
+
10
+ var __create = Object.create;
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
17
+ var __export = (target, all) => {
18
+ for (var name in all)
19
+ __defProp(target, name, { get: all[name], enumerable: true });
20
+ };
21
+ var __copyProps = (to, from, except, desc) => {
22
+ if (from && typeof from === "object" || typeof from === "function") {
23
+ for (let key of __getOwnPropNames(from))
24
+ if (!__hasOwnProp.call(to, key) && key !== except)
25
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
26
+ }
27
+ return to;
28
+ };
29
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
30
+ // If the importer is in node compatibility mode or this is not an ESM
31
+ // file that has been converted to a CommonJS file using a Babel-
32
+ // compatible transform (i.e. "__esModule" has not been set), then set
33
+ // "default" to the CommonJS "module.exports" for node compatibility.
34
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
35
+ mod
36
+ ));
37
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
+ var lazy_helper_exports = {};
39
+ __export(lazy_helper_exports, {
40
+ lazy: () => lazy
41
+ });
42
+ module.exports = __toCommonJS(lazy_helper_exports);
43
+ var import_react = __toESM(require("react"));
44
+ function lazy(factory, ...componentNames) {
45
+ if (componentNames.length === 0) {
46
+ const LazyComponent = (0, import_react.lazy)(
47
+ () => factory().then((module2) => ({
48
+ default: module2.default
49
+ }))
50
+ );
51
+ const Component = /* @__PURE__ */ __name((props) => /* @__PURE__ */ import_react.default.createElement(import_react.default.Suspense, { fallback: null }, /* @__PURE__ */ import_react.default.createElement(LazyComponent, { ...props })), "Component");
52
+ return Component;
53
+ }
54
+ return componentNames.reduce(
55
+ (acc, name) => {
56
+ const LazyComponent = (0, import_react.lazy)(
57
+ () => factory().then((module2) => ({
58
+ default: module2[name]
59
+ }))
60
+ );
61
+ acc[name] = (props) => /* @__PURE__ */ import_react.default.createElement(import_react.default.Suspense, { fallback: null }, /* @__PURE__ */ import_react.default.createElement(LazyComponent, { ...props }));
62
+ return acc;
63
+ },
64
+ {}
65
+ );
66
+ }
67
+ __name(lazy, "lazy");
68
+ // Annotate the CommonJS export names for ESM import in node:
69
+ 0 && (module.exports = {
70
+ lazy
71
+ });
@@ -34,6 +34,7 @@
34
34
  "Failed to destroy model after creation error": "Failed to destroy model after creation error",
35
35
  "Failed to get action {{action}}": "Failed to get action {{action}}",
36
36
  "Failed to get configurable flows for model {{model}}": "Failed to get configurable flows for model {{model}}",
37
+ "Attributes are unavailable before selecting a record": "Attributes are unavailable before selecting a record",
37
38
  "Failed to import FormDialog": "Failed to import FormDialog",
38
39
  "Failed to import FormDialog or FormStep": "Failed to import FormDialog or FormStep",
39
40
  "Failed to import Formily components": "Failed to import Formily components",
@@ -43,6 +43,7 @@ export declare const locales: {
43
43
  "Failed to destroy model after creation error": string;
44
44
  "Failed to get action {{action}}": string;
45
45
  "Failed to get configurable flows for model {{model}}": string;
46
+ "Attributes are unavailable before selecting a record": string;
46
47
  "Failed to import FormDialog": string;
47
48
  "Failed to import FormDialog or FormStep": string;
48
49
  "Failed to import Formily components": string;
@@ -120,6 +121,7 @@ export declare const locales: {
120
121
  "Failed to destroy model after creation error": string;
121
122
  "Failed to get action {{action}}": string;
122
123
  "Failed to get configurable flows for model {{model}}": string;
124
+ "Attributes are unavailable before selecting a record": string;
123
125
  "Failed to import FormDialog": string;
124
126
  "Failed to import FormDialog or FormStep": string;
125
127
  "Failed to import Formily components": string;
@@ -31,6 +31,7 @@
31
31
  "Failed to destroy model after creation error": "创建错误后销毁模型失败",
32
32
  "Failed to get action {{action}}": "获取 action '{{action}}' 失败",
33
33
  "Failed to get configurable flows for model {{model}}": "获取模型 '{{model}}' 的可配置 flows 失败",
34
+ "Attributes are unavailable before selecting a record": "选择记录之前,当前项属性不可用",
34
35
  "Failed to import FormDialog": "导入 FormDialog 失败",
35
36
  "Failed to import FormDialog or FormStep": "导入 FormDialog 或 FormStep 失败",
36
37
  "Failed to import Formily components": "导入 Formily 组件失败",
@@ -56,13 +56,11 @@ var import_reactive = require("@formily/reactive");
56
56
  var import_lodash = __toESM(require("lodash"));
57
57
  var import_react = __toESM(require("react"));
58
58
  var import_secure = require("uid/secure");
59
- var import_StepRequiredSettingsDialog = require("../components/settings/wrappers/contextual/StepRequiredSettingsDialog");
60
- var import_StepSettingsDialog = require("../components/settings/wrappers/contextual/StepSettingsDialog");
61
59
  var import_emitter = require("../emitter");
62
60
  var import_InstanceFlowRegistry = require("../flow-registry/InstanceFlowRegistry");
63
61
  var import_flowContext = require("../flowContext");
64
62
  var import_utils = require("../utils");
65
- var import_lib = require("antd/lib");
63
+ var import_antd = require("antd");
66
64
  var import_ModelActionRegistry = require("../action-registry/ModelActionRegistry");
67
65
  var import_utils2 = require("../components/subModel/utils");
68
66
  var import_ModelEventRegistry = require("../event-registry/ModelEventRegistry");
@@ -75,6 +73,16 @@ const classEventRegistries = /* @__PURE__ */ new WeakMap();
75
73
  const modelMetas = /* @__PURE__ */ new WeakMap();
76
74
  const modelGlobalRegistries = /* @__PURE__ */ new WeakMap();
77
75
  const classMenuExtensions = /* @__PURE__ */ new WeakMap();
76
+ async function loadOpenStepSettingsDialog() {
77
+ const mod = await import("../components/settings/wrappers/contextual/StepSettingsDialog");
78
+ return mod.openStepSettingsDialog;
79
+ }
80
+ __name(loadOpenStepSettingsDialog, "loadOpenStepSettingsDialog");
81
+ async function loadOpenRequiredParamsStepFormDialog() {
82
+ const mod = await import("../components/settings/wrappers/contextual/StepRequiredSettingsDialog");
83
+ return mod.openRequiredParamsStepFormDialog;
84
+ }
85
+ __name(loadOpenRequiredParamsStepFormDialog, "loadOpenRequiredParamsStepFormDialog");
78
86
  var ModelRenderMode = /* @__PURE__ */ ((ModelRenderMode2) => {
79
87
  ModelRenderMode2["ReactElement"] = "reactElement";
80
88
  ModelRenderMode2["RenderFunction"] = "renderFunction";
@@ -1058,7 +1066,7 @@ const _FlowModel = class _FlowModel {
1058
1066
  * @param {string} stepKey 步骤的唯一标识符
1059
1067
  * @returns {void}
1060
1068
  */
1061
- openStepSettingsDialog(flowKey, stepKey) {
1069
+ async openStepSettingsDialog(flowKey, stepKey) {
1062
1070
  var _a;
1063
1071
  const flow = this.getFlow(flowKey);
1064
1072
  const step = (_a = flow == null ? void 0 : flow.steps) == null ? void 0 : _a[stepKey];
@@ -1069,7 +1077,8 @@ const _FlowModel = class _FlowModel {
1069
1077
  const ctx = new import_flowContext.FlowRuntimeContext(this, flowKey, "settings");
1070
1078
  (0, import_utils.setupRuntimeContextSteps)(ctx, flow.steps, this, flowKey);
1071
1079
  ctx.defineProperty("currentStep", { value: step });
1072
- return (0, import_StepSettingsDialog.openStepSettingsDialog)({
1080
+ const openStepSettingsDialog = await loadOpenStepSettingsDialog();
1081
+ return openStepSettingsDialog({
1073
1082
  model: this,
1074
1083
  flowKey,
1075
1084
  stepKey,
@@ -1084,7 +1093,8 @@ const _FlowModel = class _FlowModel {
1084
1093
  * @returns {Promise<any>} 返回表单提交的值
1085
1094
  */
1086
1095
  async configureRequiredSteps(dialogWidth, dialogTitle) {
1087
- return (0, import_StepRequiredSettingsDialog.openRequiredParamsStepFormDialog)({
1096
+ const openRequiredParamsStepFormDialog = await loadOpenRequiredParamsStepFormDialog();
1097
+ return openRequiredParamsStepFormDialog({
1088
1098
  model: this,
1089
1099
  dialogWidth,
1090
1100
  dialogTitle
@@ -1303,7 +1313,7 @@ const _ErrorFlowModel = class _ErrorFlowModel extends FlowModel {
1303
1313
  this.errorMessage = msg;
1304
1314
  }
1305
1315
  render() {
1306
- return /* @__PURE__ */ import_react.default.createElement(import_lib.Typography.Text, { type: "danger" }, this.errorMessage);
1316
+ return /* @__PURE__ */ import_react.default.createElement(import_antd.Typography.Text, { type: "danger" }, this.errorMessage);
1307
1317
  }
1308
1318
  };
1309
1319
  __name(_ErrorFlowModel, "ErrorFlowModel");
@@ -51,8 +51,31 @@ const observer = /* @__PURE__ */ __name((Component, options) => {
51
51
  const ctxRef = (0, import_react.useRef)(ctx);
52
52
  ctxRef.current = ctx;
53
53
  const pendingDisposerRef = (0, import_react.useRef)(null);
54
+ const pendingTimerRef = (0, import_react.useRef)(null);
55
+ const clearPendingDisposer = /* @__PURE__ */ __name(() => {
56
+ if (pendingDisposerRef.current) {
57
+ pendingDisposerRef.current();
58
+ pendingDisposerRef.current = null;
59
+ }
60
+ }, "clearPendingDisposer");
61
+ const clearPendingTimer = /* @__PURE__ */ __name(() => {
62
+ if (pendingTimerRef.current) {
63
+ clearTimeout(pendingTimerRef.current);
64
+ pendingTimerRef.current = null;
65
+ }
66
+ }, "clearPendingTimer");
67
+ const isContextActive = /* @__PURE__ */ __name(() => {
68
+ var _a, _b;
69
+ const pageActive = getPageActive(ctxRef.current);
70
+ const tabActive = (_b = (_a = ctxRef.current) == null ? void 0 : _a.tabActive) == null ? void 0 : _b.value;
71
+ return pageActive !== false && tabActive !== false;
72
+ }, "isContextActive");
54
73
  (0, import_react.useEffect)(() => {
55
74
  return () => {
75
+ if (pendingTimerRef.current) {
76
+ clearTimeout(pendingTimerRef.current);
77
+ pendingTimerRef.current = null;
78
+ }
56
79
  if (pendingDisposerRef.current) {
57
80
  pendingDisposerRef.current();
58
81
  pendingDisposerRef.current = null;
@@ -62,30 +85,37 @@ const observer = /* @__PURE__ */ __name((Component, options) => {
62
85
  const ObservedComponent = (0, import_react.useMemo)(
63
86
  () => (0, import_reactive_react.observer)(Component, {
64
87
  scheduler(updater) {
65
- var _a, _b;
66
- const pageActive = getPageActive(ctxRef.current);
67
- const tabActive = (_b = (_a = ctxRef.current) == null ? void 0 : _a.tabActive) == null ? void 0 : _b.value;
68
- if (pageActive === false || tabActive === false) {
69
- setTimeout(() => {
88
+ if (!isContextActive()) {
89
+ if (pendingTimerRef.current || pendingDisposerRef.current) {
90
+ return;
91
+ }
92
+ pendingTimerRef.current = setTimeout(() => {
93
+ pendingTimerRef.current = null;
70
94
  if (pendingDisposerRef.current) {
71
95
  return;
72
96
  }
73
- const disposer = (0, import_reactive.autorun)(() => {
74
- var _a2, _b2, _c, _d, _e, _f;
75
- if (((_b2 = (_a2 = ctxRef.current) == null ? void 0 : _a2.pageActive) == null ? void 0 : _b2.value) && (((_d = (_c = ctxRef.current) == null ? void 0 : _c.tabActive) == null ? void 0 : _d.value) === true || ((_f = (_e = ctxRef.current) == null ? void 0 : _e.tabActive) == null ? void 0 : _f.value) === void 0)) {
97
+ if (isContextActive()) {
98
+ updater();
99
+ return;
100
+ }
101
+ pendingDisposerRef.current = (0, import_reactive.reaction)(
102
+ () => isContextActive(),
103
+ (active) => {
104
+ if (!active) {
105
+ return;
106
+ }
107
+ clearPendingDisposer();
76
108
  updater();
77
- disposer == null ? void 0 : disposer();
78
- pendingDisposerRef.current = null;
109
+ },
110
+ {
111
+ name: "FlowObserverPendingUpdate"
79
112
  }
80
- });
81
- pendingDisposerRef.current = disposer;
113
+ );
82
114
  });
83
115
  return;
84
116
  }
85
- if (pendingDisposerRef.current) {
86
- pendingDisposerRef.current();
87
- pendingDisposerRef.current = null;
88
- }
117
+ clearPendingTimer();
118
+ clearPendingDisposer();
89
119
  updater();
90
120
  },
91
121
  ...options
@@ -6,7 +6,7 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
- export type RunJSVersion = 'v1' | (string & {});
9
+ export type RunJSVersion = 'v1' | 'v2' | (string & {});
10
10
  export type RunJSContextCtor = new (delegate: any) => any;
11
11
  export type RunJSContextMeta = {
12
12
  scenes?: string[];
@@ -67,19 +67,27 @@ async function setupRunJSContexts() {
67
67
  import("./contexts/JSRecordActionRunJSContext"),
68
68
  import("./contexts/JSCollectionActionRunJSContext")
69
69
  ]);
70
- const v1 = "v1";
71
- import_registry.RunJSContextRegistry.register(v1, "*", import_flowContext.FlowRunJSContext);
72
- import_registry.RunJSContextRegistry.register(v1, "JSBlockModel", JSBlockRunJSContext, { scenes: ["block"] });
73
- import_registry.RunJSContextRegistry.register(v1, "JSFieldModel", JSFieldRunJSContext, { scenes: ["detail"] });
74
- import_registry.RunJSContextRegistry.register(v1, "JSEditableFieldModel", JSEditableFieldRunJSContext, { scenes: ["form"] });
75
- import_registry.RunJSContextRegistry.register(v1, "JSItemModel", JSItemRunJSContext, { scenes: ["form"] });
76
- import_registry.RunJSContextRegistry.register(v1, "JSColumnModel", JSColumnRunJSContext, { scenes: ["table"] });
77
- import_registry.RunJSContextRegistry.register(v1, "FormJSFieldItemModel", FormJSFieldItemRunJSContext, { scenes: ["form"] });
78
- import_registry.RunJSContextRegistry.register(v1, "JSRecordActionModel", JSRecordActionRunJSContext, { scenes: ["table"] });
79
- import_registry.RunJSContextRegistry.register(v1, "JSCollectionActionModel", JSCollectionActionRunJSContext, { scenes: ["table"] });
80
- await (0, import_contributions.applyRunJSContextContributions)(v1);
70
+ const registerBuiltins = /* @__PURE__ */ __name((version) => {
71
+ import_registry.RunJSContextRegistry.register(version, "*", import_flowContext.FlowRunJSContext);
72
+ import_registry.RunJSContextRegistry.register(version, "JSBlockModel", JSBlockRunJSContext, { scenes: ["block"] });
73
+ import_registry.RunJSContextRegistry.register(version, "JSFieldModel", JSFieldRunJSContext, { scenes: ["detail"] });
74
+ import_registry.RunJSContextRegistry.register(version, "JSEditableFieldModel", JSEditableFieldRunJSContext, { scenes: ["form"] });
75
+ import_registry.RunJSContextRegistry.register(version, "JSItemModel", JSItemRunJSContext, { scenes: ["form"] });
76
+ import_registry.RunJSContextRegistry.register(version, "JSItemActionModel", JSItemRunJSContext, { scenes: ["table"] });
77
+ import_registry.RunJSContextRegistry.register(version, "JSColumnModel", JSColumnRunJSContext, { scenes: ["table"] });
78
+ import_registry.RunJSContextRegistry.register(version, "FormJSFieldItemModel", FormJSFieldItemRunJSContext, { scenes: ["form"] });
79
+ import_registry.RunJSContextRegistry.register(version, "JSRecordActionModel", JSRecordActionRunJSContext, { scenes: ["table"] });
80
+ import_registry.RunJSContextRegistry.register(version, "JSCollectionActionModel", JSCollectionActionRunJSContext, {
81
+ scenes: ["table"]
82
+ });
83
+ }, "registerBuiltins");
84
+ const versions = ["v1", "v2"];
85
+ for (const version of versions) {
86
+ registerBuiltins(version);
87
+ await (0, import_contributions.applyRunJSContextContributions)(version);
88
+ (0, import_contributions.markRunJSContextsSetupDone)(version);
89
+ }
81
90
  done = true;
82
- (0, import_contributions.markRunJSContextsSetupDone)(v1);
83
91
  }
84
92
  __name(setupRunJSContexts, "setupRunJSContexts");
85
93
  // Annotate the CommonJS export names for ESM import in node:
@@ -81,6 +81,7 @@ const snippets = {
81
81
  "scene/detail/status-tag": /* @__PURE__ */ __name(() => import("./scene/detail/status-tag.snippet"), "scene/detail/status-tag"),
82
82
  "scene/detail/relative-time": /* @__PURE__ */ __name(() => import("./scene/detail/relative-time.snippet"), "scene/detail/relative-time"),
83
83
  "scene/detail/percentage-bar": /* @__PURE__ */ __name(() => import("./scene/detail/percentage-bar.snippet"), "scene/detail/percentage-bar"),
84
+ "scene/detail/set-field-style": /* @__PURE__ */ __name(() => import("./scene/detail/set-field-style.snippet"), "scene/detail/set-field-style"),
84
85
  // scene/form
85
86
  "scene/form/render-basic": /* @__PURE__ */ __name(() => import("./scene/form/render-basic.snippet"), "scene/form/render-basic"),
86
87
  "scene/form/set-field-value": /* @__PURE__ */ __name(() => import("./scene/form/set-field-value.snippet"), "scene/form/set-field-value"),
@@ -98,7 +99,8 @@ const snippets = {
98
99
  "scene/table/collection-selected-count": /* @__PURE__ */ __name(() => import("./scene/table/collection-selected-count.snippet"), "scene/table/collection-selected-count"),
99
100
  "scene/table/iterate-selected-rows": /* @__PURE__ */ __name(() => import("./scene/table/iterate-selected-rows.snippet"), "scene/table/iterate-selected-rows"),
100
101
  "scene/table/destroy-selected": /* @__PURE__ */ __name(() => import("./scene/table/destroy-selected.snippet"), "scene/table/destroy-selected"),
101
- "scene/table/export-selected-json": /* @__PURE__ */ __name(() => import("./scene/table/export-selected-json.snippet"), "scene/table/export-selected-json")
102
+ "scene/table/export-selected-json": /* @__PURE__ */ __name(() => import("./scene/table/export-selected-json.snippet"), "scene/table/export-selected-json"),
103
+ "scene/table/set-cell-style": /* @__PURE__ */ __name(() => import("./scene/table/set-cell-style.snippet"), "scene/table/set-cell-style")
102
104
  };
103
105
  var snippets_default = snippets;
104
106
  function registerRunJSSnippet(ref, loader, options) {
@@ -131,10 +133,19 @@ function normalizeScenes(def, key) {
131
133
  return [];
132
134
  }
133
135
  __name(normalizeScenes, "normalizeScenes");
136
+ function normalizeSceneGroup(scene) {
137
+ const mapping = {
138
+ detailFieldEvent: "detail",
139
+ tableFieldEvent: "table",
140
+ formFieldEvent: "form"
141
+ };
142
+ return mapping[scene] || scene;
143
+ }
144
+ __name(normalizeSceneGroup, "normalizeSceneGroup");
134
145
  function computeGroups(def, key) {
135
146
  const scenes = normalizeScenes(def, key);
136
147
  if (scenes.length) {
137
- return scenes.map((scene) => `scene/${scene}`);
148
+ return Array.from(new Set(scenes.map((scene) => `scene/${normalizeSceneGroup(scene)}`)));
138
149
  }
139
150
  const parts = key.split("/");
140
151
  if (!parts.length) return [];
@@ -0,0 +1,11 @@
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 { SnippetModule } from '../../types';
10
+ declare const snippet: SnippetModule;
11
+ export default snippet;
@@ -0,0 +1,50 @@
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
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var set_field_style_snippet_exports = {};
28
+ __export(set_field_style_snippet_exports, {
29
+ default: () => set_field_style_snippet_default
30
+ });
31
+ module.exports = __toCommonJS(set_field_style_snippet_exports);
32
+ const snippet = {
33
+ contexts: ["*"],
34
+ scenes: ["detailFieldEvent", "formFieldEvent"],
35
+ prefix: "sn-item-style",
36
+ label: "Set form item/details item style",
37
+ description: "Customize form item and details item container styles",
38
+ locales: {
39
+ "zh-CN": {
40
+ label: "\u8BBE\u7F6E\u8868\u5355\u9879/\u8BE6\u60C5\u9879\u6837\u5F0F",
41
+ description: "\u81EA\u5B9A\u4E49\u8868\u5355\u9879\u548C\u8BE6\u60C5\u9879\u5BB9\u5668\u6837\u5F0F"
42
+ }
43
+ },
44
+ content: `
45
+ ctx.model.props.style = {
46
+ background: 'red',
47
+ };
48
+ `
49
+ };
50
+ var set_field_style_snippet_default = snippet;
@@ -0,0 +1,11 @@
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 { SnippetModule } from '../../types';
10
+ declare const snippet: SnippetModule;
11
+ export default snippet;
@@ -0,0 +1,54 @@
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
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var set_cell_style_snippet_exports = {};
28
+ __export(set_cell_style_snippet_exports, {
29
+ default: () => set_cell_style_snippet_default
30
+ });
31
+ module.exports = __toCommonJS(set_cell_style_snippet_exports);
32
+ const snippet = {
33
+ contexts: ["*"],
34
+ scenes: ["tableFieldEvent"],
35
+ prefix: "sn-table-cell-style",
36
+ label: "Set table cell style",
37
+ description: "Customize table field cell styles with onCell",
38
+ locales: {
39
+ "zh-CN": {
40
+ label: "\u8868\u683C\u5B57\u6BB5\u6837\u5F0F\u8BBE\u7F6E",
41
+ description: "\u901A\u8FC7 onCell \u81EA\u5B9A\u4E49\u8868\u683C\u5B57\u6BB5\u5355\u5143\u683C\u6837\u5F0F"
42
+ }
43
+ },
44
+ content: `
45
+ ctx.model.props.onCell = (record, rowIndex) => {
46
+ return {
47
+ style: {
48
+ background: 'red',
49
+ },
50
+ };
51
+ };
52
+ `
53
+ };
54
+ var set_cell_style_snippet_default = snippet;
@@ -9,7 +9,10 @@
9
9
  import type { FlowEngine } from '../flowEngine';
10
10
  import type { FlowModel } from '../models/flowModel';
11
11
  type LifecycleType = 'created' | 'mounted' | 'unmounted' | 'destroyed' | `event:${string}:start` | `event:${string}:end` | `event:${string}:error`;
12
- export type ScheduleWhen = LifecycleType | ((e: LifecycleEvent) => boolean);
12
+ type EventPredicateWhen = ((e: LifecycleEvent) => boolean) & {
13
+ __eventType?: string;
14
+ };
15
+ export type ScheduleWhen = LifecycleType | EventPredicateWhen;
13
16
  export interface ScheduleOptions {
14
17
  when?: ScheduleWhen;
15
18
  }
@@ -22,6 +25,7 @@ export interface LifecycleEvent {
22
25
  error?: any;
23
26
  inputArgs?: Record<string, any>;
24
27
  result?: any;
28
+ aborted?: boolean;
25
29
  flowKey?: string;
26
30
  stepKey?: string;
27
31
  }
@@ -171,8 +171,9 @@ const _ModelOperationScheduler = class _ModelOperationScheduler {
171
171
  this.unbindHandlers.push(() => emitter.off("model:destroyed", onDestroyed));
172
172
  }
173
173
  ensureEventSubscriptionIfNeeded(when) {
174
- if (!when || typeof when !== "string") return;
175
- const parsed = this.parseEventWhen(when);
174
+ const eventType = typeof when === "string" ? when : typeof when === "function" ? when.__eventType : void 0;
175
+ if (!eventType) return;
176
+ const parsed = this.parseEventWhen(eventType);
176
177
  if (!parsed) return;
177
178
  const { name } = parsed;
178
179
  if (this.subscribedEventNames.has(name)) return;
package/lib/types.d.ts CHANGED
@@ -177,7 +177,7 @@ export interface ActionDefinition<TModel extends FlowModel = FlowModel, TCtx ext
177
177
  * - 收录内置常用事件,便于智能提示;
178
178
  * - 允许扩展字符串以保持向后兼容。
179
179
  */
180
- export type FlowEventName = 'click' | 'submit' | 'reset' | 'remove' | 'openView' | 'dropdownOpen' | 'popupScroll' | 'search' | 'customRequest' | 'collapseToggle' | (string & {});
180
+ export type FlowEventName = 'click' | 'close' | 'submit' | 'reset' | 'remove' | 'openView' | 'dropdownOpen' | 'popupScroll' | 'search' | 'customRequest' | 'collapseToggle' | (string & {});
181
181
  /**
182
182
  * 事件流的执行时机(phase)。
183
183
  *
@@ -303,6 +303,52 @@ export interface CreateModelOptions {
303
303
  delegateToParent?: boolean;
304
304
  [key: string]: any;
305
305
  }
306
+ /**
307
+ * FlowModel loader result.
308
+ * Supports returning the model constructor directly, a default export, or a module object containing the named export.
309
+ */
310
+ export type FlowModelLoaderResult = ModelConstructor | {
311
+ default?: ModelConstructor;
312
+ [key: string]: unknown;
313
+ } | Record<string, unknown>;
314
+ /**
315
+ * FlowModel loader function.
316
+ */
317
+ export type FlowModelLoader = () => Promise<FlowModelLoaderResult>;
318
+ /**
319
+ * FlowModel loader entry (normalized internal form).
320
+ */
321
+ export interface FlowModelLoaderEntry {
322
+ loader: FlowModelLoader;
323
+ extends?: string[];
324
+ }
325
+ /**
326
+ * FlowModel loader input (user-facing form for registerModelLoaders).
327
+ * The `extends` field accepts flexible formats that will be normalized to `string[]` at registration time.
328
+ */
329
+ export interface FlowModelLoaderInput {
330
+ loader: FlowModelLoader;
331
+ extends?: string | ModelConstructor | (string | ModelConstructor)[];
332
+ }
333
+ /**
334
+ * FlowModel loader entry map (normalized internal form).
335
+ */
336
+ export type FlowModelLoaderMap = Record<string, FlowModelLoaderEntry>;
337
+ /**
338
+ * FlowModel loader input map (user-facing form for registerModelLoaders).
339
+ */
340
+ export type FlowModelLoaderInputMap = Record<string, FlowModelLoaderInput>;
341
+ /**
342
+ * Batch ensure result.
343
+ */
344
+ export interface EnsureBatchResult {
345
+ requested: string[];
346
+ loaded: string[];
347
+ failed: Array<{
348
+ name: string;
349
+ error?: unknown;
350
+ }>;
351
+ }
306
352
  export interface IFlowModelRepository<T extends FlowModel = FlowModel> {
307
353
  findOne(query: Record<string, any>): Promise<Record<string, any> | null>;
308
354
  save(model: T, options?: {
@@ -8,11 +8,11 @@
8
8
  */
9
9
  export { BLOCK_GROUP_CONFIGS, BLOCK_TYPES, FLOW_ENGINE_NAMESPACE, MENU_KEYS, type BlockBuilderConfig, } from './constants';
10
10
  export { escapeT, getT, tExpr } from './translation';
11
- export { FlowCancelSaveException, FlowExitException } from './exceptions';
11
+ export { FlowCancelSaveException, FlowExitAllException, FlowExitException } from './exceptions';
12
12
  export { defineAction } from './flow-definitions';
13
13
  export { isInheritedFrom } from './inheritance';
14
14
  export { resolveCreateModelOptions, resolveDefaultParams, resolveExpressions } from './params-resolvers';
15
- export { compileUiSchema, resolveStepUiSchema, resolveStepDisabledInSettings, resolveUiMode, shouldHideStepInSettings, } from './schema-utils';
15
+ export { compileUiSchema, resolveStepUiSchema, resolveStepDisabledInSettings, resolveUiMode, shouldHideEventInSettings, shouldHideStepInSettings, } from './schema-utils';
16
16
  export { setupRuntimeContextSteps } from './setupRuntimeContextSteps';
17
17
  export { createCollectionContextMeta } from './createCollectionContextMeta';
18
18
  export { createAssociationAwareObjectMetaFactory, createAssociationSubpathResolver } from './associationObjectVariable';
@@ -30,6 +30,7 @@ __export(utils_exports, {
30
30
  BLOCK_TYPES: () => import_constants.BLOCK_TYPES,
31
31
  FLOW_ENGINE_NAMESPACE: () => import_constants.FLOW_ENGINE_NAMESPACE,
32
32
  FlowCancelSaveException: () => import_exceptions.FlowCancelSaveException,
33
+ FlowExitAllException: () => import_exceptions.FlowExitAllException,
33
34
  FlowExitException: () => import_exceptions.FlowExitException,
34
35
  MENU_KEYS: () => import_constants.MENU_KEYS,
35
36
  buildRecordMeta: () => import_variablesParams.buildRecordMeta,
@@ -86,6 +87,7 @@ __export(utils_exports, {
86
87
  serializeCtxDateValue: () => import_dateVariable.serializeCtxDateValue,
87
88
  setAutoFlowError: () => import_autoFlowError.setAutoFlowError,
88
89
  setupRuntimeContextSteps: () => import_setupRuntimeContextSteps.setupRuntimeContextSteps,
90
+ shouldHideEventInSettings: () => import_schema_utils.shouldHideEventInSettings,
89
91
  shouldHideStepInSettings: () => import_schema_utils.shouldHideStepInSettings,
90
92
  tExpr: () => import_translation.tExpr
91
93
  });
@@ -119,6 +121,7 @@ var import_resolveModuleUrl = require("./resolveModuleUrl");
119
121
  BLOCK_TYPES,
120
122
  FLOW_ENGINE_NAMESPACE,
121
123
  FlowCancelSaveException,
124
+ FlowExitAllException,
122
125
  FlowExitException,
123
126
  MENU_KEYS,
124
127
  buildRecordMeta,
@@ -175,6 +178,7 @@ var import_resolveModuleUrl = require("./resolveModuleUrl");
175
178
  serializeCtxDateValue,
176
179
  setAutoFlowError,
177
180
  setupRuntimeContextSteps,
181
+ shouldHideEventInSettings,
178
182
  shouldHideStepInSettings,
179
183
  tExpr
180
184
  });
@@ -92,7 +92,7 @@ const parsePathnameToViewParams = /* @__PURE__ */ __name((pathname) => {
92
92
  } catch (_) {
93
93
  parsed = decoded;
94
94
  }
95
- } else if (decoded && decoded.includes("=") && decoded.includes("&")) {
95
+ } else if (decoded && /^[^=&]+=[^=&]*(?:&[^=&]+=[^=&]*)*$/.test(decoded)) {
96
96
  parsed = parseKeyValuePairs(decoded);
97
97
  }
98
98
  currentView.filterByTk = parsed;
@@ -527,8 +527,8 @@ function extractUsedCtxLibKeys(code) {
527
527
  }
528
528
  __name(extractUsedCtxLibKeys, "extractUsedCtxLibKeys");
529
529
  function injectEnsureLibsPreamble(code) {
530
- if (!CTX_LIBS_MARKER_RE.test(code)) return code;
531
530
  if (ENSURE_LIBS_MARKER_RE.test(code)) return code;
531
+ if (!CTX_LIBS_MARKER_RE.test(code)) return code;
532
532
  const keys = extractUsedCtxLibKeys(code);
533
533
  if (!keys.length) return code;
534
534
  return `/* __runjs_ensure_libs */