@nocobase/flow-engine 2.0.0-beta.15 → 2.0.0-beta.16

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 (40) hide show
  1. package/lib/BlockScopedFlowEngine.js +0 -1
  2. package/lib/ViewScopedFlowEngine.js +3 -0
  3. package/lib/data-source/index.js +3 -0
  4. package/lib/flowEngine.d.ts +21 -0
  5. package/lib/flowEngine.js +38 -0
  6. package/lib/index.d.ts +1 -0
  7. package/lib/index.js +13 -0
  8. package/lib/models/CollectionFieldModel.d.ts +1 -0
  9. package/lib/models/CollectionFieldModel.js +3 -2
  10. package/lib/resources/baseRecordResource.d.ts +5 -0
  11. package/lib/resources/baseRecordResource.js +24 -0
  12. package/lib/resources/multiRecordResource.d.ts +1 -0
  13. package/lib/resources/multiRecordResource.js +11 -4
  14. package/lib/resources/singleRecordResource.js +2 -0
  15. package/lib/resources/sqlResource.d.ts +1 -0
  16. package/lib/resources/sqlResource.js +8 -3
  17. package/lib/views/useDialog.js +7 -1
  18. package/lib/views/useDrawer.js +7 -1
  19. package/lib/views/usePage.js +10 -1
  20. package/lib/views/viewEvents.d.ts +17 -0
  21. package/lib/views/viewEvents.js +88 -0
  22. package/package.json +4 -4
  23. package/src/BlockScopedFlowEngine.ts +2 -5
  24. package/src/ViewScopedFlowEngine.ts +4 -0
  25. package/src/__tests__/flowEngine.dataSourceDirty.test.ts +63 -0
  26. package/src/data-source/index.ts +3 -0
  27. package/src/flowEngine.ts +41 -0
  28. package/src/index.ts +8 -0
  29. package/src/models/CollectionFieldModel.tsx +3 -1
  30. package/src/resources/__tests__/multiRecordResource.test.ts +44 -0
  31. package/src/resources/__tests__/sqlResource.test.ts +60 -0
  32. package/src/resources/baseRecordResource.ts +31 -0
  33. package/src/resources/multiRecordResource.ts +11 -4
  34. package/src/resources/singleRecordResource.ts +3 -0
  35. package/src/resources/sqlResource.ts +8 -3
  36. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +35 -4
  37. package/src/views/useDialog.tsx +8 -0
  38. package/src/views/useDrawer.tsx +8 -0
  39. package/src/views/usePage.tsx +13 -0
  40. package/src/views/viewEvents.ts +51 -0
@@ -37,7 +37,6 @@ function createBlockScopedEngine(parent) {
37
37
  local.setModelRepository(parent.modelRepository);
38
38
  }
39
39
  local.context.addDelegate(parent.context);
