feat: 多对多关系可以添加关联 (#1333)
Co-authored-by: sealday <zhanglin@daoyoucloud.com> Reviewed-on: daoyoucloud/tachybase#1333 Reviewed-by: sealday <zhanglin@daoyoucloud.com> Co-authored-by: wjh <wwwjh0710@163.com> Co-committed-by: wjh <wwwjh0710@163.com>
This commit is contained in:
parent
9dc412dbf3
commit
27cda38a90
@ -29,7 +29,6 @@ export const SchemaInitializerItem = memo(
|
||||
const childrenItems = useSchemaInitializerMenuItems(items, name, onClick);
|
||||
const { componentCls, hashId } = useSchemaInitializerStyles();
|
||||
const { attribute } = useAriaAttributeOfMenuItem();
|
||||
|
||||
const menuItems = useMemo(() => {
|
||||
if (!(items && items.length > 0)) return undefined;
|
||||
return [
|
||||
|
@ -1,14 +1,17 @@
|
||||
import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';
|
||||
import { createForm, RecursionField, Schema, useField, useFieldSchema } from '@tachybase/schema';
|
||||
import { createForm, Form, Schema, useField } from '@tachybase/schema';
|
||||
|
||||
import { Spin } from 'antd';
|
||||
|
||||
import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps';
|
||||
import { useCollection_deprecated } from '../collection-manager';
|
||||
import { CollectionRecord, useCollectionParentRecordData, useCollectionRecord } from '../data-source';
|
||||
import {
|
||||
CollectionRecord,
|
||||
useCollectionManager,
|
||||
useCollectionParentRecordData,
|
||||
useCollectionRecord,
|
||||
} from '../data-source';
|
||||
import { RecordProvider, useRecord } from '../record-provider';
|
||||
import { useActionContext, useDesignable } from '../schema-component';
|
||||
import { Templates as DataTemplateSelect } from '../schema-component/antd/form-v2/Templates';
|
||||
import { useActionContext } from '../schema-component';
|
||||
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
|
||||
import { FormActiveFieldsProvider } from './hooks/useFormActiveFields';
|
||||
|
||||
@ -29,8 +32,9 @@ export const FormBlockContext = createContext<{
|
||||
FormBlockContext.displayName = 'FormBlockContext';
|
||||
|
||||
const InternalFormBlockProvider = (props) => {
|
||||
const cm = useCollectionManager();
|
||||
const ctx = useFormBlockContext();
|
||||
const { action, readPretty, params, collection } = props;
|
||||
const { action, readPretty, params, collection, association } = props;
|
||||
const field = useField();
|
||||
const form = useMemo(
|
||||
() =>
|
||||
@ -55,10 +59,23 @@ const InternalFormBlockProvider = (props) => {
|
||||
resource,
|
||||
updateAssociationValues,
|
||||
formBlockRef,
|
||||
collectionName: collection,
|
||||
collectionName: collection || cm.getCollectionField(association)?.target,
|
||||
formRecord: record,
|
||||
};
|
||||
}, [action, collection, ctx, field, form, params, record, resource, service, updateAssociationValues]);
|
||||
}, [
|
||||
action,
|
||||
association,
|
||||
cm,
|
||||
collection,
|
||||
ctx,
|
||||
field,
|
||||
form,
|
||||
params,
|
||||
record,
|
||||
resource,
|
||||
service,
|
||||
updateAssociationValues,
|
||||
]);
|
||||
|
||||
if (service.loading && Object.keys(form?.initialValues)?.length === 0 && action) {
|
||||
return <Spin />;
|
||||
@ -67,21 +84,24 @@ const InternalFormBlockProvider = (props) => {
|
||||
return (
|
||||
<FormBlockContext.Provider value={formBlockValue}>
|
||||
<RecordProvider isNew={record?.isNew} parent={record?.parentRecord?.data} record={record?.data}>
|
||||
<div ref={formBlockRef}>
|
||||
<RenderChildrenWithDataTemplates form={form} />
|
||||
</div>
|
||||
<div ref={formBlockRef}>{props.children}</div>
|
||||
</RecordProvider>
|
||||
</FormBlockContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* 获取表单区块的类型:update 表示是表单编辑区块,create 表示是表单新增区块
|
||||
* @returns
|
||||
*/
|
||||
export const useFormBlockType = () => {
|
||||
const ctx = useFormBlockContext() || {};
|
||||
const res = useMemo(() => {
|
||||
return { type: ctx.type } as { type: 'update' | 'create' };
|
||||
}, [ctx.type]);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
export const useIsDetailBlock = () => {
|
||||
@ -91,26 +111,8 @@ export const useIsDetailBlock = () => {
|
||||
};
|
||||
|
||||
export const FormBlockProvider = withDynamicSchemaProps((props) => {
|
||||
const record = useRecord();
|
||||
const parentRecordData = useCollectionParentRecordData();
|
||||
const { collection, isCusomeizeCreate, parentRecord } = props;
|
||||
const { __collection } = record;
|
||||
const currentCollection = useCollection_deprecated();
|
||||
const { designable } = useDesignable();
|
||||
const isDetailBlock = useIsDetailBlock();
|
||||
let detailFlag = false;
|
||||
if (isDetailBlock) {
|
||||
detailFlag = true;
|
||||
if (!designable && __collection) {
|
||||
detailFlag = __collection === collection;
|
||||
}
|
||||
}
|
||||
const createFlag =
|
||||
(currentCollection.name === (collection?.name || collection) && !isDetailBlock) || !currentCollection.name;
|
||||
|
||||
if (!detailFlag && !createFlag && !isCusomeizeCreate) {
|
||||
return null;
|
||||
}
|
||||
const { parentRecord } = props;
|
||||
|
||||
return (
|
||||
<BlockProvider
|
||||
@ -126,11 +128,18 @@ export const FormBlockProvider = withDynamicSchemaProps((props) => {
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @returns
|
||||
*/
|
||||
export const useFormBlockContext = () => {
|
||||
return useContext(FormBlockContext);
|
||||
};
|
||||
|
||||
export const useFormBlockProps = () => {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const useFormBlockProps = (shouldClearInitialValues = false) => {
|
||||
const ctx = useFormBlockContext();
|
||||
const record = useRecord();
|
||||
const { fieldSchema } = useActionContext();
|
||||
@ -154,19 +163,9 @@ export const useFormBlockProps = () => {
|
||||
};
|
||||
};
|
||||
|
||||
const RenderChildrenWithDataTemplates = ({ form }) => {
|
||||
const FieldSchema = useFieldSchema();
|
||||
const { findComponent } = useDesignable();
|
||||
const field = useField();
|
||||
const Component = findComponent(field.component?.[0]) || React.Fragment;
|
||||
return (
|
||||
<Component {...field.componentProps}>
|
||||
<DataTemplateSelect style={{ marginBottom: 18 }} form={form} />
|
||||
<RecursionField schema={FieldSchema} onlyRenderProperties />
|
||||
</Component>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const findFormBlock = (schema: Schema) => {
|
||||
while (schema) {
|
||||
if (schema['x-decorator'] === 'FormBlockProvider') {
|
||||
|
@ -236,6 +236,9 @@ export const ACLActionProvider = (props) => {
|
||||
if (!actionPath) {
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
if (!resource) {
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
const params = parseAction(actionPath, { schema, recordPkValue });
|
||||
if (!params) {
|
||||
return <ACLActionParamsContext.Provider value={params}>{props.children}</ACLActionParamsContext.Provider>;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { createContext, FC, ReactNode, useContext } from 'react';
|
||||
|
||||
import { CollectionFieldProvider } from '../collection-field';
|
||||
import { CollectionFieldProvider, useCollectionField } from '../collection-field';
|
||||
import { CollectionDeletedPlaceholder } from '../components/CollectionDeletedPlaceholder';
|
||||
import { Collection } from './Collection';
|
||||
import { useCollectionManager } from './CollectionManagerProvider';
|
||||
@ -42,3 +42,12 @@ export const AssociationProvider: FC<AssociationProviderProps> = (props) => {
|
||||
</CollectionProvider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 用来获取关系字段的信息,例如用户表中的角色字段就是这样的值:users.roles
|
||||
* @returns
|
||||
*/
|
||||
export const useAssociationName = () => {
|
||||
const field = useCollectionField();
|
||||
return field ? `${field.collectionName}.${field.name}` : null;
|
||||
};
|
||||
|
@ -0,0 +1,68 @@
|
||||
import { Field, useField, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { SchemaSettingsItemType } from '../../application';
|
||||
import { useColumnSchema, useCompile, useDesignable } from '../../schema-component';
|
||||
import { useCollectionField } from '../collection-field/CollectionFieldProvider';
|
||||
import { useDataSourceManager } from '../data-source/DataSourceManagerProvider';
|
||||
|
||||
export const fieldComponentSettingsItem: SchemaSettingsItemType = {
|
||||
name: 'fieldComponent',
|
||||
type: 'select',
|
||||
useVisible() {
|
||||
const collectionField = useCollectionField();
|
||||
const dm = useDataSourceManager();
|
||||
if (!collectionField) return false;
|
||||
const collectionInterface = dm.collectionFieldInterfaceManager.getFieldInterface(collectionField?.interface) as any;
|
||||
return (
|
||||
Array.isArray(collectionInterface?.componentOptions) &&
|
||||
collectionInterface.componentOptions.length > 1 &&
|
||||
collectionInterface.componentOptions.filter((item) => !item.useVisible || item.useVisible()).length > 1
|
||||
);
|
||||
},
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const field = useField<Field>();
|
||||
const schema = useFieldSchema();
|
||||
const collectionField = useCollectionField();
|
||||
const dm = useDataSourceManager();
|
||||
const collectionInterface = dm.collectionFieldInterfaceManager.getFieldInterface(collectionField?.interface);
|
||||
const { fieldSchema: tableColumnSchema } = useColumnSchema();
|
||||
const fieldSchema = tableColumnSchema || schema;
|
||||
const { dn } = useDesignable();
|
||||
const compile = useCompile();
|
||||
|
||||
const options =
|
||||
collectionInterface?.componentOptions
|
||||
?.filter((item) => !item.useVisible || item.useVisible())
|
||||
?.map((item) => {
|
||||
return {
|
||||
label: compile(item.label),
|
||||
value: item.value,
|
||||
useProps: item.useProps,
|
||||
};
|
||||
}) || [];
|
||||
return {
|
||||
title: t('Field component'),
|
||||
options,
|
||||
value: fieldSchema['x-component-props']?.['component'] || options[0]?.value,
|
||||
onChange(component) {
|
||||
const componentOptions = options.find((item) => item.value === component);
|
||||
const componentProps = {
|
||||
component,
|
||||
...(componentOptions?.useProps?.() || {}),
|
||||
};
|
||||
_.set(fieldSchema, 'x-component-props', componentProps);
|
||||
field.componentProps = componentProps;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
'x-component-props': componentProps,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
@ -0,0 +1 @@
|
||||
export * from './fieldComponent';
|
@ -7,3 +7,4 @@ export * from './data-block';
|
||||
export * from './data-source';
|
||||
export * from './collection-record';
|
||||
export * from './utils';
|
||||
export * from './commonsSettingsItem';
|
||||
|
@ -836,5 +836,6 @@
|
||||
"Show Data":"Show Data",
|
||||
"Setting Down Title":"Setting Down Title",
|
||||
"The current return type is not a document type":"The current return type is not a document type",
|
||||
"Test Data":"Test Data"
|
||||
"Test Data":"Test Data",
|
||||
"Add associations": "Add associations"
|
||||
}
|
||||
|
@ -32,7 +32,10 @@ export const CreateActionInitializer = () => {
|
||||
type: 'void',
|
||||
'x-component': 'Tabs',
|
||||
'x-component-props': {},
|
||||
'x-initializer': 'TabPaneInitializersForCreateFormBlock',
|
||||
'x-initializer': 'popup:addTab',
|
||||
'x-initializer-props': {
|
||||
gridInitializer: 'popup:addNew:addBlock',
|
||||
},
|
||||
properties: {
|
||||
tab1: {
|
||||
type: 'void',
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { CompatibleSchemaInitializer } from '../../../application/schema-initializer/CompatibleSchemaInitializer';
|
||||
import { useCollection } from '../../../data-source/collection/CollectionProvider';
|
||||
import { gridRowColWrap } from '../../../schema-initializer/utils';
|
||||
|
||||
/**
|
||||
@ -48,13 +51,36 @@ export const createFormBlockInitializers = new CompatibleSchemaInitializer(
|
||||
type: 'itemGroup',
|
||||
title: '{{t("Data blocks")}}',
|
||||
name: 'dataBlocks',
|
||||
children: [
|
||||
useChildren() {
|
||||
const currentCollection = useCollection();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return [
|
||||
{
|
||||
name: 'form',
|
||||
title: '{{t("Form")}}',
|
||||
Component: 'CreateFormBlockInitializer',
|
||||
Component: 'FormBlockInitializer',
|
||||
collectionName: currentCollection.name,
|
||||
dataSource: currentCollection.dataSource,
|
||||
componentProps: {
|
||||
filterCollections({ collection, associationField }) {
|
||||
if (associationField) {
|
||||
return false;
|
||||
}
|
||||
if (collection.name === currentCollection.name) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
showAssociationFields: true,
|
||||
onlyCurrentDataSource: true,
|
||||
hideSearch: true,
|
||||
componentType: 'FormItem',
|
||||
currentText: t('Current collection'),
|
||||
otherText: t('Other collections'),
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'itemGroup',
|
||||
|
@ -26,7 +26,7 @@ export const ViewActionInitializer = (props) => {
|
||||
type: 'void',
|
||||
'x-component': 'Tabs',
|
||||
'x-component-props': {},
|
||||
'x-initializer': 'TabPaneInitializers',
|
||||
'x-initializer': 'popup:addTab',
|
||||
properties: {
|
||||
tab1: {
|
||||
type: 'void',
|
||||
|
@ -5,6 +5,7 @@ import { FormOutlined } from '@ant-design/icons';
|
||||
import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
|
||||
import { useBlockAssociationContext } from '../../../../block-provider';
|
||||
import { useCollection_deprecated } from '../../../../collection-manager';
|
||||
import { useAssociationName, useCollectionManager } from '../../../../data-source';
|
||||
import { useRecordCollectionDataSourceItems } from '../../../../schema-initializer/utils';
|
||||
import { useSchemaTemplateManager } from '../../../../schema-templates';
|
||||
import { createDetailsUISchema } from './createDetailsUISchema';
|
||||
@ -29,8 +30,7 @@ export const RecordReadPrettyFormBlockInitializer = () => {
|
||||
export function useCreateSingleDetailsSchema() {
|
||||
const { insert } = useSchemaInitializer();
|
||||
const { getTemplateSchemaByMode } = useSchemaTemplateManager();
|
||||
const association = useBlockAssociationContext();
|
||||
|
||||
const association = useAssociationName();
|
||||
const templateWrap = useCallback(
|
||||
(templateSchema, options) => {
|
||||
const { item } = options;
|
||||
@ -38,7 +38,7 @@ export function useCreateSingleDetailsSchema() {
|
||||
const blockSchema = createDetailsUISchema(
|
||||
association
|
||||
? {
|
||||
association,
|
||||
association: association,
|
||||
dataSource: item.dataSource,
|
||||
templateSchema: templateSchema,
|
||||
isCurrent: true,
|
||||
|
@ -3,6 +3,7 @@ import React, { useCallback } from 'react';
|
||||
import { FormOutlined } from '@ant-design/icons';
|
||||
|
||||
import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
|
||||
import { useAssociationName } from '../../../../data-source/collection/AssociationProvider';
|
||||
import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection';
|
||||
import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer';
|
||||
import { createCreateFormBlockUISchema } from './createCreateFormBlockUISchema';
|
||||
@ -17,6 +18,8 @@ export const FormBlockInitializer = ({
|
||||
showAssociationFields,
|
||||
hideChildrenIfSingleCollection,
|
||||
hideOtherRecordsInPopup,
|
||||
currentText,
|
||||
otherText,
|
||||
}: {
|
||||
filterCollections: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean;
|
||||
onlyCurrentDataSource: boolean;
|
||||
@ -40,6 +43,10 @@ export const FormBlockInitializer = ({
|
||||
* 隐藏弹窗中的 Other records 选项
|
||||
*/
|
||||
hideOtherRecordsInPopup?: boolean;
|
||||
/** 用于更改 Current record 的文案 */
|
||||
currentText?: string;
|
||||
/** 用于更改 Other records 的文案 */
|
||||
otherText?: string;
|
||||
}) => {
|
||||
const itemConfig = useSchemaInitializerItem();
|
||||
const { createFormBlock, templateWrap } = useCreateFormBlock();
|
||||
@ -73,24 +80,47 @@ export const FormBlockInitializer = ({
|
||||
showAssociationFields={showAssociationFields}
|
||||
hideChildrenIfSingleCollection={hideChildrenIfSingleCollection}
|
||||
hideOtherRecordsInPopup={hideOtherRecordsInPopup}
|
||||
currentText={currentText}
|
||||
otherText={otherText}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const useCreateFormBlock = () => {
|
||||
const { insert } = useSchemaInitializer();
|
||||
const itemConfig = useSchemaInitializerItem();
|
||||
const { isCusomeizeCreate: isCustomizeCreate } = itemConfig;
|
||||
const association = useAssociationName();
|
||||
const { isCusomeizeCreate: isCustomizeCreate } = useSchemaInitializerItem();
|
||||
|
||||
const createFormBlock = ({ item }) => {
|
||||
const createFormBlock = useCallback(
|
||||
({ item, fromOthersInPopup }) => {
|
||||
if (fromOthersInPopup) {
|
||||
insert(
|
||||
createCreateFormBlockUISchema({
|
||||
collectionName: item.collectionName || item.name,
|
||||
dataSource: item.dataSource,
|
||||
isCusomeizeCreate: isCustomizeCreate,
|
||||
isCusomeizeCreate: true,
|
||||
}),
|
||||
);
|
||||
};
|
||||
} else {
|
||||
insert(
|
||||
createCreateFormBlockUISchema(
|
||||
association
|
||||
? {
|
||||
association,
|
||||
dataSource: item.dataSource,
|
||||
isCusomeizeCreate: isCustomizeCreate,
|
||||
}
|
||||
: {
|
||||
collectionName: item.collectionName || item.name,
|
||||
dataSource: item.dataSource,
|
||||
isCusomeizeCreate: isCustomizeCreate,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
[association, insert, isCustomizeCreate],
|
||||
);
|
||||
|
||||
const templateWrap = (templateSchema, { item }) => {
|
||||
const schema = createCreateFormBlockUISchema({
|
||||
|
@ -1,10 +1,12 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
import { FormOutlined } from '@ant-design/icons';
|
||||
|
||||
import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
|
||||
import { useBlockAssociationContext } from '../../../../block-provider';
|
||||
import { useCollection_deprecated } from '../../../../collection-manager';
|
||||
import { useAssociationName } from '../../../../data-source';
|
||||
import { useRecordCollectionDataSourceItems } from '../../../../schema-initializer/utils';
|
||||
import { useSchemaTemplateManager } from '../../../../schema-templates';
|
||||
import { createEditFormBlockUISchema } from './createEditFormBlockUISchema';
|
||||
@ -41,10 +43,10 @@ export const RecordFormBlockInitializer = () => {
|
||||
|
||||
export function useCreateEditFormBlock() {
|
||||
const { insert } = useSchemaInitializer();
|
||||
const association = useBlockAssociationContext();
|
||||
|
||||
const association = useAssociationName();
|
||||
const createEditFormBlock = useCallback(
|
||||
({ item }) => {
|
||||
const collectionName = item.collectionName || item.name;
|
||||
if (!association && item.associationField) {
|
||||
const field = item.associationField;
|
||||
insert(
|
||||
@ -63,7 +65,7 @@ export function useCreateEditFormBlock() {
|
||||
isCurrent: true,
|
||||
}
|
||||
: {
|
||||
collectionName: item.collectionName || item.name,
|
||||
collectionName,
|
||||
dataSource: item.dataSource,
|
||||
},
|
||||
),
|
||||
|
@ -1,7 +1,19 @@
|
||||
import React from 'react';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
import { GridRowContext } from '../../../../schema-component';
|
||||
import { SchemaToolbar } from '../../../../schema-settings';
|
||||
|
||||
export const TableColumnSchemaToolbar = (props) => {
|
||||
return <SchemaToolbar initializer={false} showBorder={false} showBackground {...props} />;
|
||||
return (
|
||||
<GridRowContext.Provider value={null}>
|
||||
<SchemaToolbar
|
||||
initializer={props.initializer || false}
|
||||
showBorder={false}
|
||||
showBackground
|
||||
{..._.omit(props, 'initializer')}
|
||||
/>
|
||||
</GridRowContext.Provider>
|
||||
);
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ export const createTableBlockUISchema = (options: {
|
||||
return {
|
||||
type: 'void',
|
||||
'x-decorator': 'TableBlockProvider',
|
||||
'x-acl-action': `${collectionName}:list`,
|
||||
'x-acl-action': `${association || collectionName}:list`,
|
||||
'x-use-decorator-props': 'useTableBlockDecoratorProps',
|
||||
'x-decorator-props': {
|
||||
collection: collectionName,
|
||||
@ -63,8 +63,16 @@ export const createTableBlockUISchema = (options: {
|
||||
'x-action-column': 'actions',
|
||||
'x-decorator': 'TableV2.Column.ActionBar',
|
||||
'x-component': 'TableV2.Column',
|
||||
'x-designer': 'TableV2.ActionColumnDesigner',
|
||||
'x-component-props': {
|
||||
width: 150,
|
||||
fixed: 'right',
|
||||
},
|
||||
'x-toolbar': 'TableColumnSchemaToolbar',
|
||||
'x-initializer': 'table:configureItemActions',
|
||||
'x-designer': 'TableV2.ActionColumnDesigner',
|
||||
'x-toolbar-props': {
|
||||
initializer: 'table:configureItemActions',
|
||||
},
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
|
@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useApp } from '../../../../application';
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
import { useCollectionManager_deprecated } from '../../../../collection-manager';
|
||||
import { fieldComponentSettingsItem, useCollection } from '../../../../data-source';
|
||||
import { useDesignable } from '../../../../schema-component';
|
||||
import { useAssociationFieldContext } from '../../../../schema-component/antd/association-field/hooks';
|
||||
import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
||||
@ -113,12 +114,15 @@ export const tableColumnSettings = new SchemaSettings({
|
||||
name: 'sortable',
|
||||
type: 'switch',
|
||||
useVisible() {
|
||||
const collection = useCollection();
|
||||
const { collectionField } = useColumnSchema();
|
||||
const { getInterface } = useCollectionManager_deprecated();
|
||||
const interfaceCfg = getInterface(collectionField?.interface);
|
||||
const { currentMode } = useAssociationFieldContext();
|
||||
|
||||
return interfaceCfg?.sortable === true && !currentMode;
|
||||
return (
|
||||
interfaceCfg?.sortable === true && !currentMode && collection?.name === collectionField?.collectionName
|
||||
);
|
||||
},
|
||||
useComponentProps() {
|
||||
const field: any = useField();
|
||||
@ -151,7 +155,12 @@ export const tableColumnSettings = new SchemaSettings({
|
||||
name: 'setDefaultValue',
|
||||
useVisible() {
|
||||
const { fieldSchema } = useColumnSchema();
|
||||
return !fieldSchema['x-read-pretty'];
|
||||
|
||||
if (!fieldSchema) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !fieldSchema?.['x-read-pretty'];
|
||||
},
|
||||
Component: SchemaSettingsDefaultValue as any,
|
||||
useComponentProps() {
|
||||
@ -167,6 +176,11 @@ export const tableColumnSettings = new SchemaSettings({
|
||||
useVisible() {
|
||||
const { uiSchema, fieldSchema } = useColumnSchema();
|
||||
const field: any = useField();
|
||||
|
||||
if (!fieldSchema) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isSubTableColumn = ['QuickEdit', 'FormItem'].includes(fieldSchema['x-decorator']);
|
||||
return isSubTableColumn && !field.readPretty && !uiSchema?.['x-read-pretty'];
|
||||
},
|
||||
@ -181,6 +195,10 @@ export const tableColumnSettings = new SchemaSettings({
|
||||
title: t('Required'),
|
||||
checked: fieldSchema.required as boolean,
|
||||
onChange: (required) => {
|
||||
if (!fieldSchema) {
|
||||
return console.error('fieldSchema is required');
|
||||
}
|
||||
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
@ -204,6 +222,9 @@ export const tableColumnSettings = new SchemaSettings({
|
||||
useVisible() {
|
||||
const { fieldSchema, collectionField } = useColumnSchema();
|
||||
const field: any = useField();
|
||||
if (!fieldSchema) {
|
||||
return false;
|
||||
}
|
||||
const isSubTableColumn = ['QuickEdit', 'FormItem'].includes(fieldSchema['x-decorator']);
|
||||
return (
|
||||
isSubTableColumn &&
|
||||
@ -218,6 +239,9 @@ export const tableColumnSettings = new SchemaSettings({
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
let readOnlyMode = 'editable';
|
||||
if (!fieldSchema) {
|
||||
return console.error('fieldSchema is required') as any;
|
||||
}
|
||||
if (fieldSchema['x-disabled'] === true) {
|
||||
readOnlyMode = 'readonly';
|
||||
}
|
||||
@ -283,6 +307,7 @@ export const tableColumnSettings = new SchemaSettings({
|
||||
};
|
||||
},
|
||||
},
|
||||
fieldComponentSettingsItem,
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -67,7 +67,6 @@ export const Action: ComposedAction = withDynamicSchemaProps(
|
||||
const designerProps = fieldSchema['x-designer-props'];
|
||||
const openMode = fieldSchema?.['x-component-props']?.['openMode'];
|
||||
const openSize = fieldSchema?.['x-component-props']?.['openSize'];
|
||||
|
||||
const disabled = form.disabled || field.disabled || field.data?.disabled || propsDisabled;
|
||||
const linkageRules = useMemo(() => fieldSchema?.['x-linkage-rules'] || [], [fieldSchema]);
|
||||
const { designable } = useDesignable();
|
||||
@ -175,7 +174,6 @@ export const Action: ComposedAction = withDynamicSchemaProps(
|
||||
</ActionContextProvider>
|
||||
);
|
||||
|
||||
// fix /description
|
||||
if (addChild) {
|
||||
return wrapSSR(
|
||||
<RecordProvider record={null} parent={record}>
|
||||
|
@ -7,12 +7,12 @@ import cls from 'classnames';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { useToken } from '../__builtins__';
|
||||
import { useDesignable, useFormBlockContext, useSchemaInitializerRender } from '../../../';
|
||||
import { SchemaComponent, useDesignable, useFormBlockContext, useSchemaInitializerRender } from '../../../';
|
||||
import { useFormBlockType } from '../../../block-provider';
|
||||
import { DndContext } from '../../common/dnd-context';
|
||||
import useStyles from './Grid.style';
|
||||
|
||||
const GridRowContext = createContext<any>({});
|
||||
export const GridRowContext = createContext<any>({});
|
||||
GridRowContext.displayName = 'GridRowContext';
|
||||
const GridColContext = createContext<any>({});
|
||||
GridColContext.displayName = 'GridColContext';
|
||||
@ -22,6 +22,9 @@ GridContext.displayName = 'GridContext';
|
||||
const breakRemoveOnGrid = (s: Schema) => s['x-component'] === 'Grid';
|
||||
const breakRemoveOnRow = (s: Schema) => s['x-component'] === 'Grid.Row';
|
||||
|
||||
const MemorizedRecursionField = React.memo(RecursionField);
|
||||
MemorizedRecursionField.displayName = 'MemorizedRecursionField';
|
||||
|
||||
const ColDivider = (props) => {
|
||||
const { token } = useToken();
|
||||
const dragIdRef = useRef<string | null>(null);
|
||||
@ -306,7 +309,7 @@ export const useGridRowContext = () => {
|
||||
|
||||
export const Grid: any = observer(
|
||||
(props: any) => {
|
||||
const { showDivider = true } = props;
|
||||
const { distributed, showDivider = true } = props;
|
||||
const gridRef = useRef(null);
|
||||
const field = useField();
|
||||
const fieldSchema = useFieldSchema();
|
||||
@ -316,6 +319,10 @@ export const Grid: any = observer(
|
||||
const rows = useRowProperties();
|
||||
const { setPrintContent } = useFormBlockContext();
|
||||
const { wrapSSR, componentCls, hashId } = useStyles();
|
||||
const distributedValue =
|
||||
distributed === undefined
|
||||
? fieldSchema?.parent['x-component'] === 'Page' || fieldSchema?.parent['x-component'] === 'Tabs.TabPane'
|
||||
: distributed;
|
||||
|
||||
useEffect(() => {
|
||||
gridRef.current && setPrintContent?.(gridRef.current);
|
||||
@ -343,7 +350,11 @@ export const Grid: any = observer(
|
||||
{rows.map((schema, index) => {
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
<RecursionField name={schema.name} schema={schema} />
|
||||
{distributedValue ? (
|
||||
<SchemaComponent name={schema.name} schema={schema} distributed />
|
||||
) : (
|
||||
<MemorizedRecursionField name={schema.name} schema={schema} />
|
||||
)}
|
||||
{showDivider ? (
|
||||
<RowDivider
|
||||
rows={rows}
|
||||
|
@ -8,6 +8,14 @@ type SchemaComponentOnChange = {
|
||||
onChange?: (s: Schema) => void;
|
||||
};
|
||||
|
||||
interface DistributedProps {
|
||||
/**
|
||||
* 是否和父级隔离刷新
|
||||
* @default false
|
||||
*/
|
||||
distributed?: boolean;
|
||||
}
|
||||
|
||||
function toSchema(schema?: any) {
|
||||
if (Schema.isSchemaInstance(schema)) {
|
||||
return schema;
|
||||
@ -55,7 +63,8 @@ const MemoizedSchemaComponent = (props: ISchemaFieldProps & SchemaComponentOnCha
|
||||
};
|
||||
|
||||
export const SchemaComponent = (
|
||||
props: (ISchemaFieldProps | IRecursionFieldProps) & { memoized?: boolean } & SchemaComponentOnChange,
|
||||
props: (ISchemaFieldProps | IRecursionFieldProps) & { memoized?: boolean } & SchemaComponentOnChange &
|
||||
DistributedProps,
|
||||
) => {
|
||||
const { memoized, ...others } = props;
|
||||
if (memoized) {
|
||||
|
Loading…
Reference in New Issue
Block a user