Merge branch 'main' into next

This commit is contained in:
nocobase[bot]
2026-07-07 01:39:46 +00:00
3 changed files with 85 additions and 6 deletions
@@ -340,9 +340,9 @@ describe('ViewScopedFlowEngine', () => {
const repository = new DirtyPageRepository();
root.setModelRepository(repository);
class ParentModel extends FlowModel {}
class PageModel extends FlowModel {}
class BlockModel extends FlowModel {}
class PageModel extends FlowModel<{ parent?: FlowModel; subModels: { items: BlockModel[] } }> {}
class ParentModel extends FlowModel<{ parent?: FlowModel; subModels: { page?: PageModel } }> {}
root.registerModels({ ParentModel, PageModel, BlockModel });
const parent = root.createModel<ParentModel>({ use: 'ParentModel', uid: 'popup-action' });
@@ -357,7 +357,10 @@ describe('ViewScopedFlowEngine', () => {
items: [{ use: 'BlockModel', uid: 'stale-block' }],
},
});
const staleBlock = stalePage.findSubModel('items' as any, (item) => item.uid === 'stale-block') as FlowModel;
const staleBlock = stalePage.findSubModel('items', (item) => item.uid === 'stale-block');
if (!staleBlock) {
throw new Error('Expected stale block to be loaded');
}
parent.setSubModel('page', stalePage);
oldScoped.unlinkFromStack();
@@ -372,7 +375,7 @@ describe('ViewScopedFlowEngine', () => {
},
};
root.flowSettings.enable();
await root.flowSettings.enable();
await staleBlock.saveStepParams();
root.flowSettings.disable();
repository.findOneCalls = 0;
@@ -388,8 +391,8 @@ describe('ViewScopedFlowEngine', () => {
expect(repository.findOneCalls).toBe(1);
expect(loaded).not.toBe(stalePage);
expect((parent.subModels as any).page).toBe(loaded);
expect(loaded?.mapSubModels('items' as any, (item) => item.uid)).toEqual(['fresh-block']);
expect(parent.subModels.page).toBe(loaded);
expect(loaded?.mapSubModels('items', (item) => item.uid)).toEqual(['fresh-block']);
repository.findOneCalls = 0;
const nextRuntimeScoped = createViewScopedEngine(root);
@@ -405,6 +408,69 @@ describe('ViewScopedFlowEngine', () => {
expect(loadedAgain?.uid).toBe('popup-page');
});
it('reloads a page after it was loaded in flow settings mode', async () => {
const root = new FlowEngine();
const repository = new DirtyPageRepository();
root.setModelRepository(repository);
class ParentModel extends FlowModel {}
class PageModel extends FlowModel {}
class BlockModel extends FlowModel {}
root.registerModels({ ParentModel, PageModel, BlockModel });
const parent = root.createModel<ParentModel>({ use: 'ParentModel', uid: 'settings-popup-action' });
repository.data = {
use: 'PageModel',
uid: 'settings-popup-page',
parentId: parent.uid,
subKey: 'page',
subType: 'object',
subModels: {
items: [{ use: 'BlockModel', uid: 'stale-settings-block' }],
},
};
await root.flowSettings.enable();
const designScoped = createViewScopedEngine(root);
const designLoaded = await designScoped.loadOrCreateModel<PageModel>({
async: true,
parentId: parent.uid,
subKey: 'page',
subType: 'object',
use: 'PageModel',
});
expect(repository.findOneCalls).toBe(1);
expect(designLoaded?.mapSubModels('items', (item) => item.uid)).toEqual(['stale-settings-block']);
designScoped.unlinkFromStack();
repository.data = {
use: 'PageModel',
uid: 'settings-popup-page',
parentId: parent.uid,
subKey: 'page',
subType: 'object',
subModels: {
items: [{ use: 'BlockModel', uid: 'fresh-settings-block' }],
},
};
root.flowSettings.disable();
repository.findOneCalls = 0;
const runtimeScoped = createViewScopedEngine(root);
const runtimeLoaded = await runtimeScoped.loadOrCreateModel<PageModel>({
async: true,
parentId: parent.uid,
subKey: 'page',
subType: 'object',
use: 'PageModel',
});
expect(repository.findOneCalls).toBe(1);
expect(runtimeLoaded).not.toBe(designLoaded);
expect(parent.subModels.page).toBe(runtimeLoaded);
expect(runtimeLoaded?.mapSubModels('items', (item) => item.uid)).toEqual(['fresh-settings-block']);
});
it('does not bypass loaded page cache after a non-config save', async () => {
const root = new FlowEngine();
const repository = new DirtyPageRepository();
@@ -1343,6 +1343,9 @@ export class FlowEngine {
if (!this.ensureModelRepository()) return;
const refresh = !!options?.refresh;
const bypassLoadedPageCache = this._loadedPageCache.shouldBypass(options, () => this.context.flowSettingsEnabled);
if (this.context.flowSettingsEnabled) {
this._loadedPageCache.markDirtyForOptions(options);
}
if (!refresh && !bypassLoadedPageCache) {
const model = this.findModelByParentId(options.parentId, options.subKey);
if (model) {
@@ -1412,6 +1415,9 @@ export class FlowEngine {
if (!this.ensureModelRepository()) return;
const { uid, parentId, subKey } = options;
const bypassLoadedPageCache = this._loadedPageCache.shouldBypass(options, () => this.context.flowSettingsEnabled);
if (this.context.flowSettingsEnabled) {
this._loadedPageCache.markDirtyForOptions(options);
}
if (uid && !bypassLoadedPageCache && this._modelInstances.has(uid)) {
return this._modelInstances.get(uid) as T;
}
@@ -123,6 +123,13 @@ export const createLoadedPageCache = () => {
}
},
markDirtyForOptions(options?: LoadedPageOptions): void {
const key = getLoadedPageKey(options);
if (key) {
dirtyKeys.add(key);
}
},
shouldBypass(options?: LoadedPageOptions, isFlowSettingsEnabled?: () => boolean): boolean {
const key = getLoadedPageKey(options);
if (!key || !dirtyKeys.has(key)) {