40
- const originalUnlink = local.unlinkFromStack.bind(local);
41
40
  local.unlinkFromStack = function() {
42
41
  const prev = local._previousEngine;
43
42
  const next = local._nextEngine;
@@ -31,8 +31,10 @@ __export(ViewScopedFlowEngine_exports, {
31
31
  });
32
32
  module.exports = __toCommonJS(ViewScopedFlowEngine_exports);
33
33
  var import_flowEngine = require("./flowEngine");
34
+ var import_viewEvents = require("./views/viewEvents");
34
35
  function createViewScopedEngine(parent) {
35
36
  const local = new import_flowEngine.FlowEngine();
37
+ Object.defineProperty(local, import_viewEvents.ENGINE_SCOPE_KEY, { value: import_viewEvents.VIEW_ENGINE_SCOPE, configurable: true });
36
38
  if (parent.modelRepository) {
37
39
  local.setModelRepository(parent.modelRepository);
38
40
  }
@@ -48,6 +50,7 @@ function createViewScopedEngine(parent) {
48
50
  "_applyFlowCache",
49
51
  "executor",
50
52
  "context",
53
+ import_viewEvents.ENGINE_SCOPE_KEY,
51
54
  "previousEngine",
52
55
  "nextEngine",
53
56
  // 调度器与事件总线局部化
@@ -400,6 +400,9 @@ const _Collection = class _Collection {
400
400
  if (typeof this.filterTargetKey === "string") {
401
401
  return record[this.filterTargetKey];
402
402
  }
403
+ if (Array.isArray(this.filterTargetKey) && this.filterTargetKey.length === 1) {
404
+ return record[this.filterTargetKey[0]];
405
+ }
403
406
  return import_lodash.default.pick(record, this.filterTargetKey);
404
407
  }
405
408
  get titleableFields() {
@@ -84,6 +84,17 @@ export declare class FlowEngine {
84
84
  private _previousEngine?;
85
85
  private _nextEngine?;
86
86
  private _resources;
87
+ /**
88
+ * Data change registry used to coordinate "refresh on active" across view-scoped engines.
89
+ *
90
+ * Keyed by: dataSourceKey -> resourceName -> version.
91
+ * - mark: increments version
92
+ * - get: returns current version (default 0)
93
+ *
94
+ * NOTE: ViewScopedFlowEngine proxies delegate non-local fields/methods to parents, so this
95
+ * registry naturally lives on the root engine instance and is shared across the whole view stack.
96
+ */
97
+ private _dataSourceDirtyVersions;
87
98
  /**
88
99
  * 引擎事件总线(目前用于模型生命周期等事件)。
89
100
  * ViewScopedFlowEngine 持有自己的实例,实现作用域隔离。
@@ -116,6 +127,16 @@ export declare class FlowEngine {
116
127
  getScheduler(): ModelOperationScheduler;
117
128
  /** 释放并清理当前引擎本地调度器(若存在) */
118
129
  disposeScheduler(): void;
130
+ /**
131
+ * Mark a data source resource as "dirty" (changed).
132
+ * This is used by data blocks to decide whether to refresh when a view becomes active.
133
+ */
134
+ markDataSourceDirty(dataSourceKey: string, resourceName: string): number;
135
+ /**
136
+ * Get current dirty version for a data source resource.
137
+ * Returns 0 when no writes have been recorded.
138
+ */
139
+ getDataSourceDirtyVersion(dataSourceKey: string, resourceName: string): number;
119
140
  /** 在目标模型生命周期达成时执行操作(仅在 View 引擎本地存储计划) */
120
141
  scheduleModelOperation(fromModelOrUid: FlowModel | string, toUid: string, fn: (model: FlowModel) => Promise<void> | void, options?: ScheduleOptions): ScheduledCancel;
121
142
  /** 上一个引擎(根引擎为 undefined) */
package/lib/flowEngine.js CHANGED
@@ -120,6 +120,17 @@ const _FlowEngine = class _FlowEngine {
120
120
  __publicField(this, "_previousEngine");
121
121
  __publicField(this, "_nextEngine");
122
122
  __publicField(this, "_resources", /* @__PURE__ */ new Map());
123
+ /**
124
+ * Data change registry used to coordinate "refresh on active" across view-scoped engines.
125
+ *
126
+ * Keyed by: dataSourceKey -> resourceName -> version.
127
+ * - mark: increments version
128
+ * - get: returns current version (default 0)
129
+ *
130
+ * NOTE: ViewScopedFlowEngine proxies delegate non-local fields/methods to parents, so this
131
+ * registry naturally lives on the root engine instance and is shared across the whole view stack.
132
+ */
133
+ __publicField(this, "_dataSourceDirtyVersions", /* @__PURE__ */ new Map());
123
134
  /**
124
135
  * 引擎事件总线(目前用于模型生命周期等事件)。
125
136
  * ViewScopedFlowEngine 持有自己的实例,实现作用域隔离。
@@ -187,6 +198,33 @@ const _FlowEngine = class _FlowEngine {
187
198
  }
188
199
  }
189
200
  }
201
+ /**
202
+ * Mark a data source resource as "dirty" (changed).
203
+ * This is used by data blocks to decide whether to refresh when a view becomes active.
204
+ */
205
+ markDataSourceDirty(dataSourceKey, resourceName) {
206
+ const dsKey = String(dataSourceKey || "main");
207
+ const resName = String(resourceName || "");
208
+ if (!resName) return this.getDataSourceDirtyVersion(dsKey, resName);
209
+ const ds = this._dataSourceDirtyVersions.get(dsKey) || /* @__PURE__ */ new Map();
210
+ if (!this._dataSourceDirtyVersions.has(dsKey)) {
211
+ this._dataSourceDirtyVersions.set(dsKey, ds);
212
+ }
213
+ const next = (ds.get(resName) || 0) + 1;
214
+ ds.set(resName, next);
215
+ return next;
216
+ }
217
+ /**
218
+ * Get current dirty version for a data source resource.
219
+ * Returns 0 when no writes have been recorded.
220
+ */
221
+ getDataSourceDirtyVersion(dataSourceKey, resourceName) {
222
+ var _a;
223
+ const dsKey = String(dataSourceKey || "main");
224
+ const resName = String(resourceName || "");
225
+ if (!resName) return 0;
226
+ return ((_a = this._dataSourceDirtyVersions.get(dsKey)) == null ? void 0 : _a.get(resName)) || 0;
227
+ }
190
228
  /** 在目标模型生命周期达成时执行操作(仅在 View 引擎本地存储计划) */
191
229
  scheduleModelOperation(fromModelOrUid, toUid, fn, options) {
192
230
  return this.getScheduler().schedule(fromModelOrUid, toUid, fn, options);
package/lib/index.d.ts CHANGED
@@ -29,6 +29,7 @@ export { RunJSContextRegistry, getModelClassName } from './runjs-context/registr
29
29
  export { setupRunJSContexts } from './runjs-context/setup';
30
30
  export { getSnippetBody, listSnippetsForContext } from './runjs-context/snippets';
31
31
  export * from './views';
32
+ export { DATA_SOURCE_DIRTY_EVENT, ENGINE_SCOPE_KEY, getEmitterViewActivatedVersion, VIEW_ACTIVATED_EVENT, VIEW_ACTIVATED_VERSION, VIEW_ENGINE_SCOPE, } from './views/viewEvents';
32
33
  export * from './FlowDefinition';
33
34
  export { createViewScopedEngine } from './ViewScopedFlowEngine';
34
35
  export { createBlockScopedEngine } from './BlockScopedFlowEngine';
package/lib/index.js CHANGED
@@ -27,11 +27,17 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
27
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
28
  var src_exports = {};
29
29
  __export(src_exports, {
30
+ DATA_SOURCE_DIRTY_EVENT: () => import_viewEvents.DATA_SOURCE_DIRTY_EVENT,
31
+ ENGINE_SCOPE_KEY: () => import_viewEvents.ENGINE_SCOPE_KEY,
30
32
  RunJSContextRegistry: () => import_registry.RunJSContextRegistry,
33
+ VIEW_ACTIVATED_EVENT: () => import_viewEvents.VIEW_ACTIVATED_EVENT,
34
+ VIEW_ACTIVATED_VERSION: () => import_viewEvents.VIEW_ACTIVATED_VERSION,
35
+ VIEW_ENGINE_SCOPE: () => import_viewEvents.VIEW_ENGINE_SCOPE,
31
36
  compileRunJs: () => import_jsxTransform.compileRunJs,
32
37
  createBlockScopedEngine: () => import_BlockScopedFlowEngine.createBlockScopedEngine,
33
38
  createJSRunnerWithVersion: () => import_helpers.createJSRunnerWithVersion,
34
39
  createViewScopedEngine: () => import_ViewScopedFlowEngine.createViewScopedEngine,
40
+ getEmitterViewActivatedVersion: () => import_viewEvents.getEmitterViewActivatedVersion,
35
41
  getModelClassName: () => import_registry.getModelClassName,
36
42
  getRunJSDocFor: () => import_helpers.getRunJSDocFor,
37
43
  getRunJSScenesForContext: () => import_helpers.getRunJSScenesForContext,
@@ -64,16 +70,23 @@ var import_registry = require("./runjs-context/registry");
64
70
  var import_setup = require("./runjs-context/setup");
65
71
  var import_snippets = require("./runjs-context/snippets");
66
72
  __reExport(src_exports, require("./views"), module.exports);
73
+ var import_viewEvents = require("./views/viewEvents");
67
74
  __reExport(src_exports, require("./FlowDefinition"), module.exports);
68
75
  var import_ViewScopedFlowEngine = require("./ViewScopedFlowEngine");
69
76
  var import_BlockScopedFlowEngine = require("./BlockScopedFlowEngine");
70
77
  // Annotate the CommonJS export names for ESM import in node:
71
78
  0 && (module.exports = {
79
+ DATA_SOURCE_DIRTY_EVENT,
80
+ ENGINE_SCOPE_KEY,
72
81
  RunJSContextRegistry,
82
+ VIEW_ACTIVATED_EVENT,
83
+ VIEW_ACTIVATED_VERSION,
84
+ VIEW_ENGINE_SCOPE,
73
85
  compileRunJs,
74
86
  createBlockScopedEngine,
75
87
  createJSRunnerWithVersion,
76
88
  createViewScopedEngine,
89
+ getEmitterViewActivatedVersion,
77
90
  getModelClassName,
78
91
  getRunJSDocFor,
79
92
  getRunJSScenesForContext,
@@ -45,6 +45,7 @@ export declare class CollectionFieldModel<T extends DefaultStructure = DefaultSt
45
45
  }): BindingOptions | null;
46
46
  static bindModelToInterface(modelName: string, interfaceName: string | string[], options?: {
47
47
  isDefault?: boolean;
48
+ order?: number;
48
49
  defaultProps?: object | ((ctx: FlowEngineContext, fieldInstance: CollectionField) => object);
49
50
  when?: (ctx: FlowEngineContext, fieldInstance: CollectionField) => boolean;
50
51
  }): void;
@@ -182,7 +182,7 @@ const _CollectionFieldModel = class _CollectionFieldModel extends import_flowMod
182
182
  if (!this.bindings.has(interfaceName)) {
183
183
  return [];
184
184
  }
185
- const bindings = this.bindings.get(interfaceName);
185
+ const bindings = this.bindings.get(interfaceName).sort((a, b) => a.order - b.order);
186
186
  return bindings.filter(
187
187
  (binding) => ctx.engine.getModelClass(binding.modelName) && binding.when(ctx, collectionField)
188
188
  );
@@ -245,7 +245,8 @@ const _CollectionFieldModel = class _CollectionFieldModel extends import_flowMod
245
245
  modelName,
246
246
  isDefault: options.isDefault || false,
247
247
  defaultProps: options.defaultProps || null,
248
- when: options.when || defaultWhen
248
+ when: options.when || defaultWhen,
249
+ order: options.order
249
250
  });
250
251
  this.currentBindings.set(interfaceName, bindings);
251
252
  }
@@ -30,6 +30,11 @@ export declare abstract class BaseRecordResource<TData = any> extends APIResourc
30
30
  runAction<TData = any, TMeta = any>(action: string, options: any): Promise<any>;
31
31
  setResourceName(resourceName: string): this;
32
32
  getResourceName(): string;
33
+ /**
34
+ * Mark current resource as dirty on the root FlowEngine.
35
+ * Used to coordinate "refresh on active" across view stacks.
36
+ */
37
+ protected markDataSourceDirty(resourceName?: string): void;
33
38
  setSourceId(sourceId: string | number): this;
34
39
  getSourceId(): string | number;
35
40
  setDataSourceKey(dataSourceKey: string): this;
@@ -44,6 +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
48
  const _BaseRecordResource = class _BaseRecordResource extends import_apiResource.APIResource {
48
49
  resourceName;
49
50
  sourceId = null;
@@ -145,6 +146,29 @@ const _BaseRecordResource = class _BaseRecordResource extends import_apiResource
145
146
  getResourceName() {
146
147
  return this.resourceName;
147
148
  }
149
+ /**
150
+ * Mark current resource as dirty on the root FlowEngine.
151
+ * Used to coordinate "refresh on active" across view stacks.
152
+ */
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)
170
+ });
171
+ }
148
172
  setSourceId(sourceId) {
149
173
  this.sourceId = sourceId;
150
174
  return this;
@@ -16,6 +16,7 @@ export declare class MultiRecordResource<TDataItem = any> extends BaseRecordReso
16
16
  value: Record<string, any>;
17
17
  };
18
18
  private refreshTimer;
19
+ private refreshWaiters;
19
20
  protected createActionOptions: {};
20
21
  protected updateActionOptions: {};
21
22
  protected _refreshActionName: string;
@@ -47,6 +47,7 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
47
47
  _data = import_reactive.observable.ref([]);
48
48
  _meta = import_reactive.observable.ref({});
49
49
  refreshTimer = null;
50
+ refreshWaiters = [];
50
51
  createActionOptions = {};
51
52
  updateActionOptions = {};
52
53
  _refreshActionName = "list";
@@ -130,6 +131,7 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
130
131
  async create(data, options) {
131
132
  const config = this.mergeRequestConfig({ data }, this.createActionOptions, options);
132
133
  const res = await this.runAction("create", config);
134
+ this.markDataSourceDirty();
133
135
  this.emit("saved", data);
134
136
  if ((options == null ? void 0 : options.refresh) !== false) {
135
137
  await this.refresh();
@@ -160,6 +162,7 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
160
162
  options
161
163
  );
162
164
  await this.runAction("update", config);
165
+ this.markDataSourceDirty();
163
166
  this.emit("saved", data);
164
167
  await this.refresh();
165
168
  }
@@ -180,6 +183,7 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
180
183
  options
181
184
  );
182
185
  await this.runAction("destroy", config);
186
+ this.markDataSourceDirty();
183
187
  const currentPage = this.getPage();
184
188
  const lastPage = Math.ceil((this.getCount() - import_lodash.default.castArray(filterByTk).length) / this.getPageSize());
185
189
  if (currentPage > lastPage) {
@@ -202,7 +206,11 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
202
206
  clearTimeout(this.refreshTimer);
203
207
  }
204
208
  return new Promise((resolve, reject) => {
209
+ this.refreshWaiters.push({ resolve, reject });
205
210
  this.refreshTimer = setTimeout(async () => {
211
+ const waiters = this.refreshWaiters;
212
+ this.refreshWaiters = [];
213
+ this.refreshTimer = null;
206
214
  try {
207
215
  this.clearError();
208
216
  this.loading = true;
@@ -218,13 +226,12 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
218
226
  this.setPageSize(meta.pageSize);
219
227
  }
220
228
  this.emit("refresh");
221
- this.loading = false;
222
- resolve();
229
+ waiters.forEach((w) => w.resolve());
223
230
  } catch (error) {
224
231
  this.setError(error);
225
- reject(error instanceof Error ? error : new Error(String(error)));
232
+ const err = error instanceof Error ? error : new Error(String(error));
233
+ waiters.forEach((w) => w.reject(err));
226
234
  } finally {
227
- this.refreshTimer = null;
228
235
  this.loading = false;
229
236
  }
230
237
  });
@@ -70,6 +70,7 @@ const _SingleRecordResource = class _SingleRecordResource extends import_baseRec
70
70
  ...config,
71
71
  data: result
72
72
  });
73
+ this.markDataSourceDirty();
73
74
  this.emit("saved", data);
74
75
  if ((options == null ? void 0 : options.refresh) !== false) {
75
76
  await this.refresh();
@@ -86,6 +87,7 @@ const _SingleRecordResource = class _SingleRecordResource extends import_baseRec
86
87
  options
87
88
  );
88
89
  await this.runAction("destroy", config);
90
+ this.markDataSourceDirty();
89
91
  this.setData(null);
90
92
  }
