@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.
- package/lib/BlockScopedFlowEngine.js +0 -1
- package/lib/ViewScopedFlowEngine.js +3 -0
- package/lib/data-source/index.js +3 -0
- package/lib/flowEngine.d.ts +21 -0
- package/lib/flowEngine.js +38 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +13 -0
- package/lib/models/CollectionFieldModel.d.ts +1 -0
- package/lib/models/CollectionFieldModel.js +3 -2
- package/lib/resources/baseRecordResource.d.ts +5 -0
- package/lib/resources/baseRecordResource.js +24 -0
- package/lib/resources/multiRecordResource.d.ts +1 -0
- package/lib/resources/multiRecordResource.js +11 -4
- package/lib/resources/singleRecordResource.js +2 -0
- package/lib/resources/sqlResource.d.ts +1 -0
- package/lib/resources/sqlResource.js +8 -3
- package/lib/views/useDialog.js +7 -1
- package/lib/views/useDrawer.js +7 -1
- package/lib/views/usePage.js +10 -1
- package/lib/views/viewEvents.d.ts +17 -0
- package/lib/views/viewEvents.js +88 -0
- package/package.json +4 -4
- package/src/BlockScopedFlowEngine.ts +2 -5
- package/src/ViewScopedFlowEngine.ts +4 -0
- package/src/__tests__/flowEngine.dataSourceDirty.test.ts +63 -0
- package/src/data-source/index.ts +3 -0
- package/src/flowEngine.ts +41 -0
- package/src/index.ts +8 -0
- package/src/models/CollectionFieldModel.tsx +3 -1
- package/src/resources/__tests__/multiRecordResource.test.ts +44 -0
- package/src/resources/__tests__/sqlResource.test.ts +60 -0
- package/src/resources/baseRecordResource.ts +31 -0
- package/src/resources/multiRecordResource.ts +11 -4
- package/src/resources/singleRecordResource.ts +3 -0
- package/src/resources/sqlResource.ts +8 -3
- package/src/views/__tests__/useDialog.closeDestroy.test.tsx +35 -4
- package/src/views/useDialog.tsx +8 -0
- package/src/views/useDrawer.tsx +8 -0
- package/src/views/usePage.tsx +13 -0
- 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
|
// 调度器与事件总线局部化
|
package/lib/data-source/index.js
CHANGED
|
@@ -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() {
|
package/lib/flowEngine.d.ts
CHANGED
|
@@ -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
|
-
|
|
222
|
-
resolve();
|
|
229
|
+
waiters.forEach((w) => w.resolve());
|
|
223
230
|
} catch (error) {
|
|
224
231
|
this.setError(error);
|
|
225
|
-
|
|
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() {
|
|
@@ -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
|
-
|
|
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
|
});
|
package/lib/views/useDialog.js
CHANGED
|
@@ -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) => {
|
package/lib/views/useDrawer.js
CHANGED
|
@@ -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) => {
|
package/lib/views/usePage.js
CHANGED
|
@@ -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.
|
|
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.
|
|
12
|
-
"@nocobase/shared": "2.0.0-beta.
|
|
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": "
|
|
39
|
+
"gitHead": "d76e49352101a74331ffa3005cc5f024d7fca663"
|
|
40
40
|
}
|