diff --git a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx index 8e3c7c1eb..fb6df402f 100644 --- a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx +++ b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx @@ -1,9 +1,14 @@ import React from 'react'; import { Plugin } from '../application/Plugin'; import { ActionSchemaToolbar } from '../modules/actions/ActionSchemaToolbar'; -import { CollapseItemSchemaToolbar } from '../modules/blocks/filter-blocks/collapse/CollapseItemSchemaToolbar'; +import { BlockSchemaToolbar } from '../modules/blocks/BlockSchemaToolbar'; import { FormItemSchemaToolbar } from '../modules/blocks/data-blocks/form/FormItemSchemaToolbar'; +import { useCreateFormBlockDecoratorProps } from '../modules/blocks/data-blocks/form/hooks/useCreateFormBlockDecoratorProps'; +import { useCreateFormBlockProps } from '../modules/blocks/data-blocks/form/hooks/useCreateFormBlockProps'; +import { useEditFormBlockDecoratorProps } from '../modules/blocks/data-blocks/form/hooks/useEditFormBlockDecoratorProps'; +import { useEditFormBlockProps } from '../modules/blocks/data-blocks/form/hooks/useEditFormBlockProps'; import { TableColumnSchemaToolbar } from '../modules/blocks/data-blocks/table/TableColumnSchemaToolbar'; +import { CollapseItemSchemaToolbar } from '../modules/blocks/filter-blocks/collapse/CollapseItemSchemaToolbar'; import { SchemaComponentOptions } from '../schema-component'; import { RecordLink, useParamsFromRecord, useSourceIdFromParentRecord, useSourceIdFromRecord } from './BlockProvider'; import { DetailsBlockProvider, useDetailsBlockProps } from './DetailsBlockProvider'; @@ -15,7 +20,6 @@ import { useTableBlockProps } from '../modules/blocks/data-blocks/table/hooks/us import { TableFieldProvider, useTableFieldProps } from './TableFieldProvider'; import { TableSelectorProvider, useTableSelectorProps } from './TableSelectorProvider'; import * as bp from './hooks'; -import { BlockSchemaToolbar } from '../modules/blocks/BlockSchemaToolbar'; import { useTableBlockDecoratorProps } from '../modules/blocks/data-blocks/table/hooks/useTableBlockDecoratorProps'; // TODO: delete this, replaced by `BlockSchemaComponentPlugin` @@ -38,6 +42,10 @@ export const BlockSchemaComponentProvider: React.FC = (props) => { useSourceIdFromParentRecord, useParamsFromRecord, useFormBlockProps, + useCreateFormBlockProps, + useCreateFormBlockDecoratorProps, + useEditFormBlockDecoratorProps, + useEditFormBlockProps, useFormFieldProps, useDetailsBlockProps, useTableFieldProps, @@ -82,6 +90,10 @@ export class BlockSchemaComponentPlugin extends Plugin { useSourceIdFromParentRecord, useParamsFromRecord, useFormBlockProps, + useCreateFormBlockProps, + useCreateFormBlockDecoratorProps, + useEditFormBlockDecoratorProps, + useEditFormBlockProps, useFormFieldProps, useDetailsBlockProps, useTableFieldProps, diff --git a/packages/core/client/src/block-provider/FormBlockProvider.tsx b/packages/core/client/src/block-provider/FormBlockProvider.tsx index 7ac794662..1ebbb0584 100644 --- a/packages/core/client/src/block-provider/FormBlockProvider.tsx +++ b/packages/core/client/src/block-provider/FormBlockProvider.tsx @@ -10,6 +10,7 @@ import { Templates as DataTemplateSelect } from '../schema-component/antd/form-v import { BlockProvider, useBlockRequestContext } from './BlockProvider'; import { TemplateBlockProvider } from './TemplateBlockProvider'; import { FormActiveFieldsProvider } from './hooks/useFormActiveFields'; +import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps'; export const FormBlockContext = createContext<{ form?: any; @@ -29,7 +30,7 @@ FormBlockContext.displayName = 'FormBlockContext'; const InternalFormBlockProvider = (props) => { const ctx = useFormBlockContext(); - const { action, readPretty, params, association, collection } = props; + const { action, readPretty, params, collection } = props; const field = useField(); const form = useMemo( () => @@ -89,7 +90,7 @@ export const useIsDetailBlock = () => { return ctx.type !== 'create' && fieldSchema?.['x-acl-action'] !== 'create' && fieldSchema?.['x-action'] !== 'create'; }; -export const FormBlockProvider = (props) => { +export const FormBlockProvider = withDynamicSchemaProps((props) => { const record = useRecord(); const parentRecordData = useCollectionParentRecordData(); const { collection, isCusomeizeCreate } = props; @@ -120,7 +121,7 @@ export const FormBlockProvider = (props) => { ); -}; +}); export const useFormBlockContext = () => { return useContext(FormBlockContext); diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/CreateFormBlockInitializer.tsx b/packages/core/client/src/modules/blocks/data-blocks/form/CreateFormBlockInitializer.tsx index 68614c002..d5728269c 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/CreateFormBlockInitializer.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/form/CreateFormBlockInitializer.tsx @@ -4,8 +4,9 @@ import React from 'react'; import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; import { useBlockAssociationContext } from '../../../../block-provider'; import { useCollection_deprecated } from '../../../../collection-manager'; +import { useRecordCollectionDataSourceItems } from '../../../../schema-initializer/utils'; import { useSchemaTemplateManager } from '../../../../schema-templates'; -import { createFormBlockSchema, useRecordCollectionDataSourceItems } from '../../../../schema-initializer/utils'; +import { createCreateFormBlockUISchema } from './createCreateFormBlockUISchema'; // TODO: `SchemaInitializerItem` items export const CreateFormBlockInitializer = () => { @@ -23,14 +24,19 @@ export const CreateFormBlockInitializer = () => { if (item.template) { const s = await getTemplateSchemaByMode(item); if (item.template.componentName === 'FormItem') { - const blockSchema = createFormBlockSchema({ - actionInitializers: 'createForm:configureActions', - association, - dataSource: collection.dataSource, - collection: collection.name, - template: s, - settings: 'blockSettings:createForm', - }); + const blockSchema = createCreateFormBlockUISchema( + association + ? { + association, + dataSource: collection.dataSource, + templateSchema: s, + } + : { + collectionName: collection.name, + dataSource: collection.dataSource, + templateSchema: s, + }, + ); if (item.mode === 'reference') { blockSchema['x-template-key'] = item.template.key; } @@ -40,13 +46,17 @@ export const CreateFormBlockInitializer = () => { } } else { insert( - createFormBlockSchema({ - actionInitializers: 'createForm:configureActions', - association, - dataSource: collection.dataSource, - collection: collection.name, - settings: 'blockSettings:createForm', - }), + createCreateFormBlockUISchema( + association + ? { + association, + dataSource: collection.dataSource, + } + : { + collectionName: collection.name, + dataSource: collection.dataSource, + }, + ), ); } }} diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/FormBlockInitializer.tsx b/packages/core/client/src/modules/blocks/data-blocks/form/FormBlockInitializer.tsx index 5ea124e2e..e86edbbdd 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/FormBlockInitializer.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/form/FormBlockInitializer.tsx @@ -1,9 +1,9 @@ import { FormOutlined } from '@ant-design/icons'; import React, { useCallback } from 'react'; import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; -import { createFormBlockSchema } from '../../../../schema-initializer/utils'; -import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer'; import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection'; +import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer'; +import { createCreateFormBlockUISchema } from './createCreateFormBlockUISchema'; export const FormBlockInitializer = ({ filterCollections, @@ -44,11 +44,10 @@ export const FormBlockInitializer = ({ } insert( - createFormBlockSchema({ - collection: item.collectionName || item.name, + createCreateFormBlockUISchema({ + collectionName: item.collectionName || item.name, dataSource: item.dataSource, isCusomeizeCreate, - settings: 'blockSettings:createForm', }), ); }, @@ -65,12 +64,11 @@ export const FormBlockInitializer = ({ return templateWrap(templateSchema, { item }); } - const schema = createFormBlockSchema({ + const schema = createCreateFormBlockUISchema({ isCusomeizeCreate, dataSource: item.dataSource, - template: templateSchema, - collection: item.name, - settings: 'blockSettings:createForm', + templateSchema: templateSchema, + collectionName: item.name, }); if (item.template && item.mode === 'reference') { schema['x-template-key'] = item.template.key; diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/RecordFormBlockInitializer.tsx b/packages/core/client/src/modules/blocks/data-blocks/form/RecordFormBlockInitializer.tsx index a080b596d..c207b7550 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/RecordFormBlockInitializer.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/form/RecordFormBlockInitializer.tsx @@ -3,8 +3,9 @@ import React, { useCallback } from 'react'; import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; import { useBlockAssociationContext } from '../../../../block-provider'; import { useCollection_deprecated } from '../../../../collection-manager'; +import { useRecordCollectionDataSourceItems } from '../../../../schema-initializer/utils'; import { useSchemaTemplateManager } from '../../../../schema-templates'; -import { createFormBlockSchema, useRecordCollectionDataSourceItems } from '../../../../schema-initializer/utils'; +import { createEditFormBlockUISchema } from './createEditFormBlockUISchema'; /** * @deprecated @@ -43,16 +44,17 @@ export function useCreateEditFormBlock() { const createEditFormBlock = useCallback( ({ item }) => { insert( - createFormBlockSchema({ - association, - collection: item.collectionName || item.name, - dataSource: item.dataSource, - action: 'get', - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - actionInitializers: 'editForm:configureActions', - settings: 'blockSettings:editForm', - }), + createEditFormBlockUISchema( + association + ? { + association, + dataSource: item.dataSource, + } + : { + collectionName: item.collectionName || item.name, + dataSource: item.dataSource, + }, + ), ); }, [association, insert], @@ -61,17 +63,19 @@ export function useCreateEditFormBlock() { const templateWrap = useCallback( (templateSchema, { item }) => { if (item.template.componentName === 'FormItem') { - const blockSchema = createFormBlockSchema({ - association, - collection: item.collectionName || item.name, - dataSource: item.dataSource, - action: 'get', - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - actionInitializers: 'editForm:configureActions', - template: templateSchema, - settings: 'blockSettings:editForm', - }); + const blockSchema = createEditFormBlockUISchema( + 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; } diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__tests__/createCreateFormBlockUISchema.test.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__tests__/createCreateFormBlockUISchema.test.ts new file mode 100644 index 000000000..e1daebb3b --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__tests__/createCreateFormBlockUISchema.test.ts @@ -0,0 +1,64 @@ +import { CreateFormBlockUISchemaOptions, createCreateFormBlockUISchema } from '../createCreateFormBlockUISchema'; + +vi.mock('@formily/shared', () => { + return { + uid: () => 'mocked-uid', + }; +}); + +describe('createCreateFormBlockUISchema', () => { + it('should create a schema with all options', () => { + const options: CreateFormBlockUISchemaOptions = { + collectionName: 'users', + dataSource: 'userDataSource', + association: 'userAssociation', + templateSchema: { type: 'string' }, + isCusomeizeCreate: true, + }; + + const result = createCreateFormBlockUISchema(options); + expect(result).toMatchInlineSnapshot(` + { + "properties": { + "mocked-uid": { + "properties": { + "grid": { + "type": "string", + }, + "mocked-uid": { + "type": "void", + "x-component": "ActionBar", + "x-component-props": { + "layout": "one-column", + "style": { + "marginTop": 24, + }, + }, + "x-initializer": "createForm:configureActions", + }, + }, + "type": "void", + "x-component": "FormV2", + "x-use-component-props": "useCreateFormBlockProps", + }, + }, + "type": "void", + "x-acl-action": "userAssociation:create", + "x-acl-action-props": { + "skipScopeCheck": true, + }, + "x-component": "CardItem", + "x-decorator": "FormBlockProvider", + "x-decorator-props": { + "association": "userAssociation", + "collection": "users", + "dataSource": "userDataSource", + "isCusomeizeCreate": true, + }, + "x-settings": "blockSettings:createForm", + "x-toolbar": "BlockSchemaToolbar", + "x-use-decorator-props": "useCreateFormBlockDecoratorProps", + } + `); + }); +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__tests__/createEditFormBlockUISchema.test.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__tests__/createEditFormBlockUISchema.test.ts new file mode 100644 index 000000000..8082b18d3 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__tests__/createEditFormBlockUISchema.test.ts @@ -0,0 +1,62 @@ +import { ISchema } from '@formily/react'; +import { vi } from 'vitest'; +import { createEditFormBlockUISchema } from '../createEditFormBlockUISchema'; + +vi.mock('@formily/shared', () => ({ + uid: () => 'uniqueId', +})); + +describe('createEditFormBlockUISchema', () => { + it('should create a schema with all options', () => { + const schema = createEditFormBlockUISchema({ + collectionName: 'users', + dataSource: 'UserDataSource', + association: 'users:update', + templateSchema: { type: 'string' }, + }); + + expect(schema).toMatchInlineSnapshot(` + { + "properties": { + "uniqueId": { + "properties": { + "grid": { + "type": "string", + }, + "uniqueId": { + "type": "void", + "x-component": "ActionBar", + "x-component-props": { + "layout": "one-column", + "style": { + "marginTop": 24, + }, + }, + "x-initializer": "editForm:configureActions", + }, + }, + "type": "void", + "x-component": "FormV2", + "x-use-component-props": "useEditFormBlockProps", + }, + }, + "type": "void", + "x-acl-action": "users:update:update", + "x-acl-action-props": { + "skipScopeCheck": false, + }, + "x-component": "CardItem", + "x-decorator": "FormBlockProvider", + "x-decorator-props": { + "action": "get", + "association": "users:update", + "collection": "users", + "dataSource": "UserDataSource", + }, + "x-settings": "blockSettings:editForm", + "x-toolbar": "BlockSchemaToolbar", + "x-use-decorator-props": "useEditFormBlockDecoratorProps", + } + `); + }); +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/createCreateFormBlockUISchema.ts b/packages/core/client/src/modules/blocks/data-blocks/form/createCreateFormBlockUISchema.ts new file mode 100644 index 000000000..cd399656e --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/createCreateFormBlockUISchema.ts @@ -0,0 +1,70 @@ +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; + +export interface CreateFormBlockUISchemaOptions { + dataSource: string; + /** 如果传了 association 就不需要再传 collectionName 了 */ + collectionName?: string; + association?: string; + templateSchema?: ISchema; + isCusomeizeCreate?: boolean; +} + +/** + * 创建新增表单的 UI Schema + * @returns + */ +export function createCreateFormBlockUISchema(options: CreateFormBlockUISchemaOptions): ISchema { + const { collectionName, association, dataSource, templateSchema, isCusomeizeCreate } = options; + const resourceName = association || collectionName; + + if (!dataSource) { + throw new Error('dataSource are required'); + } + + const schema: ISchema = { + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': `${resourceName}:create`, + 'x-decorator': 'FormBlockProvider', + 'x-use-decorator-props': 'useCreateFormBlockDecoratorProps', + 'x-decorator-props': { + dataSource, + collection: collectionName, + association, + isCusomeizeCreate, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:createForm', + 'x-component': 'CardItem', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'FormV2', + 'x-use-component-props': 'useCreateFormBlockProps', + properties: { + grid: templateSchema || { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'form:configureFields', + properties: {}, + }, + [uid()]: { + type: 'void', + 'x-initializer': 'createForm:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + }, + }, + }, + }, + }; + return schema; +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/createEditFormBlockUISchema.ts b/packages/core/client/src/modules/blocks/data-blocks/form/createEditFormBlockUISchema.ts new file mode 100644 index 000000000..509b0183b --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/createEditFormBlockUISchema.ts @@ -0,0 +1,64 @@ +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; + +interface EditFormBlockOptions { + dataSource: string; + /** 如果传了 association 就不需要再传 collectionName 了 */ + collectionName?: string; + association?: string; + templateSchema?: ISchema; +} + +export function createEditFormBlockUISchema(options: EditFormBlockOptions): 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-props': { + skipScopeCheck: false, + }, + 'x-acl-action': `${resourceName}:update`, + 'x-decorator': 'FormBlockProvider', + 'x-use-decorator-props': 'useEditFormBlockDecoratorProps', + 'x-decorator-props': { + action: 'get', + dataSource, + collection: collectionName, + association, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:editForm', + 'x-component': 'CardItem', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'FormV2', + 'x-use-component-props': 'useEditFormBlockProps', + properties: { + grid: templateSchema || { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'form:configureFields', + properties: {}, + }, + [uid()]: { + type: 'void', + 'x-initializer': 'editForm:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + }, + }, + }, + }, + }; +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useCreateFormBlockDecoratorProps.ts b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useCreateFormBlockDecoratorProps.ts new file mode 100644 index 000000000..d0e78303c --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useCreateFormBlockDecoratorProps.ts @@ -0,0 +1,15 @@ +import { useFormBlockSourceId } from './useFormBlockSourceId'; + +export function useCreateFormBlockDecoratorProps(props) { + let sourceId; + + // association 的值是固定不变的,所以这里可以使用 hooks + if (props.association) { + // eslint-disable-next-line react-hooks/rules-of-hooks + sourceId = useFormBlockSourceId(props); + } + + return { + sourceId, + }; +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useCreateFormBlockProps.ts b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useCreateFormBlockProps.ts new file mode 100644 index 000000000..992e8ed52 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useCreateFormBlockProps.ts @@ -0,0 +1,5 @@ +import { useFormBlockProps } from '../../../../../block-provider/FormBlockProvider'; + +export function useCreateFormBlockProps() { + return useFormBlockProps(); +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useEditFormBlockDecoratorProps.ts b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useEditFormBlockDecoratorProps.ts new file mode 100644 index 000000000..af759e656 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useEditFormBlockDecoratorProps.ts @@ -0,0 +1,22 @@ +import { useParamsFromRecord } from '../../../../../block-provider/BlockProvider'; +import { useFormBlockSourceId } from './useFormBlockSourceId'; + +export function useEditFormBlockDecoratorProps(props) { + const params = useFormBlockParams(); + let sourceId; + + // association 的值是固定不变的,所以这里可以使用 hooks + if (props.association) { + // eslint-disable-next-line react-hooks/rules-of-hooks + sourceId = useFormBlockSourceId(props); + } + + return { + params, + sourceId, + }; +} + +function useFormBlockParams() { + return useParamsFromRecord(); +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useEditFormBlockProps.ts b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useEditFormBlockProps.ts new file mode 100644 index 000000000..840a02da1 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useEditFormBlockProps.ts @@ -0,0 +1,5 @@ +import { useFormBlockProps } from '../../../../../block-provider/FormBlockProvider'; + +export function useEditFormBlockProps() { + return useFormBlockProps(); +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useFormBlockSourceId.ts b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useFormBlockSourceId.ts new file mode 100644 index 000000000..5863c1d6f --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useFormBlockSourceId.ts @@ -0,0 +1,5 @@ +import { useDataBlockSourceId } from '../../../../../block-provider/hooks/useDataBlockSourceId'; + +export function useFormBlockSourceId(props) { + return useDataBlockSourceId(props); +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/index.ts b/packages/core/client/src/modules/blocks/data-blocks/form/index.ts index b78f5584f..4e579df30 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/index.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/form/index.ts @@ -1,11 +1,12 @@ -export * from './createFormBlockSettings'; export * from './CreateFormBlockInitializer'; export * from './FormBlockInitializer'; export * from './FormItemSchemaToolbar'; export * from './RecordFormBlockInitializer'; -export * from './editFormBlockSettings'; +export * from './createCreateFormBlockUISchema'; export * from './createFormActionInitializers'; +export * from './createFormBlockSettings'; +export * from './editFormBlockSettings'; +export * from './fieldSettingsFormItem'; export * from './formActionInitializers'; export * from './formItemInitializers'; -export * from './fieldSettingsFormItem'; export * from './updateFormActionInitializers'; 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 14025ff9b..06bf20f36 100644 --- a/packages/core/client/src/schema-component/antd/details/Details.tsx +++ b/packages/core/client/src/schema-component/antd/details/Details.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { FormV2 } from '../form-v2'; -import { useDetailsBlockContext } from '../../../block-provider/DetailsBlockProvider'; import _ from 'lodash'; import { Empty } from 'antd'; import { useDataBlockRequest } from '../../../data-source'; diff --git a/packages/core/client/src/schema-component/antd/form-v2/Form.tsx b/packages/core/client/src/schema-component/antd/form-v2/Form.tsx index 763f28432..a3f381cd7 100644 --- a/packages/core/client/src/schema-component/antd/form-v2/Form.tsx +++ b/packages/core/client/src/schema-component/antd/form-v2/Form.tsx @@ -18,6 +18,7 @@ import { isVariable, REGEX_OF_VARIABLE } from '../../../variables/utils/isVariab import { getInnermostKeyAndValue, getTargetField } from '../../common/utils/uitls'; import { useProps } from '../../hooks/useProps'; import { collectFieldStateOfLinkageRules, getTempFieldState } from './utils'; +import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; export interface FormProps { [key: string]: any; @@ -197,10 +198,13 @@ export const Form: React.FC & { FilterDesigner?: any; ReadPrettyDesigner?: any; Templates?: any; -} = observer( - (props) => { +} = withDynamicSchemaProps( + observer((props) => { const field = useField(); + + // 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema const { form, disabled, ...others } = useProps(props); + const formDisabled = disabled || field.disabled; return ( @@ -222,7 +226,7 @@ export const Form: React.FC & { ); - }, + }), { displayName: 'Form' }, ); diff --git a/packages/core/client/src/schema-initializer/items/RecordAssociationFormBlockInitializer.tsx b/packages/core/client/src/schema-initializer/items/RecordAssociationFormBlockInitializer.tsx index 9b73c2ae4..a64df1e7f 100644 --- a/packages/core/client/src/schema-initializer/items/RecordAssociationFormBlockInitializer.tsx +++ b/packages/core/client/src/schema-initializer/items/RecordAssociationFormBlockInitializer.tsx @@ -1,10 +1,11 @@ -import React, { useCallback, useMemo } from 'react'; import { FormOutlined } from '@ant-design/icons'; +import React, { useCallback, useMemo } from 'react'; import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../application'; -import { useSchemaTemplateManager } from '../../schema-templates'; -import { createFormBlockSchema, useRecordCollectionDataSourceItems } from '../utils'; import { useCollectionManager_deprecated } from '../../collection-manager'; +import { createCreateFormBlockUISchema } from '../../modules/blocks/data-blocks/form/createCreateFormBlockUISchema'; +import { useSchemaTemplateManager } from '../../schema-templates'; +import { useRecordCollectionDataSourceItems } from '../utils'; /** * @deprecated @@ -18,31 +19,18 @@ export const RecordAssociationFormBlockInitializer = () => { const field = itemConfig.field; const collectionName = field.target; const collection = useMemo(() => getCollection(collectionName), [collectionName]); - const resource = `${field.collectionName}.${field.name}`; return ( } {...others} onClick={async ({ item }) => { - const action = ['hasOne', 'belongsTo'].includes(field.type) ? 'get' : null; - const actionInitializers = ['hasOne', 'belongsTo'].includes(field.type) - ? 'editForm:configureActions' - : 'createForm:configureActions'; - if (item.template) { const template = await getTemplateSchemaByMode(item); if (item.template.componentName === 'FormItem') { - const blockSchema = createFormBlockSchema({ - collection: collectionName, + const blockSchema = createCreateFormBlockUISchema({ dataSource: collection.dataSource, - resource, - association: resource, - action, - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - actionInitializers, - template: template, - settings: 'blockSettings:createForm', + association: `${field.collectionName}.${field.name}`, + templateSchema: template, }); if (item.mode === 'reference') { blockSchema['x-template-key'] = item.template.key; @@ -53,21 +41,19 @@ export const RecordAssociationFormBlockInitializer = () => { } } else { insert( - createFormBlockSchema({ - collection: collectionName, - resource, + createCreateFormBlockUISchema({ dataSource: collection.dataSource, - association: resource, - action, - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - actionInitializers, - settings: 'blockSettings:createForm', + association: `${field.collectionName}.${field.name}`, }), ); } }} - items={useRecordCollectionDataSourceItems('FormItem', itemConfig, collection, resource)} + items={useRecordCollectionDataSourceItems( + 'FormItem', + itemConfig, + collection, + `${field.collectionName}.${field.name}`, + )} /> ); }; @@ -80,21 +66,11 @@ export function useCreateAssociationFormBlock() { ({ item }) => { const field = item.associationField; const collection = getCollection(field.target); - const action = ['hasOne', 'belongsTo'].includes(field.type) ? 'get' : null; - const actionInitializers = ['hasOne', 'belongsTo'].includes(field.type) - ? 'editForm:configureActions' - : 'createForm:configureActions'; insert( - createFormBlockSchema({ - collection: field.target, + createCreateFormBlockUISchema({ dataSource: collection.dataSource, association: `${field.collectionName}.${field.name}`, - action, - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - actionInitializers, - settings: 'blockSettings:createForm', }), ); }, @@ -104,23 +80,13 @@ export function useCreateAssociationFormBlock() { const templateWrap = useCallback( (templateSchema, { item }) => { const field = item.associationField; - const action = ['hasOne', 'belongsTo'].includes(field.type) ? 'get' : null; const collection = getCollection(field.target); - const actionInitializers = ['hasOne', 'belongsTo'].includes(field.type) - ? 'editForm:configureActions' - : 'createForm:configureActions'; if (item.template.componentName === 'FormItem') { - const blockSchema = createFormBlockSchema({ - collection: field.target, + const blockSchema = createCreateFormBlockUISchema({ dataSource: collection.dataSource, association: `${field.collectionName}.${field.name}`, - action, - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - actionInitializers, - template: templateSchema, - settings: 'blockSettings:createForm', + templateSchema: templateSchema, }); if (item.mode === 'reference') { blockSchema['x-template-key'] = item.template.key; diff --git a/packages/core/client/src/schema-initializer/utils.ts b/packages/core/client/src/schema-initializer/utils.ts index 4a9fed7d8..b4778b082 100644 --- a/packages/core/client/src/schema-initializer/utils.ts +++ b/packages/core/client/src/schema-initializer/utils.ts @@ -1,6 +1,7 @@ import { Field, Form } from '@formily/core'; import { ISchema, Schema, useFieldSchema, useForm } from '@formily/react'; import { uid } from '@formily/shared'; +import _ from 'lodash'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { @@ -12,13 +13,12 @@ import { useFormActiveFields, useFormBlockContext, } from '../'; -import { FieldOptions, useCollection_deprecated, useCollectionManager_deprecated } from '../collection-manager'; +import { FieldOptions, useCollectionManager_deprecated, useCollection_deprecated } from '../collection-manager'; +import { Collection, CollectionFieldOptions } from '../data-source/collection/Collection'; +import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider'; import { isAssocField } from '../filter-provider/utils'; import { useActionContext, useCompile, useDesignable } from '../schema-component'; import { useSchemaTemplateManager } from '../schema-templates'; -import { Collection, CollectionFieldOptions } from '../data-source/collection/Collection'; -import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider'; -import _ from 'lodash'; export const itemsMerge = (items1) => { return items1; @@ -1150,7 +1150,28 @@ export const createGridCardBlockSchema = (options) => { }; return schema; }; -export const createFormBlockSchema = (options) => { + +/** + * @deprecated + * 已弃用,请使用 createCreateFormBlockUISchema 或者 createEditFormBlockUISchema 替代 + * @param options + * @returns + */ +export const createFormBlockSchema = (options: { + formItemInitializers?: string; + actionInitializers?: string; + collection: string; + resource?: string; + dataSource?: string; + association?: string; + action?: string; + actions?: Record; + template?: any; + title?: string; + settings?: any; + 'x-designer'?: string; + [key: string]: any; +}) => { const { formItemInitializers = 'form:configureFields', actionInitializers = 'createForm:configureActions', diff --git a/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/CreateFormBulkEditBlockInitializer.tsx b/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/CreateFormBulkEditBlockInitializer.tsx index f5afd1b22..ab2291b42 100644 --- a/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/CreateFormBulkEditBlockInitializer.tsx +++ b/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/CreateFormBulkEditBlockInitializer.tsx @@ -1,15 +1,16 @@ import { FormOutlined } from '@ant-design/icons'; -import React from 'react'; import { + SchemaInitializerItem, + createCreateFormBlockUISchema, useBlockAssociationContext, useCollection_deprecated, - useSchemaTemplateManager, - createFormBlockSchema, useRecordCollectionDataSourceItems, - SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem, + useSchemaTemplateManager, } from '@nocobase/client'; +import React from 'react'; +import { createBulkEditBlockUISchema } from './createBulkEditBlockUISchema'; export const CreateFormBulkEditBlockInitializer = () => { const itemConfig = useSchemaInitializerItem(); @@ -26,13 +27,19 @@ export const CreateFormBulkEditBlockInitializer = () => { if (item.template) { const s = await getTemplateSchemaByMode(item); if (item.template.componentName === 'FormItem') { - const blockSchema = createFormBlockSchema({ - actionInitializers: 'createForm:configureActions', - association, - collection: collection.name, - dataSource: collection.dataSource, - template: s, - }); + const blockSchema = createCreateFormBlockUISchema( + association + ? { + association, + dataSource: collection.dataSource, + templateSchema: s, + } + : { + collectionName: collection.name, + dataSource: collection.dataSource, + templateSchema: s, + }, + ); if (item.mode === 'reference') { blockSchema['x-template-key'] = item.template.key; } @@ -42,11 +49,9 @@ export const CreateFormBulkEditBlockInitializer = () => { } } else { insert( - createFormBlockSchema({ - formItemInitializers: 'bulkEditForm:configureFields', - actionInitializers: 'bulkEditForm:configureActions', + createBulkEditBlockUISchema({ association, - collection: collection.name, + collectionName: collection.name, dataSource: collection.dataSource, }), ); diff --git a/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/createBulkEditBlockUISchema.ts b/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/createBulkEditBlockUISchema.ts new file mode 100644 index 000000000..208e44e7b --- /dev/null +++ b/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/createBulkEditBlockUISchema.ts @@ -0,0 +1,65 @@ +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; + +/** + * 创建批量编辑表单的 UI Schema + * @returns + */ +export function createBulkEditBlockUISchema(options: { + collectionName: string; + dataSource: string; + association?: string; +}): ISchema { + const { collectionName, association, dataSource } = options; + const resourceName = association || collectionName; + + if (!collectionName || !dataSource) { + throw new Error('collectionName and dataSource are required'); + } + + const schema: ISchema = { + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': `${resourceName}:create`, + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + dataSource, + collection: collectionName, + association, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:createForm', + 'x-component': 'CardItem', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useCreateFormBlockProps }}', + }, + properties: { + grid: { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'bulkEditForm:configureFields', + properties: {}, + }, + [uid()]: { + type: 'void', + 'x-initializer': 'bulkEditForm:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + }, + }, + }, + }, + }; + return schema; +} diff --git a/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/FormBlockInitializer.tsx b/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/FormBlockInitializer.tsx index 5ee4fc513..19bd06e43 100644 --- a/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/FormBlockInitializer.tsx +++ b/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/FormBlockInitializer.tsx @@ -4,7 +4,6 @@ import { CollectionProvider_deprecated, SchemaInitializerItem, SchemaInitializerItemType, - createFormBlockSchema, useRecordCollectionDataSourceItems, useSchemaInitializer, useSchemaInitializerItem, @@ -14,6 +13,7 @@ import { import { JOB_STATUS, traverseSchema } from '@nocobase/plugin-workflow/client'; import { NAMESPACE } from '../../locale'; +import { createManualFormBlockUISchema } from './createManualFormBlockUISchema'; function InternalFormBlockInitializer({ schema, ...others }) { const { getTemplateSchemaByMode } = useSchemaTemplateManager(); @@ -21,7 +21,7 @@ function InternalFormBlockInitializer({ schema, ...others }) { const items = useRecordCollectionDataSourceItems('FormItem') as SchemaInitializerItemType[]; async function onConfirm({ item }) { const template = item.template ? await getTemplateSchemaByMode(item) : null; - const result = createFormBlockSchema({ + const result = createManualFormBlockUISchema({ actionInitializers: 'workflowManual:form:configureActions', actions: { resolve: { diff --git a/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/createManualFormBlockUISchema.ts b/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/createManualFormBlockUISchema.ts new file mode 100644 index 000000000..98841991f --- /dev/null +++ b/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/createManualFormBlockUISchema.ts @@ -0,0 +1,5 @@ +import { createFormBlockSchema } from '@nocobase/client'; + +export function createManualFormBlockUISchema(options) { + return createFormBlockSchema(options); +}