91
93
  async refresh() {
@@ -35,6 +35,7 @@ export declare class SQLResource<TData = any> extends BaseRecordResource<TData>
35
35
  value: Record<string, any>;
36
36
  };
37
37
  private refreshTimer;
38
+ private refreshWaiters;
38
39
  private _debugEnabled;
39
40
  private _sql;
40
41
  protected request: {
@@ -126,6 +126,7 @@ const _SQLResource = class _SQLResource extends import_baseRecordResource.BaseRe
126
126
  _data = import_reactive.observable.ref(null);
127
127
  _meta = import_reactive.observable.ref({});
128
128
  refreshTimer = null;
129
+ refreshWaiters = [];
129
130
  _debugEnabled = false;
130
131
  _sql;
131
132
  // 请求配置 - 与 APIClient 接口保持一致
@@ -261,7 +262,11 @@ const _SQLResource = class _SQLResource extends import_baseRecordResource.BaseRe
261
262
  clearTimeout(this.refreshTimer);
262
263
  }
263
264
  return new Promise((resolve, reject) => {
265
+ this.refreshWaiters.push({ resolve, reject });
264
266
  this.refreshTimer = setTimeout(async () => {
267
+ const waiters = this.refreshWaiters;
268
+ this.refreshWaiters = [];
269
+ this.refreshTimer = null;
265
270
  try {
266
271
  this.clearError();
267
272
  this.loading = true;
@@ -270,12 +275,12 @@ const _SQLResource = class _SQLResource extends import_baseRecordResource.BaseRe
270
275
  this.setData(data).setMeta(meta);
271
276
  this.loading = false;
272
277
  this.emit("refresh");
273
- resolve();
278
+ waiters.forEach((w) => w.resolve());
274
279
  } catch (error) {
275
280
  this.setError(error);
276
- reject(error instanceof Error ? error : new Error(String(error)));
281
+ const err = error instanceof Error ? error : new Error(String(error));
282
+ waiters.forEach((w) => w.reject(err));
277
283
  } finally {
278
- this.refreshTimer = null;
279
284
  this.loading = false;
280
285
  }
281
286
  });
@@ -48,6 +48,7 @@ var import_FlowContextProvider = require("../FlowContextProvider");
48
48
  var import_createViewMeta = require("./createViewMeta");
49
49
  var import_DialogComponent = __toESM(require("./DialogComponent"));
50
50
  var import_usePatchElement = __toESM(require("./usePatchElement"));
51
+ var import_viewEvents = require("./viewEvents");
51
52
  var import_provider = require("../provider");
52
53
  var import_ViewScopedFlowEngine = require("../ViewScopedFlowEngine");
53
54
  var import_variablesParams = require("../utils/variablesParams");
@@ -56,6 +57,7 @@ function useDialog() {
56
57
  const holderRef = React.useRef(null);
57
58
  const open = /* @__PURE__ */ __name((config, flowContext) => {
58
59
  var _a, _b, _c;
60
+ const parentEngine = flowContext == null ? void 0 : flowContext.engine;
59
61
  uuid += 1;
60
62
  const dialogRef = React.createRef();
61
63
  let closeFunc;
@@ -93,6 +95,7 @@ function useDialog() {
93
95
  }, "HeaderComponent");
94
96
  const ctx = new import_flowContext.FlowContext();
95
97
  const scopedEngine = (0, import_ViewScopedFlowEngine.createViewScopedEngine)(flowContext.engine);
98
+ const openerEngine = (0, import_viewEvents.resolveOpenerEngine)(parentEngine, scopedEngine);
96
99
  ctx.defineProperty("engine", { value: scopedEngine });
97
100
  ctx.addDelegate(scopedEngine.context);
98
101
  if (config.inheritContext !== false) {
@@ -105,11 +108,14 @@ function useDialog() {
105
108
  inputArgs: config.inputArgs || {},
106
109
  preventClose: !!config.preventClose,
107
110
  destroy: /* @__PURE__ */ __name((result) => {
108
- var _a2, _b2;
111
+ var _a2, _b2, _c2, _d;
109
112
  (_a2 = config.onClose) == null ? void 0 : _a2.call(config);
110
113
  (_b2 = dialogRef.current) == null ? void 0 : _b2.destroy();
111
114
  closeFunc == null ? void 0 : closeFunc();
112
115
  resolvePromise == null ? void 0 : resolvePromise(result);
116
+ const openerEmitter = openerEngine == null ? void 0 : openerEngine.emitter;
117
+ (0, import_viewEvents.bumpViewActivatedVersion)(openerEmitter);
118
+ (_d = openerEmitter == null ? void 0 : openerEmitter.emit) == null ? void 0 : _d.call(openerEmitter, import_viewEvents.VIEW_ACTIVATED_EVENT, { type: "dialog", viewUid: (_c2 = currentDialog == null ? void 0 : currentDialog.inputArgs) == null ? void 0 : _c2.viewUid });
113
119
  scopedEngine.unlinkFromStack();
114
120
  }, "destroy"),
115
121
  update: /* @__PURE__ */ __name((newConfig) => {
@@ -48,6 +48,7 @@ var import_FlowContextProvider = require("../FlowContextProvider");
48
48
  var import_createViewMeta = require("./createViewMeta");
49
49
  var import_DrawerComponent = __toESM(require("./DrawerComponent"));
50
50
  var import_usePatchElement = __toESM(require("./usePatchElement"));
51
+ var import_viewEvents = require("./viewEvents");
51
52
  var import_provider = require("../provider");
52
53
  var import_ViewScopedFlowEngine = require("../ViewScopedFlowEngine");
53
54
  var import_variablesParams = require("../utils/variablesParams");
@@ -76,6 +77,7 @@ function useDrawer() {
76
77
  RenderNestedDrawer.displayName = "RenderNestedDrawer";
77
78
  const open = /* @__PURE__ */ __name((config, flowContext) => {
78
79
  var _a, _b;
80
+ const parentEngine = flowContext.engine;
79
81
  const drawerRef = React.createRef();
80
82
  let closeFunc;
81
83
  let resolvePromise;
@@ -112,6 +114,7 @@ function useDrawer() {
112
114
  }, "HeaderComponent");
113
115
  const ctx = new import_flowContext.FlowContext();
114
116
  const scopedEngine = (0, import_ViewScopedFlowEngine.createViewScopedEngine)(flowContext.engine);
117
+ const openerEngine = (0, import_viewEvents.resolveOpenerEngine)(parentEngine, scopedEngine);
115
118
  ctx.defineProperty("engine", { value: scopedEngine });
116
119
  ctx.addDelegate(scopedEngine.context);
117
120
  if (config.inheritContext !== false) {
@@ -124,11 +127,14 @@ function useDrawer() {
124
127
  inputArgs: config.inputArgs || {},
125
128
  preventClose: !!config.preventClose,
126
129
  destroy: /* @__PURE__ */ __name((result) => {
127
- var _a2, _b2;
130
+ var _a2, _b2, _c, _d;
128
131
  (_a2 = config.onClose) == null ? void 0 : _a2.call(config);
129
132
  (_b2 = drawerRef.current) == null ? void 0 : _b2.destroy();
130
133
  closeFunc == null ? void 0 : closeFunc();
131
134
  resolvePromise == null ? void 0 : resolvePromise(result);
135
+ const openerEmitter = openerEngine == null ? void 0 : openerEngine.emitter;
136
+ (0, import_viewEvents.bumpViewActivatedVersion)(openerEmitter);
137
+ (_d = openerEmitter == null ? void 0 : openerEmitter.emit) == null ? void 0 : _d.call(openerEmitter, import_viewEvents.VIEW_ACTIVATED_EVENT, { type: "drawer", viewUid: (_c = currentDrawer == null ? void 0 : currentDrawer.inputArgs) == null ? void 0 : _c.viewUid });
132
138
  scopedEngine.unlinkFromStack();
133
139
  }, "destroy"),
134
140
  update: /* @__PURE__ */ __name((newConfig) => {
@@ -50,6 +50,7 @@ var import_FlowContextProvider = require("../FlowContextProvider");
50
50
  var import_createViewMeta = require("./createViewMeta");
51
51
  var import_PageComponent = require("./PageComponent");
52
52
  var import_usePatchElement = __toESM(require("./usePatchElement"));
53
+ var import_viewEvents = require("./viewEvents");
53
54
  var import_provider = require("../provider");
54
55
  var import_ViewScopedFlowEngine = require("../ViewScopedFlowEngine");
55
56
  var import_variablesParams = require("../utils/variablesParams");
@@ -68,6 +69,7 @@ function usePage() {
68
69
  const globalEmbedActiveRef = import_react.default.useRef(null);
69
70
  const open = /* @__PURE__ */ __name((config, flowContext) => {
70
71
  var _a, _b, _c;
72
+ const parentEngine = flowContext == null ? void 0 : flowContext.engine;
71
73
  uuid += 1;
72
74
  const pageRef = import_react.default.createRef();
73
75
  let closeFunc;
@@ -117,6 +119,7 @@ function usePage() {
117
119
  }
118
120
  const ctx = new import_flowContext.FlowContext();
119
121
  const scopedEngine = (0, import_ViewScopedFlowEngine.createViewScopedEngine)(flowContext.engine);
122
+ const openerEngine = (0, import_viewEvents.resolveOpenerEngine)(parentEngine, scopedEngine);
120
123
  ctx.defineProperty("engine", { value: scopedEngine });
121
124
  ctx.addDelegate(scopedEngine.context);
122
125
  if (inheritContext) {
@@ -129,7 +132,7 @@ function usePage() {
129
132
  inputArgs: viewInputArgs,
130
133
  preventClose: !!config.preventClose,
131
134
  destroy: /* @__PURE__ */ __name((result) => {
132
- var _a2, _b2;
135
+ var _a2, _b2, _c2, _d, _e;
133
136
  (_a2 = config.onClose) == null ? void 0 : _a2.call(config);
134
137
  resolvePromise == null ? void 0 : resolvePromise(result);
135
138
  (_b2 = pageRef.current) == null ? void 0 : _b2.destroy();
@@ -137,6 +140,12 @@ function usePage() {
137
140
  if (isGlobalEmbedContainer) {
138
141
  globalEmbedActiveRef.current = null;
139
142
  }
143
+ const isReplacing = isGlobalEmbedContainer && target instanceof HTMLElement && ((_c2 = target.dataset) == null ? void 0 : _c2[EMBED_REPLACING_DATA_KEY]) === "1";
144
+ if (!isReplacing) {
145
+ const openerEmitter = openerEngine == null ? void 0 : openerEngine.emitter;
146
+ (0, import_viewEvents.bumpViewActivatedVersion)(openerEmitter);
147
+ (_e = openerEmitter == null ? void 0 : openerEmitter.emit) == null ? void 0 : _e.call(openerEmitter, import_viewEvents.VIEW_ACTIVATED_EVENT, { type: "embed", viewUid: (_d = currentPage == null ? void 0 : currentPage.inputArgs) == null ? void 0 : _d.viewUid });
148
+ }
140
149
  scopedEngine.unlinkFromStack();
141
150
  }, "destroy"),
142
151
  update: /* @__PURE__ */ __name((newConfig) => {
@@ -0,0 +1,17 @@
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 { FlowEngine } from '../flowEngine';
10
+ export declare const VIEW_ACTIVATED_VERSION: unique symbol;
11
+ export declare const VIEW_ACTIVATED_EVENT: "view:activated";
12
+ export declare const DATA_SOURCE_DIRTY_EVENT: "dataSource:dirty";
13
+ export declare const ENGINE_SCOPE_KEY: "__NOCOBASE_ENGINE_SCOPE__";
14
+ export declare const VIEW_ENGINE_SCOPE: "view";
15
+ export declare function getEmitterViewActivatedVersion(emitter: any): number;
16
+ export declare function bumpViewActivatedVersion(emitter: any): number;
17
+ export declare function resolveOpenerEngine(parentEngine: FlowEngine, scopedEngine: FlowEngine): FlowEngine | undefined;
@@ -0,0 +1,88 @@
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 __name = (target, value) => __defProp(target, "name", { value, configurable: true });
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
18
+ };
19
+ var __copyProps = (to, from, except, desc) => {
20
+ if (from && typeof from === "object" || typeof from === "function") {
21
+ for (let key of __getOwnPropNames(from))
22
+ if (!__hasOwnProp.call(to, key) && key !== except)
23
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
+ }
25
+ return to;
26
+ };
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var viewEvents_exports = {};
29
+ __export(viewEvents_exports, {
30
+ DATA_SOURCE_DIRTY_EVENT: () => DATA_SOURCE_DIRTY_EVENT,
31
+ ENGINE_SCOPE_KEY: () => ENGINE_SCOPE_KEY,
32
+ VIEW_ACTIVATED_EVENT: () => VIEW_ACTIVATED_EVENT,
33
+ VIEW_ACTIVATED_VERSION: () => VIEW_ACTIVATED_VERSION,
34
+ VIEW_ENGINE_SCOPE: () => VIEW_ENGINE_SCOPE,
35
+ bumpViewActivatedVersion: () => bumpViewActivatedVersion,
36
+ getEmitterViewActivatedVersion: () => getEmitterViewActivatedVersion,
37
+ resolveOpenerEngine: () => resolveOpenerEngine
38
+ });
39
+ module.exports = __toCommonJS(viewEvents_exports);
40
+ const VIEW_ACTIVATED_VERSION = Symbol.for("__NOCOBASE_VIEW_ACTIVATED_VERSION__");
41
+ const VIEW_ACTIVATED_EVENT = "view:activated";
42
+ const DATA_SOURCE_DIRTY_EVENT = "dataSource:dirty";
43
+ const ENGINE_SCOPE_KEY = "__NOCOBASE_ENGINE_SCOPE__";
44
+ const VIEW_ENGINE_SCOPE = "view";
45
+ function getEmitterViewActivatedVersion(emitter) {
46
+ const raw = Reflect.get(emitter, VIEW_ACTIVATED_VERSION);
47
+ const num = typeof raw === "number" ? raw : Number(raw);
48
+ return Number.isFinite(num) && num > 0 ? num : 0;
49
+ }
50
+ __name(getEmitterViewActivatedVersion, "getEmitterViewActivatedVersion");
51
+ function bumpViewActivatedVersion(emitter) {
52
+ const current = getEmitterViewActivatedVersion(emitter);
53
+ if (!Object.isExtensible(emitter)) return current;
54
+ const next = current + 1;
55
+ Reflect.set(emitter, VIEW_ACTIVATED_VERSION, next);
56
+ return next;
57
+ }
58
+ __name(bumpViewActivatedVersion, "bumpViewActivatedVersion");
59
+ function isViewEngine(engine) {
60
+ return Reflect.get(engine, ENGINE_SCOPE_KEY) === VIEW_ENGINE_SCOPE;
61
+ }
62
+ __name(isViewEngine, "isViewEngine");
63
+ function findNearestViewEngine(engine) {
64
+ let cur = engine;
65
+ let guard = 0;
66
+ while (cur && guard++ < 50) {
67
+ if (isViewEngine(cur)) return cur;
68
+ cur = cur.previousEngine;
69
+ }
70
+ }
71
+ __name(findNearestViewEngine, "findNearestViewEngine");
72
+ function resolveOpenerEngine(parentEngine, scopedEngine) {
73
+ if (!parentEngine) return void 0;
74
+ const previousEngine = scopedEngine == null ? void 0 : scopedEngine.previousEngine;
75
+ return findNearestViewEngine(previousEngine) || parentEngine;
76
+ }
77
+ __name(resolveOpenerEngine, "resolveOpenerEngine");
78
+ // Annotate the CommonJS export names for ESM import in node:
79
+ 0 && (module.exports = {
80
+ DATA_SOURCE_DIRTY_EVENT,
81
+ ENGINE_SCOPE_KEY,
82
+ VIEW_ACTIVATED_EVENT,
83
+ VIEW_ACTIVATED_VERSION,
84
+ VIEW_ENGINE_SCOPE,
85
+ bumpViewActivatedVersion,
86
+ getEmitterViewActivatedVersion,
87
+ resolveOpenerEngine
88
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/flow-engine",
3
- "version": "2.0.0-beta.15",
3
+ "version": "2.0.0-beta.16",
4
4
  "private": false,
5
5
  "description": "A standalone flow engine for NocoBase, managing workflows, models, and actions.",
6
6
  "main": "lib/index.js",
@@ -8,8 +8,8 @@
8
8
  "dependencies": {
9
9
  "@formily/antd-v5": "1.x",
10
10
  "@formily/reactive": "2.x",
11
- "@nocobase/sdk": "2.0.0-beta.15",
12
- "@nocobase/shared": "2.0.0-beta.15",
11
+ "@nocobase/sdk": "2.0.0-beta.16",
12
+ "@nocobase/shared": "2.0.0-beta.16",
13
13
  "ahooks": "^3.7.2",
14
14
  "dayjs": "^1.11.9",
15
15
  "dompurify": "^3.0.2",
@@ -36,5 +36,5 @@
36
36
  ],
37
37
  "author": "NocoBase Team",
38
38
  "license": "AGPL-3.0",
39
- "gitHead": "3eaf3d9b571dcf4d56e28aa6ea6c24dd3896740d"
39
+ "gitHead": "d76e49352101a74331ffa3005cc5f024d7fca663"
40
40
  }