From 06980fd87dc92475bb0905020949847593ed9476 Mon Sep 17 00:00:00 2001 From: chenos Date: Wed, 27 Mar 2024 20:15:13 +0800 Subject: [PATCH 01/26] fix: improve app manager (#3841) --- .../src/client/AppManager.tsx | 2 +- .../src/client/MultiAppManagerProvider.tsx | 2 +- .../client/settings/schemas/applications.ts | 28 +++++++++++-------- .../src/locale/zh-CN.json | 5 +++- .../src/swagger/index.ts | 10 +++---- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppManager.tsx b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppManager.tsx index be7ae97ed..e614705c3 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppManager.tsx +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppManager.tsx @@ -7,7 +7,7 @@ import { usePluginUtils } from './utils'; const useLink = () => { const record = useRecord(); const app = useApp(); - if (record.options?.standaloneDeployment && record.cname) { + if (record.cname) { return `//${record.cname}`; } return app.getRouteUrl(`/apps/${record.name}/admin/`); diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/MultiAppManagerProvider.tsx b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/MultiAppManagerProvider.tsx index d04707df4..162788b84 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/MultiAppManagerProvider.tsx +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/MultiAppManagerProvider.tsx @@ -24,7 +24,7 @@ const MultiAppManager = () => { const items = [ ...(data?.data || []).map((app) => { let link = instance.getRouteUrl(`/apps/${app.name}/admin/`); - if (app.options?.standaloneDeployment && app.cname) { + if (app.cname) { link = `//${app.cname}`; } return { diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/settings/schemas/applications.ts b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/settings/schemas/applications.ts index 93c6bf5b8..d79625abd 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/settings/schemas/applications.ts +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/settings/schemas/applications.ts @@ -2,6 +2,7 @@ import { ISchema } from '@formily/react'; import { uid } from '@formily/shared'; import { SchemaComponentOptions, + tval, useActionContext, useRecord, useRequest, @@ -112,25 +113,30 @@ export const formSchema: ISchema = { 'x-decorator': 'FormItem', 'x-disabled': '{{ !createOnly }}', }, - pinned: { - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - }, - 'options.standaloneDeployment': { - 'x-component': 'Checkbox', - 'x-decorator': 'FormItem', - 'x-content': i18nText('Standalone deployment'), - }, + // 'options.standaloneDeployment': { + // 'x-component': 'Checkbox', + // 'x-decorator': 'FormItem', + // 'x-content': i18nText('Standalone deployment'), + // }, 'options.autoStart': { - 'x-component': 'Checkbox', + title: tval('Start mode', { ns: '@nocobase/plugin-multi-app-manager' }), + 'x-component': 'Radio.Group', 'x-decorator': 'FormItem', - 'x-content': i18nText('Auto start'), + default: false, + enum: [ + { label: tval('Start on first visit', { ns: '@nocobase/plugin-multi-app-manager' }), value: false }, + { label: tval('Start with main application', { ns: '@nocobase/plugin-multi-app-manager' }), value: true }, + ], }, cname: { title: i18nText('Custom domain'), 'x-component': 'Input', 'x-decorator': 'FormItem', }, + pinned: { + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + }, }, }; diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/locale/zh-CN.json b/packages/plugins/@nocobase/plugin-multi-app-manager/src/locale/zh-CN.json index 1b81f70ff..7ca07d595 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/locale/zh-CN.json +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/locale/zh-CN.json @@ -7,5 +7,8 @@ "Custom domain": "自定义域名", "Manage applications": "管理应用", "Standalone deployment": "独立部署", - "Auto start": "自动启动" + "Auto start": "自动启动", + "Start mode": "启动方式", + "Start on first visit": "首次访问时启动", + "Start with main application": "随主应用一同启动" } diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/swagger/index.ts b/packages/plugins/@nocobase/plugin-multi-app-manager/src/swagger/index.ts index 3ac0bc01c..c48a388a2 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/swagger/index.ts +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/swagger/index.ts @@ -166,11 +166,11 @@ export default { options: { type: 'object', properties: { - standaloneDeployment: { - type: 'boolean', - example: true, - description: '是否为独立部署的子应用', - }, + // standaloneDeployment: { + // type: 'boolean', + // example: true, + // description: '是否为独立部署的子应用', + // }, autoStart: { type: 'boolean', example: true, From d6f38495a7ab8497f30af3725c57dbdc8eaa5559 Mon Sep 17 00:00:00 2001 From: Zeke Zhang <958414905@qq.com> Date: Wed, 27 Mar 2024 20:52:29 +0800 Subject: [PATCH 02/26] refactor(DataBlock): filter form (#3785) * refactor: migrate to modules * refactor: add useFilterFormBlockProps * refactor: add useFilterFormBlockDecoratorProps hook * chore: avoid error * refactor: use x-use-component-props instead of useProps * chore: fix unit test * chore: fix build --- .../BlockSchemaComponentProvider.tsx | 6 + .../FilterFormBlockProvider.tsx | 5 +- .../form/FilterFormBlockInitializer.tsx | 10 +- .../createFilterFormBlockSchema.test.ts | 106 ++++++++++++++++++ .../form/createFilterFormBlockSchema.ts | 57 ++++++++++ .../hooks/useFilterFormBlockDecoratorProps.ts | 1 + .../form/hooks/useFilterFormBlockProps.ts | 5 + .../client/src/schema-initializer/index.ts | 1 - .../client/src/schema-initializer/utils.ts | 65 ----------- 9 files changed, 182 insertions(+), 74 deletions(-) create mode 100644 packages/core/client/src/modules/blocks/filter-blocks/form/__tests__/createFilterFormBlockSchema.test.ts create mode 100644 packages/core/client/src/modules/blocks/filter-blocks/form/createFilterFormBlockSchema.ts create mode 100644 packages/core/client/src/modules/blocks/filter-blocks/form/hooks/useFilterFormBlockDecoratorProps.ts create mode 100644 packages/core/client/src/modules/blocks/filter-blocks/form/hooks/useFilterFormBlockProps.ts diff --git a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx index e5b1b8c69..04e53e396 100644 --- a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx +++ b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx @@ -24,6 +24,8 @@ import { useTableBlockDecoratorProps } from '../modules/blocks/data-blocks/table import { useListBlockDecoratorProps } from '../modules/blocks/data-blocks/list/hooks/useListBlockDecoratorProps'; import { useTableSelectorDecoratorProps } from '../modules/blocks/data-blocks/table-selector/hooks/useTableSelectorDecoratorProps'; import { useCollapseBlockDecoratorProps } from '../modules/blocks/filter-blocks/collapse/hooks/useCollapseBlockDecoratorProps'; +import { useFilterFormBlockProps } from '../modules/blocks/filter-blocks/form/hooks/useFilterFormBlockProps'; +import { useFilterFormBlockDecoratorProps } from '../modules/blocks/filter-blocks/form/hooks/useFilterFormBlockDecoratorProps'; // TODO: delete this, replaced by `BlockSchemaComponentPlugin` export const BlockSchemaComponentProvider: React.FC = (props) => { @@ -58,6 +60,8 @@ export const BlockSchemaComponentProvider: React.FC = (props) => { useListBlockDecoratorProps, useTableSelectorDecoratorProps, useCollapseBlockDecoratorProps, + useFilterFormBlockProps, + useFilterFormBlockDecoratorProps, }} > {props.children} @@ -109,6 +113,8 @@ export class BlockSchemaComponentPlugin extends Plugin { useListBlockDecoratorProps, useTableSelectorDecoratorProps, useCollapseBlockDecoratorProps, + useFilterFormBlockProps, + useFilterFormBlockDecoratorProps, }); } } diff --git a/packages/core/client/src/block-provider/FilterFormBlockProvider.tsx b/packages/core/client/src/block-provider/FilterFormBlockProvider.tsx index 850c04e7a..b54c9433a 100644 --- a/packages/core/client/src/block-provider/FilterFormBlockProvider.tsx +++ b/packages/core/client/src/block-provider/FilterFormBlockProvider.tsx @@ -2,8 +2,9 @@ import React from 'react'; import { DatePickerProvider } from '../schema-component'; import { DefaultValueProvider } from '../schema-settings'; import { FormBlockProvider } from './FormBlockProvider'; +import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps'; -export const FilterFormBlockProvider = (props) => { +export const FilterFormBlockProvider = withDynamicSchemaProps((props) => { return ( false}> @@ -11,4 +12,4 @@ export const FilterFormBlockProvider = (props) => { ); -}; +}); diff --git a/packages/core/client/src/modules/blocks/filter-blocks/form/FilterFormBlockInitializer.tsx b/packages/core/client/src/modules/blocks/filter-blocks/form/FilterFormBlockInitializer.tsx index 1842396f5..3263e610e 100644 --- a/packages/core/client/src/modules/blocks/filter-blocks/form/FilterFormBlockInitializer.tsx +++ b/packages/core/client/src/modules/blocks/filter-blocks/form/FilterFormBlockInitializer.tsx @@ -1,7 +1,7 @@ import { FormOutlined } from '@ant-design/icons'; import React from 'react'; import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; -import { createFilterFormBlockSchema } from '../../../../schema-initializer/utils'; +import { createFilterFormBlockSchema } from './createFilterFormBlockSchema'; import { FilterBlockInitializer } from '../../../../schema-initializer/items/FilterBlockInitializer'; import { Collection, CollectionFieldOptions } from '../../../../data-source'; @@ -25,10 +25,9 @@ export const FilterFormBlockInitializer = ({ componentType={'FilterFormItem'} templateWrap={(templateSchema, { item }) => { const s = createFilterFormBlockSchema({ - template: templateSchema, + templateSchema: templateSchema, dataSource: item.dataSource, - collection: item.name || item.collectionName, - settings: 'blockSettings:filterForm', + collectionName: item.name || item.collectionName, }); if (item.template && item.mode === 'reference') { s['x-template-key'] = item.template.key; @@ -38,9 +37,8 @@ export const FilterFormBlockInitializer = ({ onCreateBlockSchema={({ item }) => { return insert( createFilterFormBlockSchema({ - collection: item.collectionName || item.name, + collectionName: item.collectionName || item.name, dataSource: item.dataSource, - settings: 'blockSettings:filterForm', }), ); }} diff --git a/packages/core/client/src/modules/blocks/filter-blocks/form/__tests__/createFilterFormBlockSchema.test.ts b/packages/core/client/src/modules/blocks/filter-blocks/form/__tests__/createFilterFormBlockSchema.test.ts new file mode 100644 index 000000000..4fc5e833d --- /dev/null +++ b/packages/core/client/src/modules/blocks/filter-blocks/form/__tests__/createFilterFormBlockSchema.test.ts @@ -0,0 +1,106 @@ +import { createFilterFormBlockSchema } from '../createFilterFormBlockSchema'; + +vi.mock('@formily/shared', () => { + return { + uid: () => 'mocked-uid', + }; +}); + +describe('createFilterFormBlockSchema', () => { + test('should return the correct schema', () => { + const schema = createFilterFormBlockSchema({ + collectionName: 'myCollection', + dataSource: 'myDataSource', + templateSchema: { type: 'string' }, + }); + + expect(schema).toMatchInlineSnapshot(` + { + "properties": { + "mocked-uid": { + "properties": { + "grid": { + "type": "string", + }, + "mocked-uid": { + "type": "void", + "x-component": "ActionBar", + "x-component-props": { + "layout": "one-column", + "style": { + "float": "right", + }, + }, + "x-initializer": "filterForm:configureActions", + }, + }, + "type": "void", + "x-component": "FormV2", + "x-use-component-props": "useFilterFormBlockProps", + }, + }, + "type": "void", + "x-component": "CardItem", + "x-decorator": "FilterFormBlockProvider", + "x-decorator-props": { + "collection": "myCollection", + "dataSource": "myDataSource", + }, + "x-filter-operators": {}, + "x-filter-targets": [], + "x-settings": "blockSettings:filterForm", + "x-toolbar": "BlockSchemaToolbar", + "x-use-decorator-props": "useFilterFormBlockDecoratorProps", + } + `); + }); + + test('should return the correct schema without templateSchema', () => { + const schema = createFilterFormBlockSchema({ + collectionName: 'myCollection', + dataSource: 'myDataSource', + }); + + expect(schema).toMatchInlineSnapshot(` + { + "properties": { + "mocked-uid": { + "properties": { + "grid": { + "type": "void", + "x-component": "Grid", + "x-initializer": "filterForm:configureFields", + }, + "mocked-uid": { + "type": "void", + "x-component": "ActionBar", + "x-component-props": { + "layout": "one-column", + "style": { + "float": "right", + }, + }, + "x-initializer": "filterForm:configureActions", + }, + }, + "type": "void", + "x-component": "FormV2", + "x-use-component-props": "useFilterFormBlockProps", + }, + }, + "type": "void", + "x-component": "CardItem", + "x-decorator": "FilterFormBlockProvider", + "x-decorator-props": { + "collection": "myCollection", + "dataSource": "myDataSource", + }, + "x-filter-operators": {}, + "x-filter-targets": [], + "x-settings": "blockSettings:filterForm", + "x-toolbar": "BlockSchemaToolbar", + "x-use-decorator-props": "useFilterFormBlockDecoratorProps", + } + `); + }); +}); diff --git a/packages/core/client/src/modules/blocks/filter-blocks/form/createFilterFormBlockSchema.ts b/packages/core/client/src/modules/blocks/filter-blocks/form/createFilterFormBlockSchema.ts new file mode 100644 index 000000000..85ab058de --- /dev/null +++ b/packages/core/client/src/modules/blocks/filter-blocks/form/createFilterFormBlockSchema.ts @@ -0,0 +1,57 @@ +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; + +export const createFilterFormBlockSchema = (options: { + collectionName: string; + dataSource: string; + templateSchema?: ISchema; +}) => { + const { collectionName, dataSource, templateSchema } = options; + + if (!collectionName || !dataSource) { + throw new Error('collectionName and dataSource are required'); + } + + const schema: ISchema = { + type: 'void', + 'x-decorator': 'FilterFormBlockProvider', + 'x-use-decorator-props': 'useFilterFormBlockDecoratorProps', + 'x-decorator-props': { + dataSource, + collection: collectionName, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:filterForm', + 'x-component': 'CardItem', + // 保存当前筛选区块所能过滤的数据区块 + 'x-filter-targets': [], + // 用于存储用户设置的每个字段的运算符,目前仅筛选表单区块支持自定义 + 'x-filter-operators': {}, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'FormV2', + 'x-use-component-props': 'useFilterFormBlockProps', + properties: { + grid: templateSchema || { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'filterForm:configureFields', + }, + [uid()]: { + type: 'void', + 'x-initializer': 'filterForm:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + float: 'right', + }, + }, + }, + }, + }, + }, + }; + return schema; +}; diff --git a/packages/core/client/src/modules/blocks/filter-blocks/form/hooks/useFilterFormBlockDecoratorProps.ts b/packages/core/client/src/modules/blocks/filter-blocks/form/hooks/useFilterFormBlockDecoratorProps.ts new file mode 100644 index 000000000..37f6d0fc8 --- /dev/null +++ b/packages/core/client/src/modules/blocks/filter-blocks/form/hooks/useFilterFormBlockDecoratorProps.ts @@ -0,0 +1 @@ +export function useFilterFormBlockDecoratorProps() {} diff --git a/packages/core/client/src/modules/blocks/filter-blocks/form/hooks/useFilterFormBlockProps.ts b/packages/core/client/src/modules/blocks/filter-blocks/form/hooks/useFilterFormBlockProps.ts new file mode 100644 index 000000000..76ad7db2b --- /dev/null +++ b/packages/core/client/src/modules/blocks/filter-blocks/form/hooks/useFilterFormBlockProps.ts @@ -0,0 +1,5 @@ +import { useFormBlockProps } from '../../../../../block-provider/FormBlockProvider'; + +export function useFilterFormBlockProps() { + return useFormBlockProps(); +} diff --git a/packages/core/client/src/schema-initializer/index.ts b/packages/core/client/src/schema-initializer/index.ts index 648cdb45f..7af974161 100644 --- a/packages/core/client/src/schema-initializer/index.ts +++ b/packages/core/client/src/schema-initializer/index.ts @@ -123,7 +123,6 @@ export * from './buttons'; export * from './items'; export { createDetailsBlockSchema, - createFilterFormBlockSchema, createFormBlockSchema, createReadPrettyFormBlockSchema, createTableBlockSchema, diff --git a/packages/core/client/src/schema-initializer/utils.ts b/packages/core/client/src/schema-initializer/utils.ts index cd1998681..14c26667c 100644 --- a/packages/core/client/src/schema-initializer/utils.ts +++ b/packages/core/client/src/schema-initializer/utils.ts @@ -1154,71 +1154,6 @@ export const createFormBlockSchema = (options: { return schema; }; -export const createFilterFormBlockSchema = (options) => { - const { - formItemInitializers = 'filterForm:configureFields', - actionInitializers = 'filterForm:configureActions', - collection, - resource, - association, - dataSource, - action, - template, - settings, - ...others - } = options; - const resourceName = resource || association || collection; - const schema: ISchema = { - type: 'void', - 'x-decorator': 'FilterFormBlockProvider', - 'x-decorator-props': { - ...others, - action, - resource: resourceName, - dataSource, - collection, - association, - }, - 'x-toolbar': 'BlockSchemaToolbar', - ...(settings ? { 'x-settings': settings } : { 'x-designer': 'FormV2.FilterDesigner' }), - 'x-component': 'CardItem', - // 保存当前筛选区块所能过滤的数据区块 - 'x-filter-targets': [], - // 用于存储用户设置的每个字段的运算符,目前仅筛选表单区块支持自定义 - 'x-filter-operators': {}, - properties: { - [uid()]: { - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - grid: template || { - type: 'void', - 'x-component': 'Grid', - 'x-initializer': formItemInitializers, - properties: {}, - }, - [uid()]: { - type: 'void', - 'x-initializer': actionInitializers, - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - float: 'right', - }, - }, - properties: {}, - }, - }, - }, - }, - }; - return schema; -}; - /** * @deprecated * 已弃用,可以使用 createDetailsBlockSchema 替换 From d9325461941534d9bd29e7121518279efc654d27 Mon Sep 17 00:00:00 2001 From: Zeke Zhang <958414905@qq.com> Date: Wed, 27 Mar 2024 20:56:30 +0800 Subject: [PATCH 03/26] refactor(DataBlock): grid card block (#3781) * refactor: migrate createGridCardBlockSchema to modules * refactor: add grid-card block hooks and decorator props * refactor: should not get collection on getting association in UISchema * refactor: use x-use-component-props instead of useProps * chore: fix build --- .../BlockSchemaComponentProvider.tsx | 3 + .../grid-card/GridCardBlockInitializer.tsx | 5 +- .../createGridCardBlockSchema.test.ts | 158 ++++++++++++++++++ .../grid-card/createGridCardBlockSchema.ts | 81 +++++++++ .../hooks/useGridCardBlockDecoratorProps.ts | 18 ++ .../grid-card/hooks/useGridCardBlockParams.ts | 17 ++ .../antd/block-item/BlockItem.tsx | 7 +- .../antd/grid-card/GridCard.Decorator.tsx | 38 +++-- .../antd/grid-card/GridCard.Item.tsx | 5 +- .../antd/grid-card/GridCard.tsx | 5 +- ...ordAssociationGridCardBlockInitializer.tsx | 8 +- .../client/src/schema-initializer/utils.ts | 91 ---------- 12 files changed, 317 insertions(+), 119 deletions(-) create mode 100644 packages/core/client/src/modules/blocks/data-blocks/grid-card/__tests__/createGridCardBlockSchema.test.ts create mode 100644 packages/core/client/src/modules/blocks/data-blocks/grid-card/createGridCardBlockSchema.ts create mode 100644 packages/core/client/src/modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockDecoratorProps.ts create mode 100644 packages/core/client/src/modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockParams.ts diff --git a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx index 04e53e396..444abb570 100644 --- a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx +++ b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx @@ -26,6 +26,7 @@ import { useTableSelectorDecoratorProps } from '../modules/blocks/data-blocks/ta import { useCollapseBlockDecoratorProps } from '../modules/blocks/filter-blocks/collapse/hooks/useCollapseBlockDecoratorProps'; import { useFilterFormBlockProps } from '../modules/blocks/filter-blocks/form/hooks/useFilterFormBlockProps'; import { useFilterFormBlockDecoratorProps } from '../modules/blocks/filter-blocks/form/hooks/useFilterFormBlockDecoratorProps'; +import { useGridCardBlockDecoratorProps } from '../modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockDecoratorProps'; // TODO: delete this, replaced by `BlockSchemaComponentPlugin` export const BlockSchemaComponentProvider: React.FC = (props) => { @@ -62,6 +63,7 @@ export const BlockSchemaComponentProvider: React.FC = (props) => { useCollapseBlockDecoratorProps, useFilterFormBlockProps, useFilterFormBlockDecoratorProps, + useGridCardBlockDecoratorProps, }} > {props.children} @@ -115,6 +117,7 @@ export class BlockSchemaComponentPlugin extends Plugin { useCollapseBlockDecoratorProps, useFilterFormBlockProps, useFilterFormBlockDecoratorProps, + useGridCardBlockDecoratorProps, }); } } diff --git a/packages/core/client/src/modules/blocks/data-blocks/grid-card/GridCardBlockInitializer.tsx b/packages/core/client/src/modules/blocks/data-blocks/grid-card/GridCardBlockInitializer.tsx index c483b9710..c0d4c2b9e 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/grid-card/GridCardBlockInitializer.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/grid-card/GridCardBlockInitializer.tsx @@ -2,7 +2,7 @@ import { OrderedListOutlined } from '@ant-design/icons'; import React from 'react'; import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; import { useCollectionManager_deprecated } from '../../../../collection-manager'; -import { createGridCardBlockSchema } from '../../../../schema-initializer/utils'; +import { createGridCardBlockSchema } from './createGridCardBlockSchema'; import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer'; import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection'; @@ -48,10 +48,9 @@ export const GridCardBlockInitializer = ({ const collection = getCollection(item.name, item.dataSource); const schema = createGridCardBlockSchema({ - collection: item.name, + collectionName: item.name, dataSource: item.dataSource, rowKey: collection.filterTargetKey || 'id', - settings: 'blockSettings:gridCard', }); insert(schema); }} diff --git a/packages/core/client/src/modules/blocks/data-blocks/grid-card/__tests__/createGridCardBlockSchema.test.ts b/packages/core/client/src/modules/blocks/data-blocks/grid-card/__tests__/createGridCardBlockSchema.test.ts new file mode 100644 index 000000000..11164efdc --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/grid-card/__tests__/createGridCardBlockSchema.test.ts @@ -0,0 +1,158 @@ +import { createGridCardBlockSchema } from '../createGridCardBlockSchema'; + +describe('createGridCardBlockSchema', () => { + test('should return the correct schema', () => { + const options = { + collectionName: 'testCollection', + dataSource: 'testDataSource', + association: 'testAssociation', + templateSchema: { type: 'string' }, + rowKey: 'testRowKey', + }; + + const schema = createGridCardBlockSchema(options); + + expect(schema).toMatchInlineSnapshot(` + { + "properties": { + "actionBar": { + "type": "void", + "x-component": "ActionBar", + "x-component-props": { + "style": { + "marginBottom": "var(--nb-spacing)", + }, + }, + "x-initializer": "gridCard:configureActions", + }, + "list": { + "properties": { + "item": { + "properties": { + "actionBar": { + "type": "void", + "x-align": "left", + "x-component": "ActionBar", + "x-component-props": { + "layout": "one-column", + }, + "x-initializer": "gridCard:configureItemActions", + "x-use-component-props": "useGridCardActionBarProps", + }, + "grid": { + "type": "string", + }, + }, + "type": "object", + "x-component": "GridCard.Item", + "x-read-pretty": true, + "x-use-component-props": "useGridCardItemProps", + }, + }, + "type": "array", + "x-component": "GridCard", + "x-use-component-props": "useGridCardBlockProps", + }, + }, + "type": "void", + "x-acl-action": "testAssociation:view", + "x-component": "BlockItem", + "x-decorator": "GridCard.Decorator", + "x-decorator-props": { + "action": "list", + "association": "testAssociation", + "collection": "testCollection", + "dataSource": "testDataSource", + "params": { + "pageSize": 12, + }, + "readPretty": true, + "rowKey": "testRowKey", + "runWhenParamsChanged": true, + }, + "x-settings": "blockSettings:gridCard", + "x-toolbar": "BlockSchemaToolbar", + "x-use-component-props": "useGridCardBlockItemProps", + "x-use-decorator-props": "useGridCardBlockDecoratorProps", + } + `); + }); + + test('should return the correct schema when templateSchema is empty', () => { + const options = { + collectionName: 'testCollection', + dataSource: 'testDataSource', + association: 'testAssociation', + rowKey: 'testRowKey', + }; + + const schema = createGridCardBlockSchema(options); + + expect(schema).toMatchInlineSnapshot(` + { + "properties": { + "actionBar": { + "type": "void", + "x-component": "ActionBar", + "x-component-props": { + "style": { + "marginBottom": "var(--nb-spacing)", + }, + }, + "x-initializer": "gridCard:configureActions", + }, + "list": { + "properties": { + "item": { + "properties": { + "actionBar": { + "type": "void", + "x-align": "left", + "x-component": "ActionBar", + "x-component-props": { + "layout": "one-column", + }, + "x-initializer": "gridCard:configureItemActions", + "x-use-component-props": "useGridCardActionBarProps", + }, + "grid": { + "type": "void", + "x-component": "Grid", + "x-initializer": "details:configureFields", + }, + }, + "type": "object", + "x-component": "GridCard.Item", + "x-read-pretty": true, + "x-use-component-props": "useGridCardItemProps", + }, + }, + "type": "array", + "x-component": "GridCard", + "x-use-component-props": "useGridCardBlockProps", + }, + }, + "type": "void", + "x-acl-action": "testAssociation:view", + "x-component": "BlockItem", + "x-decorator": "GridCard.Decorator", + "x-decorator-props": { + "action": "list", + "association": "testAssociation", + "collection": "testCollection", + "dataSource": "testDataSource", + "params": { + "pageSize": 12, + }, + "readPretty": true, + "rowKey": "testRowKey", + "runWhenParamsChanged": true, + }, + "x-settings": "blockSettings:gridCard", + "x-toolbar": "BlockSchemaToolbar", + "x-use-component-props": "useGridCardBlockItemProps", + "x-use-decorator-props": "useGridCardBlockDecoratorProps", + } + `); + }); +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/grid-card/createGridCardBlockSchema.ts b/packages/core/client/src/modules/blocks/data-blocks/grid-card/createGridCardBlockSchema.ts new file mode 100644 index 000000000..3f69b8846 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/grid-card/createGridCardBlockSchema.ts @@ -0,0 +1,81 @@ +import { ISchema } from '@formily/react'; + +export const createGridCardBlockSchema = (options: { + dataSource: string; + collectionName?: string; + association?: string; + templateSchema?: ISchema; + rowKey?: string; +}): ISchema => { + const { collectionName, association, templateSchema, dataSource, rowKey } = options; + const resourceName = association || collectionName; + + if (!dataSource) { + throw new Error('dataSource are required'); + } + + return { + type: 'void', + 'x-acl-action': `${resourceName}:view`, + 'x-decorator': 'GridCard.Decorator', + 'x-use-decorator-props': 'useGridCardBlockDecoratorProps', + 'x-decorator-props': { + collection: collectionName, + association, + dataSource, + readPretty: true, + action: 'list', + params: { + pageSize: 12, + }, + runWhenParamsChanged: true, + rowKey, + }, + 'x-component': 'BlockItem', + 'x-use-component-props': 'useGridCardBlockItemProps', + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:gridCard', + properties: { + actionBar: { + type: 'void', + 'x-initializer': 'gridCard:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + }, + list: { + type: 'array', + 'x-component': 'GridCard', + 'x-use-component-props': 'useGridCardBlockProps', + properties: { + item: { + type: 'object', + 'x-component': 'GridCard.Item', + 'x-read-pretty': true, + 'x-use-component-props': 'useGridCardItemProps', + properties: { + grid: templateSchema || { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'details:configureFields', + }, + actionBar: { + type: 'void', + 'x-align': 'left', + 'x-initializer': 'gridCard:configureItemActions', + 'x-component': 'ActionBar', + 'x-use-component-props': 'useGridCardActionBarProps', + 'x-component-props': { + layout: 'one-column', + }, + }, + }, + }, + }, + }, + }, + }; +}; diff --git a/packages/core/client/src/modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockDecoratorProps.ts b/packages/core/client/src/modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockDecoratorProps.ts new file mode 100644 index 000000000..1dac89fee --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockDecoratorProps.ts @@ -0,0 +1,18 @@ +import { useDataBlockSourceId } from '../../../../../block-provider/hooks/useDataBlockSourceId'; +import { useGridCardBlockParams } from './useGridCardBlockParams'; + +export function useGridCardBlockDecoratorProps(props) { + const params = useGridCardBlockParams(props); + let sourceId; + + // 因为 association 是固定的,所以可以在条件中使用 hooks + if (props.association) { + // eslint-disable-next-line react-hooks/rules-of-hooks + sourceId = useDataBlockSourceId({ association: props.association }); + } + + return { + params, + sourceId, + }; +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockParams.ts b/packages/core/client/src/modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockParams.ts new file mode 100644 index 000000000..1edcac117 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockParams.ts @@ -0,0 +1,17 @@ +import { useParsedFilter } from '../../../../../block-provider/hooks/useParsedFilter'; +import { useMemo } from 'react'; + +export function useGridCardBlockParams(props) { + const { params } = props; + const { filter: parsedFilter } = useParsedFilter({ + filterOption: params?.filter, + }); + const paramsWithFilter = useMemo(() => { + return { + ...params, + filter: parsedFilter, + }; + }, [parsedFilter, params]); + + return paramsWithFilter; +} diff --git a/packages/core/client/src/schema-component/antd/block-item/BlockItem.tsx b/packages/core/client/src/schema-component/antd/block-item/BlockItem.tsx index 63a9b9a3e..01f47df86 100644 --- a/packages/core/client/src/schema-component/antd/block-item/BlockItem.tsx +++ b/packages/core/client/src/schema-component/antd/block-item/BlockItem.tsx @@ -5,9 +5,12 @@ import { SortableItem } from '../../common'; import { useDesigner, useProps } from '../../hooks'; import { useGetAriaLabelOfBlockItem } from './hooks/useGetAriaLabelOfBlockItem'; import { useFieldSchema } from '@formily/react'; +import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; -export const BlockItem: React.FC = (props) => { +export const BlockItem: React.FC = withDynamicSchemaProps((props) => { + // 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema const { className, children } = useProps(props); + const Designer = useDesigner(); const fieldSchema = useFieldSchema(); const { getAriaLabel } = useGetAriaLabelOfBlockItem(props.name); @@ -69,4 +72,4 @@ export const BlockItem: React.FC = (props) => { {children} ); -}; +}); diff --git a/packages/core/client/src/schema-component/antd/grid-card/GridCard.Decorator.tsx b/packages/core/client/src/schema-component/antd/grid-card/GridCard.Decorator.tsx index ecb1c0fe5..00dc5c748 100644 --- a/packages/core/client/src/schema-component/antd/grid-card/GridCard.Decorator.tsx +++ b/packages/core/client/src/schema-component/antd/grid-card/GridCard.Decorator.tsx @@ -1,9 +1,12 @@ import { FormLayout } from '@formily/antd-v5'; import { createForm } from '@formily/core'; -import { FormContext, useField } from '@formily/react'; +import { FormContext, useField, useFieldSchema } from '@formily/react'; import React, { createContext, useContext, useEffect, useMemo } from 'react'; import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider'; import useStyles from './GridCard.Decorator.style'; +import { useGridCardBlockParams } from '../../../modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockParams'; +import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; + export const GridCardBlockContext = createContext({}); GridCardBlockContext.displayName = 'GridCardBlockContext'; @@ -41,24 +44,31 @@ const InternalGridCardBlockProvider = (props) => { ); }; -export const GridCardBlockProvider = (props) => { - const { params } = props; - const { filter: parsedFilter } = useParsedFilter({ - filterOption: params?.filter, - }); - const paramsWithFilter = useMemo(() => { - return { - ...params, - filter: parsedFilter, - }; - }, [parsedFilter, params]); +/** + * 用于兼容旧版 UISchema(旧版本没有 x-use-decorator-props) + * @param props + */ +const useCompatGridCardBlockParams = (props) => { + const schema = useFieldSchema(); + + // 因为 x-use-decorator-props 的值是固定的,所以可以在条件中使用 hooks + if (schema['x-use-decorator-props']) { + return props.params; + } else { + // eslint-disable-next-line react-hooks/rules-of-hooks + return useGridCardBlockParams(props); + } +}; + +export const GridCardBlockProvider = withDynamicSchemaProps((props) => { + const params = useCompatGridCardBlockParams(props); return ( - + ); -}; +}); export const useGridCardBlockContext = () => { return useContext(GridCardBlockContext); diff --git a/packages/core/client/src/schema-component/antd/grid-card/GridCard.Item.tsx b/packages/core/client/src/schema-component/antd/grid-card/GridCard.Item.tsx index 8fdd38f58..c005d82d8 100644 --- a/packages/core/client/src/schema-component/antd/grid-card/GridCard.Item.tsx +++ b/packages/core/client/src/schema-component/antd/grid-card/GridCard.Item.tsx @@ -5,6 +5,7 @@ import { Card } from 'antd'; import React from 'react'; import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider'; import { RecordProvider } from '../../../record-provider'; +import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; const itemCss = css` display: flex; @@ -15,7 +16,7 @@ const itemCss = css` gap: 8px; `; -export const GridCardItem = (props) => { +export const GridCardItem = withDynamicSchemaProps((props) => { const field = useField(); const parentRecordData = useCollectionParentRecordData(); return ( @@ -40,4 +41,4 @@ export const GridCardItem = (props) => { ); -}; +}); diff --git a/packages/core/client/src/schema-component/antd/grid-card/GridCard.tsx b/packages/core/client/src/schema-component/antd/grid-card/GridCard.tsx index 990b7763f..63104ad2d 100644 --- a/packages/core/client/src/schema-component/antd/grid-card/GridCard.tsx +++ b/packages/core/client/src/schema-component/antd/grid-card/GridCard.tsx @@ -11,6 +11,7 @@ import { GridCardDesigner } from './GridCard.Designer'; import { GridCardItem } from './GridCard.Item'; import { useGridCardActionBarProps } from './hooks'; import { defaultColumnCount, pageSizeOptions } from './options'; +import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; const rowGutter = { md: 12, @@ -56,7 +57,9 @@ const designerCss = css` `; const InternalGridCard = (props) => { + // 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema const { columnCount: columnCountProp, pagination } = useProps(props); + const { service, columnCount: _columnCount = defaultColumnCount } = useGridCardBlockContext(); const columnCount = columnCountProp || _columnCount; const { run, params } = service; @@ -145,7 +148,7 @@ const InternalGridCard = (props) => { ); }; -export const GridCard = InternalGridCard as typeof InternalGridCard & { +export const GridCard = withDynamicSchemaProps(InternalGridCard) as typeof InternalGridCard & { Item: typeof GridCardItem; Designer: typeof GridCardDesigner; Decorator: typeof GridCardBlockProvider; diff --git a/packages/core/client/src/schema-initializer/items/RecordAssociationGridCardBlockInitializer.tsx b/packages/core/client/src/schema-initializer/items/RecordAssociationGridCardBlockInitializer.tsx index eec7ef3d7..2be266619 100644 --- a/packages/core/client/src/schema-initializer/items/RecordAssociationGridCardBlockInitializer.tsx +++ b/packages/core/client/src/schema-initializer/items/RecordAssociationGridCardBlockInitializer.tsx @@ -4,7 +4,8 @@ import React, { useCallback } from 'react'; import { useCollectionManager_deprecated } from '../../collection-manager'; import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../application'; import { useSchemaTemplateManager } from '../../schema-templates'; -import { createGridCardBlockSchema, useRecordCollectionDataSourceItems } from '../utils'; +import { useRecordCollectionDataSourceItems } from '../utils'; +import { createGridCardBlockSchema } from '../../modules/blocks/data-blocks/grid-card/createGridCardBlockSchema'; /** * @deprecated @@ -31,11 +32,8 @@ export const RecordAssociationGridCardBlockInitializer = () => { insert( createGridCardBlockSchema({ rowKey: collection.filterTargetKey, - collection: field.target, - resource, dataSource: collection.dataSource, association: resource, - settings: 'blockSettings:gridCard', }), ); } @@ -57,10 +55,8 @@ export function useCreateAssociationGridCardBlock() { insert( createGridCardBlockSchema({ rowKey: collection.filterTargetKey, - collection: field.target, dataSource: collection.dataSource, association: `${field.collectionName}.${field.name}`, - settings: 'blockSettings:gridCard', }), ); }, diff --git a/packages/core/client/src/schema-initializer/utils.ts b/packages/core/client/src/schema-initializer/utils.ts index 14c26667c..52dd6410c 100644 --- a/packages/core/client/src/schema-initializer/utils.ts +++ b/packages/core/client/src/schema-initializer/utils.ts @@ -972,97 +972,6 @@ export const createDetailsBlockSchema = (options) => { return schema; }; -export const createGridCardBlockSchema = (options) => { - const { - formItemInitializers = 'details:configureFields', - actionInitializers = 'gridCard:configureActions', - itemActionInitializers = 'gridCard:configureItemActions', - collection, - association, - template, - dataSource, - settings, - ...others - } = options; - const resourceName = association || collection; - const schema: ISchema = { - type: 'void', - 'x-acl-action': `${resourceName}:view`, - 'x-decorator': 'GridCard.Decorator', - 'x-decorator-props': { - collection, - association, - dataSource, - readPretty: true, - action: 'list', - params: { - pageSize: 12, - }, - runWhenParamsChanged: true, - ...others, - }, - 'x-component': 'BlockItem', - 'x-component-props': { - useProps: '{{ useGridCardBlockItemProps }}', - }, - 'x-toolbar': 'BlockSchemaToolbar', - 'x-settings': settings, - properties: { - actionBar: { - type: 'void', - 'x-initializer': actionInitializers, - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - properties: {}, - }, - list: { - type: 'array', - 'x-component': 'GridCard', - 'x-component-props': { - useProps: '{{ useGridCardBlockProps }}', - }, - properties: { - item: { - type: 'object', - 'x-component': 'GridCard.Item', - 'x-read-pretty': true, - 'x-component-props': { - useProps: '{{ useGridCardItemProps }}', - }, - properties: { - grid: template || { - type: 'void', - 'x-component': 'Grid', - 'x-initializer': formItemInitializers, - 'x-initializer-props': { - useProps: '{{ useGridCardItemInitializerProps }}', - }, - properties: {}, - }, - actionBar: { - type: 'void', - 'x-align': 'left', - 'x-initializer': itemActionInitializers, - 'x-component': 'ActionBar', - 'x-component-props': { - useProps: '{{ useGridCardActionBarProps }}', - layout: 'one-column', - }, - properties: {}, - }, - }, - }, - }, - }, - }, - }; - return schema; -}; - /** * @deprecated * 已弃用,请使用 createCreateFormBlockUISchema 或者 createEditFormBlockUISchema 替代 From 7566a7b35788db9480169fc58a0950ea373a4608 Mon Sep 17 00:00:00 2001 From: jack zhang <1098626505@qq.com> Date: Wed, 27 Mar 2024 21:03:51 +0800 Subject: [PATCH 04/26] fix: client internal method (T-3711 and T-3712 and T-3713) (#3839) * fix: client internal method (T-3711 and T-3712 and T-3712) * fix: bug --- .../client/src/application/Application.tsx | 6 ++++++ .../client/src/application/PluginManager.ts | 6 ++++++ .../client/src/application/RouterManager.tsx | 6 ++++++ .../schema-initializer/hooks/index.tsx | 6 ++++++ .../hooks/useAriaAttributeOfMenuItem.ts | 3 +++ .../components/SchemaSettingsWrapper.tsx | 3 +++ .../client/src/application/utils/globalDeps.ts | 3 +++ .../src/application/utils/remotePlugins.ts | 18 ++++++++++++++++++ .../client/src/application/utils/requirejs.ts | 3 +++ .../mixins/InheritanceCollectionMixin.ts | 2 +- .../collection-field/CollectionField.tsx | 5 ++++- .../src/data-source/collection/Collection.ts | 3 ++- .../collection/CollectionManager.ts | 3 +++ .../client/src/data-source/collection/utils.ts | 6 ++++++ .../CollectionDeletedPlaceholder.tsx | 3 +++ .../DataSourceApplicationProvider.tsx | 3 +++ .../data-block/DataBlockProvider.tsx | 3 +++ .../src/data-source/data-source/DataSource.ts | 3 +++ 18 files changed, 82 insertions(+), 3 deletions(-) diff --git a/packages/core/client/src/application/Application.tsx b/packages/core/client/src/application/Application.tsx index 938745e13..471ec5216 100644 --- a/packages/core/client/src/application/Application.tsx +++ b/packages/core/client/src/application/Application.tsx @@ -175,6 +175,9 @@ export class Application { return this.dataSourceManager.getDataSource(dataSource)?.collectionManager; } + /** + * @internal + */ getComposeProviders() { const Providers = compose(...this.providers)(BlankComponent); Providers.displayName = 'Providers'; @@ -280,6 +283,9 @@ export class Application { return React.createElement(this.getComponent(Component), props); } + /** + * @internal use addComponents({ SomeComponent }) instead + */ protected addComponent(component: ComponentType, name?: string) { const componentName = name || component.displayName || component.name; if (!componentName) { diff --git a/packages/core/client/src/application/PluginManager.ts b/packages/core/client/src/application/PluginManager.ts index 159313c19..3daa9c4c3 100644 --- a/packages/core/client/src/application/PluginManager.ts +++ b/packages/core/client/src/application/PluginManager.ts @@ -26,6 +26,9 @@ export class PluginManager { this.initPlugins = this.init(_plugins); } + /** + * @internal + */ async init(_plugins: PluginType[]) { await this.initStaticPlugins(_plugins); if (this.loadRemotePlugins) { @@ -84,6 +87,9 @@ export class PluginManager { return new plugin(opts, this.app); } + /** + * @internal + */ async load() { await this.initPlugins; diff --git a/packages/core/client/src/application/RouterManager.tsx b/packages/core/client/src/application/RouterManager.tsx index 5784463b2..405dc37aa 100644 --- a/packages/core/client/src/application/RouterManager.tsx +++ b/packages/core/client/src/application/RouterManager.tsx @@ -41,6 +41,9 @@ export class RouterManager { this.app = app; } + /** + * @internal + */ getRoutesTree(): RouteObject[] { type RouteTypeWithChildren = RouteType & { children?: RouteTypeWithChildren }; const routes: Record = {}; @@ -106,6 +109,9 @@ export class RouterManager { this.options.basename = basename; } + /** + * @internal + */ getRouterComponent() { const { type = 'browser', ...opts } = this.options; const Routers = { diff --git a/packages/core/client/src/application/schema-initializer/hooks/index.tsx b/packages/core/client/src/application/schema-initializer/hooks/index.tsx index 64cd3d30f..13dc41c1f 100644 --- a/packages/core/client/src/application/schema-initializer/hooks/index.tsx +++ b/packages/core/client/src/application/schema-initializer/hooks/index.tsx @@ -9,11 +9,17 @@ import { SchemaInitializerOptions } from '../types'; export * from './useAriaAttributeOfMenuItem'; +/** + * @internal + */ export function useSchemaInitializerMenuItems(items: any[], name?: string, onClick?: (args: any) => void) { const getMenuItems = useGetSchemaInitializerMenuItems(onClick); return useMemo(() => getMenuItems(items, name), [getMenuItems, items, name]); } +/** + * @internal + */ export function useGetSchemaInitializerMenuItems(onClick?: (args: any) => void) { const compile = useCompile(); diff --git a/packages/core/client/src/application/schema-initializer/hooks/useAriaAttributeOfMenuItem.ts b/packages/core/client/src/application/schema-initializer/hooks/useAriaAttributeOfMenuItem.ts index 04b2779dc..b1f38193c 100644 --- a/packages/core/client/src/application/schema-initializer/hooks/useAriaAttributeOfMenuItem.ts +++ b/packages/core/client/src/application/schema-initializer/hooks/useAriaAttributeOfMenuItem.ts @@ -1,6 +1,9 @@ import { useMemo } from 'react'; import { useSchemaInitializerSubMenuContext } from '../components/SchemaInitializerSubMenu'; +/** + * @internal + */ export const useAriaAttributeOfMenuItem = () => { const { isInMenu } = useSchemaInitializerSubMenuContext(); // 在 Menu 中,每一项的 role 已经被标记为 menuitem 了,不需要再次标记; diff --git a/packages/core/client/src/application/schema-settings/components/SchemaSettingsWrapper.tsx b/packages/core/client/src/application/schema-settings/components/SchemaSettingsWrapper.tsx index 5d7f7ab7f..ff0e8e81e 100644 --- a/packages/core/client/src/application/schema-settings/components/SchemaSettingsWrapper.tsx +++ b/packages/core/client/src/application/schema-settings/components/SchemaSettingsWrapper.tsx @@ -7,6 +7,9 @@ import React from 'react'; import { useDesignable } from '../../../schema-component'; import { useField, useFieldSchema } from '@formily/react'; +/** + * @internal + */ export const SchemaSettingsWrapper: FC> = (props) => { const { items, Component = SchemaSettingsIcon, name, componentProps, style, ...others } = props; const { dn } = useDesignable(); diff --git a/packages/core/client/src/application/utils/globalDeps.ts b/packages/core/client/src/application/utils/globalDeps.ts index 3de6c4406..177e6f474 100644 --- a/packages/core/client/src/application/utils/globalDeps.ts +++ b/packages/core/client/src/application/utils/globalDeps.ts @@ -35,6 +35,9 @@ import * as nocobaseClient from '../../index'; import type { RequireJS } from './requirejs'; +/** + * @internal + */ export function defineGlobalDeps(requirejs: RequireJS) { // react requirejs.define('react', () => React); diff --git a/packages/core/client/src/application/utils/remotePlugins.ts b/packages/core/client/src/application/utils/remotePlugins.ts index adfcabc6c..c6f3f850f 100644 --- a/packages/core/client/src/application/utils/remotePlugins.ts +++ b/packages/core/client/src/application/utils/remotePlugins.ts @@ -3,12 +3,18 @@ import type { PluginData } from '../PluginManager'; import type { RequireJS } from './requirejs'; import type { DevDynamicImport } from '../Application'; +/** + * @internal + */ export function defineDevPlugins(plugins: Record) { Object.entries(plugins).forEach(([packageName, plugin]) => { window.define(`${packageName}/client`, () => plugin); }); } +/** + * @internal + */ export function definePluginClient(packageName: string) { window.define(`${packageName}/client`, ['exports', packageName], function (_exports: any, _pluginExports: any) { Object.defineProperty(_exports, '__esModule', { @@ -27,6 +33,9 @@ export function definePluginClient(packageName: string) { }); } +/** + * @internal + */ export function configRequirejs(requirejs: any, pluginData: PluginData[]) { requirejs.requirejs.config({ waitSeconds: 120, @@ -37,6 +46,9 @@ export function configRequirejs(requirejs: any, pluginData: PluginData[]) { }); } +/** + * @internal + */ export function processRemotePlugins(pluginData: PluginData[], resolve: (plugins: [string, typeof Plugin][]) => void) { return (...pluginModules: (typeof Plugin & { default?: typeof Plugin })[]) => { const res: [string, typeof Plugin][] = pluginModules @@ -58,6 +70,9 @@ export function processRemotePlugins(pluginData: PluginData[], resolve: (plugins }; } +/** + * @internal + */ export function getRemotePlugins( requirejs: any, pluginData: PluginData[] = [], @@ -80,6 +95,9 @@ interface GetPluginsOption { devDynamicImport?: DevDynamicImport; } +/** + * @internal + */ export async function getPlugins(options: GetPluginsOption): Promise> { const { requirejs, pluginData, devDynamicImport } = options; if (pluginData.length === 0) return []; diff --git a/packages/core/client/src/application/utils/requirejs.ts b/packages/core/client/src/application/utils/requirejs.ts index 9a0d77edf..10aeddfcf 100644 --- a/packages/core/client/src/application/utils/requirejs.ts +++ b/packages/core/client/src/application/utils/requirejs.ts @@ -10,6 +10,9 @@ export interface RequireJS { define: RequireDefine } +/** + * @internal + */ export function getRequireJs(): RequireJS { var requirejs, require, define; var req, s, head, baseElement, dataMain, src, diff --git a/packages/core/client/src/collection-manager/mixins/InheritanceCollectionMixin.ts b/packages/core/client/src/collection-manager/mixins/InheritanceCollectionMixin.ts index 3f9549c27..2d489bd11 100644 --- a/packages/core/client/src/collection-manager/mixins/InheritanceCollectionMixin.ts +++ b/packages/core/client/src/collection-manager/mixins/InheritanceCollectionMixin.ts @@ -110,7 +110,7 @@ export class InheritanceCollectionMixin extends Collection { } // override Collection - getFieldsMap() { + protected getFieldsMap() { if (this.fieldsMap) { return this.fieldsMap; } diff --git a/packages/core/client/src/data-source/collection-field/CollectionField.tsx b/packages/core/client/src/data-source/collection-field/CollectionField.tsx index 2896d3563..514cfa31c 100644 --- a/packages/core/client/src/data-source/collection-field/CollectionField.tsx +++ b/packages/core/client/src/data-source/collection-field/CollectionField.tsx @@ -13,7 +13,10 @@ type Props = { children?: React.ReactNode; }; -// TODO: 初步适配 +/** + * TODO: 初步适配 + * @internal + */ export const CollectionFieldInternalField: React.FC = (props: Props) => { const { component } = props; const compile = useCompile(); diff --git a/packages/core/client/src/data-source/collection/Collection.ts b/packages/core/client/src/data-source/collection/Collection.ts index 5f83bcaea..27763b019 100644 --- a/packages/core/client/src/data-source/collection/Collection.ts +++ b/packages/core/client/src/data-source/collection/Collection.ts @@ -234,7 +234,8 @@ export class Collection { getFields(predicate?: GetCollectionFieldPredicate) { return predicate ? filter(this.fields, predicate) : this.fields; } - getFieldsMap() { + + protected getFieldsMap() { if (!this.fieldsMap) { this.fieldsMap = this.getFields().reduce((memo, field) => { memo[field.name] = field; diff --git a/packages/core/client/src/data-source/collection/CollectionManager.ts b/packages/core/client/src/data-source/collection/CollectionManager.ts index 95bdf8fa1..e1b0b851e 100644 --- a/packages/core/client/src/data-source/collection/CollectionManager.ts +++ b/packages/core/client/src/data-source/collection/CollectionManager.ts @@ -131,6 +131,9 @@ export class CollectionManager { return this.getCollection(collectionName)?.getFields(predicate) || []; } + /** + * @internal + */ clone(collections: CollectionOptions[] = []) { const collectionManager = new CollectionManager([], this.dataSource); diff --git a/packages/core/client/src/data-source/collection/utils.ts b/packages/core/client/src/data-source/collection/utils.ts index 84a2fd013..a078ff872 100644 --- a/packages/core/client/src/data-source/collection/utils.ts +++ b/packages/core/client/src/data-source/collection/utils.ts @@ -1,6 +1,9 @@ import type { Application } from '../../application/Application'; import type { CollectionOptions } from './Collection'; +/** + * @internal + */ export const collectionTransform = (collection: CollectionOptions, app: Application) => { const { rawTitle, title, fields = [], ...rest } = collection; return { @@ -26,6 +29,9 @@ export const collectionTransform = (collection: CollectionOptions, app: Applicat }; }; +/** + * @internal + */ export function applyMixins(Cls: any, mixins: any[], options?: any, collectionManager?: any) { const instance = new Cls(options, collectionManager); mixins.forEach((MixinClass) => { diff --git a/packages/core/client/src/data-source/components/CollectionDeletedPlaceholder.tsx b/packages/core/client/src/data-source/components/CollectionDeletedPlaceholder.tsx index d92c582d4..278fd51cd 100644 --- a/packages/core/client/src/data-source/components/CollectionDeletedPlaceholder.tsx +++ b/packages/core/client/src/data-source/components/CollectionDeletedPlaceholder.tsx @@ -15,6 +15,9 @@ export interface CollectionDeletedPlaceholderProps { const { Text } = Typography; +/** + * @internal + */ export const CollectionDeletedPlaceholder: FC = ({ type, name, message }) => { const { designable, dn } = useDesignable(); const { modal } = App.useApp(); diff --git a/packages/core/client/src/data-source/components/DataSourceApplicationProvider.tsx b/packages/core/client/src/data-source/components/DataSourceApplicationProvider.tsx index c2b754691..4327f647d 100644 --- a/packages/core/client/src/data-source/components/DataSourceApplicationProvider.tsx +++ b/packages/core/client/src/data-source/components/DataSourceApplicationProvider.tsx @@ -10,6 +10,9 @@ interface DataSourceApplicationProviderProps extends CollectionManagerProviderPr dataSourceManager: DataSourceManager; } +/** + * @internal + */ export const DataSourceApplicationProvider: FC = ({ children, dataSourceManager, diff --git a/packages/core/client/src/data-source/data-block/DataBlockProvider.tsx b/packages/core/client/src/data-source/data-block/DataBlockProvider.tsx index 6936566d6..e4067ffb8 100644 --- a/packages/core/client/src/data-source/data-block/DataBlockProvider.tsx +++ b/packages/core/client/src/data-source/data-block/DataBlockProvider.tsx @@ -103,6 +103,9 @@ export interface DataBlockContextValue { export const DataBlockContext = createContext>({} as any); DataBlockContext.displayName = 'DataBlockContext'; +/** + * @internal + */ export const AssociationOrCollectionProvider = (props: { collection: string | CollectionOptions; association: string; diff --git a/packages/core/client/src/data-source/data-source/DataSource.ts b/packages/core/client/src/data-source/data-source/DataSource.ts index 6a991f455..2787f98a4 100644 --- a/packages/core/client/src/data-source/data-source/DataSource.ts +++ b/packages/core/client/src/data-source/data-source/DataSource.ts @@ -83,6 +83,9 @@ export abstract class DataSource { } } +/** + * @internal + */ export class LocalDataSource extends DataSource { getDataSource() { return { From 2468caeeb91db9596617753e446a7c72cb9d027b Mon Sep 17 00:00:00 2001 From: Zeke Zhang <958414905@qq.com> Date: Thu, 28 Mar 2024 08:48:58 +0800 Subject: [PATCH 05/26] refactor(DataBlock): details block (#3776) * refactor: remove useless code related 'TableField' * refactor: add details block UI schema and hooks * refactor: update details block schema and create new hook for details block without paging props * refactor: add useDetailsBlockWithoutPagingDecoratorProps and useDetailsBlockWithPagingDecoratorProps * test: add unit tests * chore: fix build * chore: fix import path for withDynamicSchemaProps * fix: fix import typo in createDetailsBlockWithoutPagingUISchema test * chore: fix unit test * refactor: should not get collection on getting association in UISchema * chore: fix unit test * refactor: use x-use-component-props instead of useProps * chore: fix Pagination * chore: skip weird tests * chore: remove weird test * refactor: update details block initializers and associated schemas * refactor: rename to useDetailsWithPaginationProps * refactor: rename to useDetailsWithPaginationDecoratorProps * refactor: rename to createDetailsWithPaginationUISchema * chore: fix unit test * refactor: rename to createDetailsUISchema * refactor: rename to useDetailsDecoratorProps * refactor: rename to useDetailsProps * refactor: rename to 'blockSettings:details' * chore: fix e2e --- .../BlockSchemaComponentProvider.tsx | 12 + .../block-provider/DetailsBlockProvider.tsx | 10 +- .../DetailsActionInitializers.tsx | 4 + .../details-multi/DetailsBlockInitializer.tsx | 13 +- ...eateDetailsBlockWithPagingUISchema.test.ts | 69 ++++++ .../createDetailsWithPaginationUISchema.ts | 70 ++++++ .../detailsWithPaginationSettings.tsx | 216 ++++++++++++++++++ .../useDetailsWithPaginationDecoratorProps.ts | 15 ++ .../hooks/useDetailsWithPaginationProps.ts | 5 + .../multiDataDetailsBlockSettings.tsx | 204 ----------------- .../ReadPrettyFormItemInitializers.tsx | 1 + .../RecordReadPrettyFormBlockInitializer.tsx | 58 ++--- ...eDetailsBlockWithoutPagingUISchema.test.ts | 62 +++++ .../details-single/createDetailsUISchema.ts | 60 +++++ .../details-single/detailsBlockSettings.ts | 56 +++++ .../hooks/useDetailsDecoratorProps.ts | 18 ++ .../details-single/hooks/useDetailsProps.ts | 5 + .../singleDataDetailsBlockSettings.ts | 44 ---- .../dialog/__e2e__/schemaInitializer.test.ts | 2 +- .../schema-component/antd/details/Details.tsx | 5 +- .../pagination/__tests__/pagination.test.tsx | 15 -- .../antd/pagination/index.tsx | 39 ++-- ...cordAssociationDetailsBlockInitializer.tsx | 12 +- ...dPrettyAssociationFormBlockInitializer.tsx | 50 +--- .../client/src/schema-initializer/utils.ts | 13 +- .../schema-settings/SchemaSettingsPlugin.ts | 12 +- 26 files changed, 698 insertions(+), 372 deletions(-) create mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-multi/__tests__/createDetailsBlockWithPagingUISchema.test.ts create mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-multi/createDetailsWithPaginationUISchema.ts create mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-multi/detailsWithPaginationSettings.tsx create mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationDecoratorProps.ts create mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationProps.ts delete mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-multi/multiDataDetailsBlockSettings.tsx create mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-single/__tests__/createDetailsBlockWithoutPagingUISchema.test.ts create mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-single/createDetailsUISchema.ts create mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-single/detailsBlockSettings.ts create mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-single/hooks/useDetailsDecoratorProps.ts create mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-single/hooks/useDetailsProps.ts delete mode 100644 packages/core/client/src/modules/blocks/data-blocks/details-single/singleDataDetailsBlockSettings.ts delete mode 100644 packages/core/client/src/schema-component/antd/pagination/__tests__/pagination.test.tsx diff --git a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx index 444abb570..d7d8afbed 100644 --- a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx +++ b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx @@ -27,6 +27,10 @@ import { useCollapseBlockDecoratorProps } from '../modules/blocks/filter-blocks/ import { useFilterFormBlockProps } from '../modules/blocks/filter-blocks/form/hooks/useFilterFormBlockProps'; import { useFilterFormBlockDecoratorProps } from '../modules/blocks/filter-blocks/form/hooks/useFilterFormBlockDecoratorProps'; import { useGridCardBlockDecoratorProps } from '../modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockDecoratorProps'; +import { useDetailsProps } from '../modules/blocks/data-blocks/details-single/hooks/useDetailsProps'; +import { useDetailsWithPaginationProps } from '../modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationProps'; +import { useDetailsDecoratorProps } from '../modules/blocks/data-blocks/details-single/hooks/useDetailsDecoratorProps'; +import { useDetailsWithPaginationDecoratorProps } from '../modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationDecoratorProps'; // TODO: delete this, replaced by `BlockSchemaComponentPlugin` export const BlockSchemaComponentProvider: React.FC = (props) => { @@ -54,6 +58,10 @@ export const BlockSchemaComponentProvider: React.FC = (props) => { useEditFormBlockProps, useFormFieldProps, useDetailsBlockProps, + useDetailsProps, + useDetailsWithPaginationProps, + useDetailsDecoratorProps, + useDetailsWithPaginationDecoratorProps, useTableFieldProps, useTableBlockProps, useTableSelectorProps, @@ -108,6 +116,10 @@ export class BlockSchemaComponentPlugin extends Plugin { useEditFormBlockProps, useFormFieldProps, useDetailsBlockProps, + useDetailsProps, + useDetailsWithPaginationProps, + useDetailsDecoratorProps, + useDetailsWithPaginationDecoratorProps, useTableFieldProps, useTableBlockProps, useTableSelectorProps, diff --git a/packages/core/client/src/block-provider/DetailsBlockProvider.tsx b/packages/core/client/src/block-provider/DetailsBlockProvider.tsx index 97edf2075..8899a1e5a 100644 --- a/packages/core/client/src/block-provider/DetailsBlockProvider.tsx +++ b/packages/core/client/src/block-provider/DetailsBlockProvider.tsx @@ -7,6 +7,7 @@ import { useCollectionParentRecord } from '../data-source/collection-record/Coll import { RecordProvider } from '../record-provider'; import { BlockProvider, useBlockRequestContext } from './BlockProvider'; import { useParsedFilter } from './hooks'; +import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps'; export const DetailsBlockContext = createContext({}); DetailsBlockContext.displayName = 'DetailsBlockContext'; @@ -57,13 +58,13 @@ const InternalDetailsBlockProvider = (props) => { ); }; -export const DetailsBlockProvider = (props) => { +export const DetailsBlockProvider = withDynamicSchemaProps((props) => { return ( ); -}; +}); /** * @deprecated @@ -72,6 +73,11 @@ export const useDetailsBlockContext = () => { return useContext(DetailsBlockContext); }; +/** + * @deprecated + * 即将废弃,请用 useDetailsWithPaginationProps 或者 useDetailsProps + * @returns + */ export const useDetailsBlockProps = () => { const ctx = useDetailsBlockContext(); useEffect(() => { diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-multi/DetailsActionInitializers.tsx b/packages/core/client/src/modules/blocks/data-blocks/details-multi/DetailsActionInitializers.tsx index 15ace51a0..41adedbfb 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/details-multi/DetailsActionInitializers.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/details-multi/DetailsActionInitializers.tsx @@ -53,6 +53,10 @@ export const detailsActionInitializers_deprecated = new CompatibleSchemaInitiali ], }); +/** + * @deprecated + * 已弃用,请使用 readPrettyFormActionInitializers 代替 + */ export const detailsActionInitializers = new CompatibleSchemaInitializer( { name: 'detailsWithPaging:configureActions', diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-multi/DetailsBlockInitializer.tsx b/packages/core/client/src/modules/blocks/data-blocks/details-multi/DetailsBlockInitializer.tsx index 4c5bb13ca..11abe4a9b 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/details-multi/DetailsBlockInitializer.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/details-multi/DetailsBlockInitializer.tsx @@ -2,9 +2,9 @@ import { TableOutlined } from '@ant-design/icons'; import React from 'react'; import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; import { useCollectionManager_deprecated } from '../../../../collection-manager'; -import { createDetailsBlockSchema } from '../../../../schema-initializer/utils'; import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer'; import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection'; +import { createDetailsWithPaginationUISchema } from './createDetailsWithPaginationUISchema'; export const DetailsBlockInitializer = ({ filterCollections, @@ -51,15 +51,14 @@ export const DetailsBlockInitializer = ({ const { item } = options; const collection = getCollection(item.name, item.dataSource); - const schema = createDetailsBlockSchema({ - collection: item.name, + const schema = createDetailsWithPaginationUISchema({ + collectionName: item.name, dataSource: item.dataSource, rowKey: collection.filterTargetKey || 'id', - actionInitializers: + hideActionInitializer: !( (collection.template !== 'view' || collection?.writableView) && - collection.template !== 'sql' && - 'detailsWithPaging:configureActions', - settings: 'blockSettings:multiDataDetails', + collection.template !== 'sql' + ), }); insert(schema); }} diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-multi/__tests__/createDetailsBlockWithPagingUISchema.test.ts b/packages/core/client/src/modules/blocks/data-blocks/details-multi/__tests__/createDetailsBlockWithPagingUISchema.test.ts new file mode 100644 index 000000000..2bfc87976 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/details-multi/__tests__/createDetailsBlockWithPagingUISchema.test.ts @@ -0,0 +1,69 @@ +import { createDetailsWithPaginationUISchema } from '../createDetailsWithPaginationUISchema'; + +vi.mock('@formily/shared', () => ({ + uid: vi.fn().mockReturnValue('mocked-uid'), +})); + +describe('createDetailsBlockWithPaginationUISchema', () => { + it('should return the correct schema', () => { + const schema = createDetailsWithPaginationUISchema({ + collectionName: 'users', + dataSource: 'users', + rowKey: 'id', + }); + + expect(schema).toMatchInlineSnapshot(` + { + "properties": { + "mocked-uid": { + "properties": { + "grid": { + "properties": {}, + "type": "void", + "x-component": "Grid", + "x-initializer": "details:configureFields", + }, + "mocked-uid": { + "properties": {}, + "type": "void", + "x-component": "ActionBar", + "x-component-props": { + "style": { + "marginBottom": 24, + }, + }, + "x-initializer": "details:configureActions", + }, + "pagination": { + "type": "void", + "x-component": "Pagination", + "x-use-component-props": "useDetailsPaginationProps", + }, + }, + "type": "void", + "x-component": "Details", + "x-read-pretty": true, + "x-use-component-props": "useDetailsWithPaginationProps", + }, + }, + "type": "void", + "x-acl-action": "users:view", + "x-component": "CardItem", + "x-decorator": "DetailsBlockProvider", + "x-decorator-props": { + "action": "list", + "association": undefined, + "collection": "users", + "dataSource": "users", + "params": { + "pageSize": 1, + }, + "readPretty": true, + }, + "x-settings": "blockSettings:detailsWithPagination", + "x-toolbar": "BlockSchemaToolbar", + "x-use-decorator-props": "useDetailsWithPaginationDecoratorProps", + } + `); + }); +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-multi/createDetailsWithPaginationUISchema.ts b/packages/core/client/src/modules/blocks/data-blocks/details-multi/createDetailsWithPaginationUISchema.ts new file mode 100644 index 000000000..009162592 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/details-multi/createDetailsWithPaginationUISchema.ts @@ -0,0 +1,70 @@ +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; + +export function createDetailsWithPaginationUISchema(options: { + dataSource: string; + rowKey: string; + collectionName?: string; + association?: string; + templateSchema?: ISchema; + hideActionInitializer?: boolean; +}): ISchema { + const { collectionName, dataSource, association, templateSchema, hideActionInitializer, rowKey } = options; + const resourceName = association || collectionName; + + if (!dataSource || !rowKey) { + throw new Error('dataSource and rowKey are required'); + } + + return { + type: 'void', + 'x-acl-action': `${resourceName}:view`, + 'x-decorator': 'DetailsBlockProvider', + 'x-use-decorator-props': 'useDetailsWithPaginationDecoratorProps', + 'x-decorator-props': { + dataSource, + collection: collectionName, + association, + readPretty: true, + action: 'list', + params: { + pageSize: 1, + }, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:detailsWithPagination', + 'x-component': 'CardItem', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Details', + 'x-read-pretty': true, + 'x-use-component-props': 'useDetailsWithPaginationProps', + properties: { + [uid()]: { + type: 'void', + 'x-initializer': hideActionInitializer ? undefined : 'details:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + properties: {}, + }, + grid: templateSchema || { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'details:configureFields', + properties: {}, + }, + pagination: { + type: 'void', + 'x-component': 'Pagination', + 'x-use-component-props': 'useDetailsPaginationProps', + }, + }, + }, + }, + }; +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-multi/detailsWithPaginationSettings.tsx b/packages/core/client/src/modules/blocks/data-blocks/details-multi/detailsWithPaginationSettings.tsx new file mode 100644 index 000000000..adea06e58 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/details-multi/detailsWithPaginationSettings.tsx @@ -0,0 +1,216 @@ +import { ArrayItems } from '@formily/antd-v5'; +import { ISchema, useField, useFieldSchema } from '@formily/react'; +import { useTranslation } from 'react-i18next'; +import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings'; +import { useFormBlockContext } from '../../../../block-provider'; +import { useDetailsBlockContext } from '../../../../block-provider/DetailsBlockProvider'; +import { useCollection_deprecated, useSortFields } from '../../../../collection-manager'; +import { removeNullCondition, useDesignable } from '../../../../schema-component'; +import { SchemaSettingsBlockTitleItem, SchemaSettingsTemplate } from '../../../../schema-settings'; +import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope'; +import { setDataLoadingModeSettingsItem, useDataLoadingMode } from './setDataLoadingModeSettingsItem'; +import { SchemaSettingsItemType } from '../../../../application/schema-settings/types'; + +const commonItems: SchemaSettingsItemType[] = [ + { + name: 'title', + Component: SchemaSettingsBlockTitleItem, + }, + { + name: 'dataScope', + Component: SchemaSettingsDataScope, + useComponentProps() { + const { name } = useCollection_deprecated(); + const fieldSchema = useFieldSchema(); + const { form } = useFormBlockContext(); + const field = useField(); + const { service } = useDetailsBlockContext(); + const { dn } = useDesignable(); + const dataLoadingMode = useDataLoadingMode(); + return { + collectionName: name, + defaultFilter: fieldSchema?.['x-decorator-props']?.params?.filter || {}, + form, + onSubmit: ({ filter }) => { + filter = removeNullCondition(filter); + const params = field.decoratorProps.params || {}; + params.filter = filter; + field.decoratorProps.params = params; + fieldSchema['x-decorator-props']['params'] = params; + + if (dataLoadingMode === 'auto') { + service.run({ ...service.params?.[0], filter }); + } + + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + }, + }; + }, + }, + { + name: 'sortingRules', + type: 'modal', + useComponentProps() { + const { name } = useCollection_deprecated(); + const { t } = useTranslation(); + const fieldSchema = useFieldSchema(); + const field = useField(); + const { service } = useDetailsBlockContext(); + const { dn } = useDesignable(); + const sortFields = useSortFields(name); + const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || []; + const sort = defaultSort?.map((item: string) => { + return item.startsWith('-') + ? { + field: item.substring(1), + direction: 'desc', + } + : { + field: item, + direction: 'asc', + }; + }); + return { + title: t('Set default sorting rules'), + components: { + ArrayItems, + }, + schema: { + type: 'object', + title: t('Set default sorting rules'), + properties: { + sort: { + type: 'array', + default: sort, + 'x-component': 'ArrayItems', + 'x-decorator': 'FormItem', + items: { + type: 'object', + properties: { + space: { + type: 'void', + 'x-component': 'Space', + properties: { + sort: { + type: 'void', + 'x-decorator': 'FormItem', + 'x-component': 'ArrayItems.SortHandle', + }, + field: { + type: 'string', + enum: sortFields, + required: true, + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-component-props': { + style: { + width: 260, + }, + }, + }, + direction: { + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'Radio.Group', + 'x-component-props': { + optionType: 'button', + }, + enum: [ + { + label: t('ASC'), + value: 'asc', + }, + { + label: t('DESC'), + value: 'desc', + }, + ], + }, + remove: { + type: 'void', + 'x-decorator': 'FormItem', + 'x-component': 'ArrayItems.Remove', + }, + }, + }, + }, + }, + properties: { + add: { + type: 'void', + title: t('Add sort field'), + 'x-component': 'ArrayItems.Addition', + }, + }, + }, + }, + } as ISchema, + onSubmit({ sort }) { + const sortArr = sort.map((item) => { + return item.direction === 'desc' ? `-${item.field}` : item.field; + }); + const params = field.decoratorProps.params || {}; + params.sort = sortArr; + field.decoratorProps.params = params; + fieldSchema['x-decorator-props']['params'] = params; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + service.run({ ...service.params?.[0], sort: sortArr }); + }, + }; + }, + }, + setDataLoadingModeSettingsItem, + { + name: 'template', + Component: SchemaSettingsTemplate, + useComponentProps() { + const { name } = useCollection_deprecated(); + const fieldSchema = useFieldSchema(); + const defaultResource = + fieldSchema?.['x-decorator-props']?.resource || fieldSchema?.['x-decorator-props']?.association; + return { + componentName: 'Details', + collectionName: name, + resourceName: defaultResource, + }; + }, + }, + { + name: 'divider', + type: 'divider', + }, + { + name: 'remove', + type: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + }, + }, +]; + +/** + * @deprecated + * 已弃用,请使用 detailsWithPaginationSettings 代替 + */ +export const multiDataDetailsBlockSettings = new SchemaSettings({ + name: 'blockSettings:multiDataDetails', + items: commonItems, +}); + +export const detailsWithPaginationSettings = new SchemaSettings({ + name: 'blockSettings:detailsWithPagination', + items: commonItems, +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationDecoratorProps.ts b/packages/core/client/src/modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationDecoratorProps.ts new file mode 100644 index 000000000..5d3935fde --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationDecoratorProps.ts @@ -0,0 +1,15 @@ +import { useDataBlockSourceId } from '../../../../../block-provider/hooks/useDataBlockSourceId'; + +export function useDetailsWithPaginationDecoratorProps(props) { + let sourceId; + + // association 的值是固定不变的,所以可以在条件中使用 hooks + if (props.association) { + // eslint-disable-next-line react-hooks/rules-of-hooks + sourceId = useDataBlockSourceId({ association: props.association }); + } + + return { + sourceId, + }; +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationProps.ts b/packages/core/client/src/modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationProps.ts new file mode 100644 index 000000000..675c97518 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationProps.ts @@ -0,0 +1,5 @@ +import { useDetailsBlockProps } from '../../../../../block-provider/DetailsBlockProvider'; + +export function useDetailsWithPaginationProps() { + return useDetailsBlockProps(); +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-multi/multiDataDetailsBlockSettings.tsx b/packages/core/client/src/modules/blocks/data-blocks/details-multi/multiDataDetailsBlockSettings.tsx deleted file mode 100644 index 8b52f5907..000000000 --- a/packages/core/client/src/modules/blocks/data-blocks/details-multi/multiDataDetailsBlockSettings.tsx +++ /dev/null @@ -1,204 +0,0 @@ -import { ArrayItems } from '@formily/antd-v5'; -import { ISchema, useField, useFieldSchema } from '@formily/react'; -import { useTranslation } from 'react-i18next'; -import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings'; -import { useFormBlockContext } from '../../../../block-provider'; -import { useDetailsBlockContext } from '../../../../block-provider/DetailsBlockProvider'; -import { useCollection_deprecated, useSortFields } from '../../../../collection-manager'; -import { removeNullCondition, useDesignable } from '../../../../schema-component'; -import { SchemaSettingsBlockTitleItem, SchemaSettingsTemplate } from '../../../../schema-settings'; -import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope'; -import { setDataLoadingModeSettingsItem, useDataLoadingMode } from './setDataLoadingModeSettingsItem'; - -export const multiDataDetailsBlockSettings = new SchemaSettings({ - name: 'blockSettings:multiDataDetails', - items: [ - { - name: 'title', - Component: SchemaSettingsBlockTitleItem, - }, - { - name: 'dataScope', - Component: SchemaSettingsDataScope, - useComponentProps() { - const { name } = useCollection_deprecated(); - const fieldSchema = useFieldSchema(); - const { form } = useFormBlockContext(); - const field = useField(); - const { service } = useDetailsBlockContext(); - const { dn } = useDesignable(); - const dataLoadingMode = useDataLoadingMode(); - return { - collectionName: name, - defaultFilter: fieldSchema?.['x-decorator-props']?.params?.filter || {}, - form, - onSubmit: ({ filter }) => { - filter = removeNullCondition(filter); - const params = field.decoratorProps.params || {}; - params.filter = filter; - field.decoratorProps.params = params; - fieldSchema['x-decorator-props']['params'] = params; - - if (dataLoadingMode === 'auto') { - service.run({ ...service.params?.[0], filter }); - } - - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - }, - }; - }, - }, - { - name: 'sortingRules', - type: 'modal', - useComponentProps() { - const { name } = useCollection_deprecated(); - const { t } = useTranslation(); - const fieldSchema = useFieldSchema(); - const field = useField(); - const { service } = useDetailsBlockContext(); - const { dn } = useDesignable(); - const sortFields = useSortFields(name); - const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || []; - const sort = defaultSort?.map((item: string) => { - return item.startsWith('-') - ? { - field: item.substring(1), - direction: 'desc', - } - : { - field: item, - direction: 'asc', - }; - }); - return { - title: t('Set default sorting rules'), - components: { - ArrayItems, - }, - schema: { - type: 'object', - title: t('Set default sorting rules'), - properties: { - sort: { - type: 'array', - default: sort, - 'x-component': 'ArrayItems', - 'x-decorator': 'FormItem', - items: { - type: 'object', - properties: { - space: { - type: 'void', - 'x-component': 'Space', - properties: { - sort: { - type: 'void', - 'x-decorator': 'FormItem', - 'x-component': 'ArrayItems.SortHandle', - }, - field: { - type: 'string', - enum: sortFields, - required: true, - 'x-decorator': 'FormItem', - 'x-component': 'Select', - 'x-component-props': { - style: { - width: 260, - }, - }, - }, - direction: { - type: 'string', - 'x-decorator': 'FormItem', - 'x-component': 'Radio.Group', - 'x-component-props': { - optionType: 'button', - }, - enum: [ - { - label: t('ASC'), - value: 'asc', - }, - { - label: t('DESC'), - value: 'desc', - }, - ], - }, - remove: { - type: 'void', - 'x-decorator': 'FormItem', - 'x-component': 'ArrayItems.Remove', - }, - }, - }, - }, - }, - properties: { - add: { - type: 'void', - title: t('Add sort field'), - 'x-component': 'ArrayItems.Addition', - }, - }, - }, - }, - } as ISchema, - onSubmit({ sort }) { - const sortArr = sort.map((item) => { - return item.direction === 'desc' ? `-${item.field}` : item.field; - }); - const params = field.decoratorProps.params || {}; - params.sort = sortArr; - field.decoratorProps.params = params; - fieldSchema['x-decorator-props']['params'] = params; - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - service.run({ ...service.params?.[0], sort: sortArr }); - }, - }; - }, - }, - setDataLoadingModeSettingsItem, - { - name: 'template', - Component: SchemaSettingsTemplate, - useComponentProps() { - const { name } = useCollection_deprecated(); - const fieldSchema = useFieldSchema(); - const defaultResource = - fieldSchema?.['x-decorator-props']?.resource || fieldSchema?.['x-decorator-props']?.association; - return { - componentName: 'Details', - collectionName: name, - resourceName: defaultResource, - }; - }, - }, - { - name: 'divider', - type: 'divider', - }, - { - name: 'remove', - type: 'remove', - componentProps: { - removeParentsIfNoChildren: true, - breakRemoveOn: { - 'x-component': 'Grid', - }, - }, - }, - ], -}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-single/ReadPrettyFormItemInitializers.tsx b/packages/core/client/src/modules/blocks/data-blocks/details-single/ReadPrettyFormItemInitializers.tsx index 9efcdcf26..6e87749ba 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/details-single/ReadPrettyFormItemInitializers.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/details-single/ReadPrettyFormItemInitializers.tsx @@ -47,6 +47,7 @@ const AssociatedFields = () => { /** * @deprecated + * 已弃用,请使用 readPrettyFormItemInitializers 代替 */ export const readPrettyFormItemInitializers_deprecated = new CompatibleSchemaInitializer({ name: 'ReadPrettyFormItemInitializers', diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-single/RecordReadPrettyFormBlockInitializer.tsx b/packages/core/client/src/modules/blocks/data-blocks/details-single/RecordReadPrettyFormBlockInitializer.tsx index 35782e788..6d6127fbb 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/details-single/RecordReadPrettyFormBlockInitializer.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/details-single/RecordReadPrettyFormBlockInitializer.tsx @@ -1,10 +1,11 @@ import { FormOutlined } from '@ant-design/icons'; import React, { useCallback } from 'react'; import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; -import { useBlockAssociationContext, useBlockRequestContext } from '../../../../block-provider'; +import { useBlockAssociationContext } from '../../../../block-provider'; import { useCollection_deprecated } from '../../../../collection-manager'; import { useSchemaTemplateManager } from '../../../../schema-templates'; -import { createDetailsBlockSchema, useRecordCollectionDataSourceItems } from '../../../../schema-initializer/utils'; +import { useRecordCollectionDataSourceItems } from '../../../../schema-initializer/utils'; +import { createDetailsUISchema } from './createDetailsUISchema'; export const RecordReadPrettyFormBlockInitializer = () => { const itemConfig = useSchemaInitializerItem(); @@ -24,29 +25,27 @@ export const RecordReadPrettyFormBlockInitializer = () => { }; export function useCreateSingleDetailsSchema() { - const itemConfig = useSchemaInitializerItem(); const { insert } = useSchemaInitializer(); const { getTemplateSchemaByMode } = useSchemaTemplateManager(); const association = useBlockAssociationContext(); - const { block } = useBlockRequestContext(); - const actionInitializers = - block !== 'TableField' ? itemConfig.actionInitializers || 'details:configureActions' : null; const templateWrap = useCallback( (templateSchema, options) => { const { item } = options; if (item.template.componentName === 'ReadPrettyFormItem') { - const blockSchema = createDetailsBlockSchema({ - actionInitializers, - association, - collection: item.collectionName || item.name, - dataSource: item.dataSource, - action: 'get', - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - template: templateSchema, - settings: 'blockSettings:singleDataDetails', - }); + const blockSchema = createDetailsUISchema( + association + ? { + association, + dataSource: item.dataSource, + templateSchema: templateSchema, + } + : { + collectionName: item.collectionName || item.name, + dataSource: item.dataSource, + templateSchema: templateSchema, + }, + ); if (item.mode === 'reference') { blockSchema['x-template-key'] = item.template.key; } @@ -55,7 +54,7 @@ export function useCreateSingleDetailsSchema() { return templateSchema; } }, - [actionInitializers, association], + [association], ); const createSingleDetailsSchema = useCallback( @@ -65,20 +64,21 @@ export function useCreateSingleDetailsSchema() { insert(templateWrap(template, { item })); } else { insert( - createDetailsBlockSchema({ - actionInitializers, - association, - collection: item.collectionName || item.name, - dataSource: item.dataSource, - action: 'get', - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - settings: 'blockSettings:singleDataDetails', - }), + createDetailsUISchema( + association + ? { + association, + dataSource: item.dataSource, + } + : { + collectionName: item.collectionName || item.name, + dataSource: item.dataSource, + }, + ), ); } }, - [actionInitializers, association, getTemplateSchemaByMode, insert, templateWrap], + [association, getTemplateSchemaByMode, insert, templateWrap], ); return { createSingleDetailsSchema, templateWrap }; diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-single/__tests__/createDetailsBlockWithoutPagingUISchema.test.ts b/packages/core/client/src/modules/blocks/data-blocks/details-single/__tests__/createDetailsBlockWithoutPagingUISchema.test.ts new file mode 100644 index 000000000..520789160 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/details-single/__tests__/createDetailsBlockWithoutPagingUISchema.test.ts @@ -0,0 +1,62 @@ +import { createDetailsUISchema } from '../createDetailsUISchema'; + +// Mock uid to always return a fixed value +vi.mock('@formily/shared', () => ({ + uid: () => 'fixed-uid', +})); + +describe('createDetailsBlockWithoutPagingUISchema', () => { + it('should create a valid schema with mandatory fields', () => { + const options = { + collectionName: 'users', + dataSource: 'usersDataSource', + }; + + const result = createDetailsUISchema(options); + expect(result).toMatchInlineSnapshot(` + { + "properties": { + "fixed-uid": { + "properties": { + "fixed-uid": { + "properties": {}, + "type": "void", + "x-component": "ActionBar", + "x-component-props": { + "style": { + "marginBottom": 24, + }, + }, + "x-initializer": "details:configureActions", + }, + "grid": { + "properties": {}, + "type": "void", + "x-component": "Grid", + "x-initializer": "details:configureFields", + }, + }, + "type": "void", + "x-component": "Details", + "x-read-pretty": true, + "x-use-component-props": "useDetailsProps", + }, + }, + "type": "void", + "x-acl-action": "users:get", + "x-component": "CardItem", + "x-decorator": "DetailsBlockProvider", + "x-decorator-props": { + "action": "get", + "association": undefined, + "collection": "users", + "dataSource": "usersDataSource", + "readPretty": true, + }, + "x-settings": "blockSettings:details", + "x-toolbar": "BlockSchemaToolbar", + "x-use-decorator-props": "useDetailsDecoratorProps", + } + `); + }); +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-single/createDetailsUISchema.ts b/packages/core/client/src/modules/blocks/data-blocks/details-single/createDetailsUISchema.ts new file mode 100644 index 000000000..963c489e8 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/details-single/createDetailsUISchema.ts @@ -0,0 +1,60 @@ +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; + +export function createDetailsUISchema(options: { + dataSource: string; + collectionName?: string; + association?: string; + templateSchema?: ISchema; +}): ISchema { + const { collectionName, dataSource, association, templateSchema } = options; + const resourceName = association || collectionName; + + if (!dataSource) { + throw new Error('dataSource are required'); + } + + return { + type: 'void', + 'x-acl-action': `${resourceName}:get`, + 'x-decorator': 'DetailsBlockProvider', + 'x-use-decorator-props': 'useDetailsDecoratorProps', + 'x-decorator-props': { + dataSource, + collection: collectionName, + association, + readPretty: true, + action: 'get', + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:details', + 'x-component': 'CardItem', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Details', + 'x-read-pretty': true, + 'x-use-component-props': 'useDetailsProps', + properties: { + [uid()]: { + type: 'void', + 'x-initializer': 'details:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + properties: {}, + }, + grid: templateSchema || { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'details:configureFields', + properties: {}, + }, + }, + }, + }, + }; +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-single/detailsBlockSettings.ts b/packages/core/client/src/modules/blocks/data-blocks/details-single/detailsBlockSettings.ts new file mode 100644 index 000000000..999109fff --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/details-single/detailsBlockSettings.ts @@ -0,0 +1,56 @@ +import { useFieldSchema } from '@formily/react'; +import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings'; +import { useCollection_deprecated } from '../../../../collection-manager'; +import { SchemaSettingsBlockTitleItem, SchemaSettingsFormItemTemplate } from '../../../../schema-settings'; +import { SchemaSettingsItemType } from '../../../../application/schema-settings/types'; + +const commonItems: SchemaSettingsItemType[] = [ + { + name: 'title', + Component: SchemaSettingsBlockTitleItem, + }, + { + name: 'formItemTemplate', + Component: SchemaSettingsFormItemTemplate, + useComponentProps() { + const { name } = useCollection_deprecated(); + const fieldSchema = useFieldSchema(); + const defaultResource = + fieldSchema?.['x-decorator-props']?.resource || fieldSchema?.['x-decorator-props']?.association; + return { + insertAdjacentPosition: 'beforeEnd', + componentName: 'ReadPrettyFormItem', + collectionName: name, + resourceName: defaultResource, + }; + }, + }, + { + name: 'divider', + type: 'divider', + }, + { + name: 'remove', + type: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + }, + }, +]; + +/** + * @deprecated + * 已弃用,请使用 detailsBlockSettings 代替 + */ +export const singleDataDetailsBlockSettings = new SchemaSettings({ + name: 'blockSettings:singleDataDetails', + items: commonItems, +}); + +export const detailsBlockSettings = new SchemaSettings({ + name: 'blockSettings:details', + items: commonItems, +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-single/hooks/useDetailsDecoratorProps.ts b/packages/core/client/src/modules/blocks/data-blocks/details-single/hooks/useDetailsDecoratorProps.ts new file mode 100644 index 000000000..71cd7e870 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/details-single/hooks/useDetailsDecoratorProps.ts @@ -0,0 +1,18 @@ +import { useParamsFromRecord } from '../../../../../block-provider/BlockProvider'; +import { useDataBlockSourceId } from '../../../../../block-provider/hooks/useDataBlockSourceId'; + +export function useDetailsDecoratorProps(props) { + const params = useParamsFromRecord(); + let sourceId; + + // association 的值是固定不变的,所以可以在条件中使用 hooks + if (props.association) { + // eslint-disable-next-line react-hooks/rules-of-hooks + sourceId = useDataBlockSourceId({ association: props.association }); + } + + return { + params, + sourceId, + }; +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-single/hooks/useDetailsProps.ts b/packages/core/client/src/modules/blocks/data-blocks/details-single/hooks/useDetailsProps.ts new file mode 100644 index 000000000..69bacd854 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/details-single/hooks/useDetailsProps.ts @@ -0,0 +1,5 @@ +import { useDetailsBlockProps } from '../../../../../block-provider/DetailsBlockProvider'; + +export function useDetailsProps() { + return useDetailsBlockProps(); +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-single/singleDataDetailsBlockSettings.ts b/packages/core/client/src/modules/blocks/data-blocks/details-single/singleDataDetailsBlockSettings.ts deleted file mode 100644 index c2bfdda96..000000000 --- a/packages/core/client/src/modules/blocks/data-blocks/details-single/singleDataDetailsBlockSettings.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { useFieldSchema } from '@formily/react'; -import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings'; -import { useCollection_deprecated } from '../../../../collection-manager'; -import { SchemaSettingsBlockTitleItem, SchemaSettingsFormItemTemplate } from '../../../../schema-settings'; - -export const singleDataDetailsBlockSettings = new SchemaSettings({ - name: 'blockSettings:singleDataDetails', - items: [ - { - name: 'title', - Component: SchemaSettingsBlockTitleItem, - }, - { - name: 'formItemTemplate', - Component: SchemaSettingsFormItemTemplate, - useComponentProps() { - const { name } = useCollection_deprecated(); - const fieldSchema = useFieldSchema(); - const defaultResource = - fieldSchema?.['x-decorator-props']?.resource || fieldSchema?.['x-decorator-props']?.association; - return { - insertAdjacentPosition: 'beforeEnd', - componentName: 'ReadPrettyFormItem', - collectionName: name, - resourceName: defaultResource, - }; - }, - }, - { - name: 'divider', - type: 'divider', - }, - { - name: 'remove', - type: 'remove', - componentProps: { - removeParentsIfNoChildren: true, - breakRemoveOn: { - 'x-component': 'Grid', - }, - }, - }, - ], -}); diff --git a/packages/core/client/src/modules/dialog/__e2e__/schemaInitializer.test.ts b/packages/core/client/src/modules/dialog/__e2e__/schemaInitializer.test.ts index 210eb77e0..0d7879d7f 100644 --- a/packages/core/client/src/modules/dialog/__e2e__/schemaInitializer.test.ts +++ b/packages/core/client/src/modules/dialog/__e2e__/schemaInitializer.test.ts @@ -88,7 +88,7 @@ test.describe('where to open a popup and what can be added to it', () => { // 删除已创建的 blocks,腾出页面空间 // delete details block await page.getByText('GeneralConfigure actionsConfigure fields').hover(); - await page.getByLabel('designer-schema-settings-CardItem-blockSettings:singleDataDetails-general').hover(); + await page.getByLabel('designer-schema-settings-CardItem-blockSettings:details-general').hover(); await page.getByRole('menuitem', { name: 'Delete' }).click(); await page.getByRole('button', { name: 'OK', exact: true }).click(); // delete form block diff --git a/packages/core/client/src/schema-component/antd/details/Details.tsx b/packages/core/client/src/schema-component/antd/details/Details.tsx index 06bf20f36..d1641a71e 100644 --- a/packages/core/client/src/schema-component/antd/details/Details.tsx +++ b/packages/core/client/src/schema-component/antd/details/Details.tsx @@ -3,8 +3,9 @@ import { FormV2 } from '../form-v2'; import _ from 'lodash'; import { Empty } from 'antd'; import { useDataBlockRequest } from '../../../data-source'; +import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; -export const Details = (props) => { +export const Details = withDynamicSchemaProps((props) => { const request = useDataBlockRequest(); if (!request?.loading && _.isEmpty(request?.data?.data)) { @@ -12,4 +13,4 @@ export const Details = (props) => { } return ; -}; +}); diff --git a/packages/core/client/src/schema-component/antd/pagination/__tests__/pagination.test.tsx b/packages/core/client/src/schema-component/antd/pagination/__tests__/pagination.test.tsx deleted file mode 100644 index 5652edcc2..000000000 --- a/packages/core/client/src/schema-component/antd/pagination/__tests__/pagination.test.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { render } from '@nocobase/test/client'; -import React from 'react'; -import { Pagination } from '../index'; - -describe('Pagination', () => { - it('should render correctly', () => { - render(); - expect(document.querySelector('.ant-pagination')).toBeInTheDocument(); - }); - - it('hidden', () => { - render(