diff --git a/packages/core/client/src/schema-component/antd/page/__tests__/usePopupContextInActionOrAssociationField.test.ts b/packages/core/client/src/schema-component/antd/page/__tests__/usePopupContextInActionOrAssociationField.test.ts index f9fa14221d..8091fe6fcf 100644 --- a/packages/core/client/src/schema-component/antd/page/__tests__/usePopupContextInActionOrAssociationField.test.ts +++ b/packages/core/client/src/schema-component/antd/page/__tests__/usePopupContextInActionOrAssociationField.test.ts @@ -54,12 +54,11 @@ describe('usePopupContextInActionOrAssociationField', () => { dataSource: 'dataSource', collection: 'collection', association: 'association', - sourceId: 'sourceId', }; result.current.updatePopupContext(context); - expect(dnMock.emit).toHaveBeenCalledWith('patch', { + expect(dnMock.emit).toHaveBeenCalledWith('initializeActionContext', { schema: { 'x-uid': fieldSchemaMock['x-uid'], 'x-action-context': context, @@ -84,9 +83,8 @@ describe('usePopupContextInActionOrAssociationField', () => { result.current.updatePopupContext({ ...context, collection: undefined, - sourceId: null, }); - expect(dnMock.emit).toHaveBeenCalledWith('patch', { + expect(dnMock.emit).toHaveBeenCalledWith('initializeActionContext', { schema: { 'x-uid': fieldSchemaMock['x-uid'], 'x-action-context': { diff --git a/packages/core/client/src/schema-component/antd/page/usePopupContextInActionOrAssociationField.ts b/packages/core/client/src/schema-component/antd/page/usePopupContextInActionOrAssociationField.ts index 2c30024fd8..028a8f4e13 100644 --- a/packages/core/client/src/schema-component/antd/page/usePopupContextInActionOrAssociationField.ts +++ b/packages/core/client/src/schema-component/antd/page/usePopupContextInActionOrAssociationField.ts @@ -39,7 +39,7 @@ export const usePopupContextInActionOrAssociationField = () => { customSchema[CONTEXT_SCHEMA_KEY] = context; - return dn.emit('patch', { + return dn.emit('initializeActionContext', { schema: { 'x-uid': customSchema['x-uid'], [CONTEXT_SCHEMA_KEY]: context, diff --git a/packages/core/client/src/schema-component/hooks/useDesignable.tsx b/packages/core/client/src/schema-component/hooks/useDesignable.tsx index 1b8b952926..c8e3e2efc2 100644 --- a/packages/core/client/src/schema-component/hooks/useDesignable.tsx +++ b/packages/core/client/src/schema-component/hooks/useDesignable.tsx @@ -217,6 +217,19 @@ export class Designable { }); message.success(t('Saved successfully'), 0.2); }); + this.on('initializeActionContext', async ({ schema }) => { + this.refresh(); + if (!schema?.['x-uid']) { + return; + } + await api.request({ + url: `/uiSchemas:initializeActionContext`, + method: 'post', + data: { + ...schema, + }, + }); + }); this.on('batchPatch', async ({ schemas }) => { this.refresh(); await api.request({ @@ -267,14 +280,17 @@ export class Designable { generateUid(schema); } - on(name: 'insertAdjacent' | 'remove' | 'error' | 'patch' | 'batchPatch', listener: any) { + on(name: 'insertAdjacent' | 'remove' | 'error' | 'patch' | 'batchPatch' | 'initializeActionContext', listener: any) { if (!this.events[name]) { this.events[name] = []; } this.events[name].push(listener); } - async emit(name: 'insertAdjacent' | 'remove' | 'error' | 'patch' | 'batchPatch', ...args) { + async emit( + name: 'insertAdjacent' | 'remove' | 'error' | 'patch' | 'batchPatch' | 'initializeActionContext', + ...args + ) { if (!this.events[name]) { return; } diff --git a/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/__tests__/action.test.ts b/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/__tests__/action.test.ts index 9b6f34b37b..19bba0d699 100644 --- a/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/__tests__/action.test.ts +++ b/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/__tests__/action.test.ts @@ -248,6 +248,65 @@ describe('action test', () => { expect(data.properties.b['properties']['c']['title']).toEqual('c-title'); }); + test('initializeActionContext', async () => { + await app + .agent() + .resource('uiSchemas') + .insert({ + values: { + 'x-uid': 'n1', + name: 'a', + type: 'object', + properties: { + b: { + 'x-uid': 'n2', + type: 'object', + properties: { + c: { 'x-uid': 'n3' }, + }, + }, + d: { 'x-uid': 'n4' }, + }, + }, + }); + + let response = await app + .agent() + .resource('uiSchemas') + .initializeActionContext({ + values: { + 'x-uid': 'n1', + 'x-action-context': { + field1: 'field1', + field2: 'field2', + }, + properties: { + b: { + properties: { + c: { + title: 'c-title', + }, + }, + }, + }, + }, + }); + + expect(response.statusCode).toEqual(200); + response = await app.agent().resource('uiSchemas').getJsonSchema({ + resourceIndex: 'n1', + }); + + const { data } = response.body; + + // only update the x-action-context + expect(data.properties.b['properties']['c']['title']).toBe(undefined); + expect(data['x-action-context']).toEqual({ + field1: 'field1', + field2: 'field2', + }); + }); + test('insert adjacent', async () => { await app .agent() diff --git a/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/__tests__/ui-schema-repository.test.ts b/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/__tests__/ui-schema-repository.test.ts index b717398330..dc3947bf15 100644 --- a/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/__tests__/ui-schema-repository.test.ts +++ b/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/__tests__/ui-schema-repository.test.ts @@ -952,6 +952,96 @@ describe('ui_schema repository', () => { }); }); + describe('initializeActionContext', function () { + let rootNode; + let rootUid: string; + let oldTree; + + beforeEach(async () => { + const root = { + type: 'object', + title: 'title', + name: 'root', + properties: { + a1: { + type: 'string', + title: 'A1', + 'x-component': 'Input', + }, + b1: { + type: 'string', + title: 'B1', + properties: { + c1: { + type: 'string', + title: 'C1', + }, + d1: { + type: 'string', + title: 'D1', + }, + }, + }, + }, + }; + + await repository.insert(root); + + rootNode = await repository.findOne({ + filter: { + name: 'root', + }, + }); + + rootUid = rootNode.get('x-uid') as string; + + oldTree = await repository.getJsonSchema(rootUid); + }); + + it('should update root ui schema and only have x-action-context to be updated', async () => { + await repository.initializeActionContext({ + 'x-uid': rootUid, + title: 'test-title', + ['x-action-context']: { + field1: 'field1', + field2: 'field2', + }, + properties: { + a1: { + type: 'string', + title: 'new a1 title', + 'x-component': 'Input', + }, + }, + }); + + const newTree = await repository.getJsonSchema(rootUid); + expect(newTree).toEqual({ + ...oldTree, + ['x-action-context']: { + field1: 'field1', + field2: 'field2', + }, + }); + + // will not updated when x-action-context existed + await repository.initializeActionContext({ + 'x-uid': rootUid, + ['x-action-context']: { + field3: 'field3', + field4: 'field4', + }, + }); + expect(newTree).toEqual({ + ...oldTree, + ['x-action-context']: { + field1: 'field1', + field2: 'field2', + }, + }); + }); + }); + it('should insertInner with removeParent', async () => { const schema = { 'x-uid': 'A', diff --git a/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/actions/ui-schema-action.ts b/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/actions/ui-schema-action.ts index 76e13d8eb0..98e367726b 100644 --- a/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/actions/ui-schema-action.ts +++ b/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/actions/ui-schema-action.ts @@ -67,6 +67,7 @@ export const uiSchemaActions = { insertNewSchema: callRepositoryMethod('insertNewSchema', 'values'), remove: callRepositoryMethod('remove', 'resourceIndex'), patch: callRepositoryMethod('patch', 'values'), + initializeActionContext: callRepositoryMethod('initializeActionContext', 'values'), batchPatch: callRepositoryMethod('batchPatch', 'values'), clearAncestor: callRepositoryMethod('clearAncestor', 'resourceIndex'), diff --git a/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/repository.ts b/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/repository.ts index 71e2a8a1ba..f13461d128 100644 --- a/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/repository.ts +++ b/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/repository.ts @@ -331,6 +331,28 @@ export class UiSchemaRepository extends Repository { await traverSchemaTree(newSchema); } + @transaction() + async initializeActionContext(newSchema: any, options: any = {}) { + if (!newSchema['x-uid'] || !newSchema['x-action-context']) { + return; + } + + const { transaction } = options; + + const nodeModel = await this.findOne({ + filter: { + 'x-uid': newSchema['x-uid'], + }, + transaction, + }); + + if (!lodash.isEmpty(nodeModel?.get('schema')['x-action-context'])) { + return; + } + + return this.patch(lodash.pick(newSchema, ['x-uid', 'x-action-context']), options); + } + @transaction() async batchPatch(schemas: any[], options?) { const { transaction } = options; diff --git a/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/server.ts b/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/server.ts index b55743c6db..ce84e72ab2 100644 --- a/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/server.ts +++ b/packages/plugins/@nocobase/plugin-ui-schema-storage/src/server/server.ts @@ -80,7 +80,11 @@ export class PluginUISchemaStorageServer extends Plugin { actions: uiSchemaActions, }); - this.app.acl.allow('uiSchemas', ['getProperties', 'getJsonSchema', 'getParentJsonSchema'], 'loggedIn'); + this.app.acl.allow( + 'uiSchemas', + ['getProperties', 'getJsonSchema', 'getParentJsonSchema', 'initializeActionContext'], + 'loggedIn', + ); this.app.acl.allow('uiSchemaTemplates', ['get', 'list'], 'loggedIn'); }