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 替代