diff --git a/packages/core/client/src/collection-manager/CollectionManagerProvider.tsx b/packages/core/client/src/collection-manager/CollectionManagerProvider.tsx index 48ad0fb17..6b70977c5 100644 --- a/packages/core/client/src/collection-manager/CollectionManagerProvider.tsx +++ b/packages/core/client/src/collection-manager/CollectionManagerProvider.tsx @@ -10,7 +10,7 @@ import * as defaultInterfaces from './interfaces'; import { CollectionManagerOptions } from './types'; export const CollectionManagerProvider: React.FC = (props) => { - const { service, interfaces, collections = [], refreshCM, templates } = props; + const { service, interfaces, collections = [], refreshCM, updateCollection, templates } = props; const defaultTemplates = keyBy(templateOptions(), (item) => item.name); const ctx = useContext(CollectionManagerContext); return ( @@ -22,6 +22,7 @@ export const CollectionManagerProvider: React.FC = (pr templates: { ...defaultTemplates, ...templates }, collections: [...ctx.collections, ...collections], refreshCM, + updateCollection, }} > {props.children} @@ -76,12 +77,17 @@ export const RemoteCollectionManagerProvider = (props: any) => { return data?.data || []; }; + const updateCollection = (collection) => { + service.mutate({ data: collection }); + }; + return ( @@ -95,7 +101,7 @@ export const CollectionCategroriesProvider = (props) => { value={{ data: service?.data?.data, refresh: refreshCategory, - ...props + ...props, }} > {props.children} diff --git a/packages/core/client/src/collection-manager/Configuration/CollectionFields.tsx b/packages/core/client/src/collection-manager/Configuration/CollectionFields.tsx new file mode 100644 index 000000000..87513f6e5 --- /dev/null +++ b/packages/core/client/src/collection-manager/Configuration/CollectionFields.tsx @@ -0,0 +1,440 @@ +import { css } from '@emotion/css'; +import { Field, createForm } from '@formily/core'; +import { FieldContext, FormContext, useField } from '@formily/react'; +import { Space, Switch, Table, TableColumnProps, Tag, Tooltip } from 'antd'; +import React, { useContext, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { RecordProvider, useRecord } from '../../record-provider'; +import { Action, useAttach, useCompile } from '../../schema-component'; +import { + ResourceActionContext, + ResourceActionProvider, + useResourceActionContext, + useResourceContext, +} from '../ResourceActionProvider'; +import { + isDeleteButtonDisabled, + useBulkDestroyActionAndRefreshCM, + useDestroyActionAndRefreshCM, +} from '../action-hooks'; +import { useCollectionManager } from '../hooks/useCollectionManager'; +import { AddCollectionField } from './AddFieldAction'; +import { EditCollectionField } from './EditFieldAction'; +import { OverridingCollectionField } from './OverridingCollectionField'; +import { SyncFieldsAction } from './SyncFieldsAction'; +import { ViewCollectionField } from './ViewInheritedField'; +import { collection } from './schemas/collectionFields'; +const CELL_WIDTH = 200; + +const indentStyle = css` + .ant-table { + margin-left: -7px !important; + } +`; +const rowStyle = css` + .ant-table-cell { + background-color: white; + } +`; + +const titlePrompt = 'Default title for each record'; +// 只有下面类型的字段才可以设置为标题字段 +const expectTypes = ['string', 'integer', 'bigInt', 'float', 'double', 'decimal', 'date', 'dateonly', 'time']; +const excludeInterfaces = ['icon']; + +const CurrentFields = (props) => { + const compile = useCompile(); + const { getInterface } = useCollectionManager(); + const { t } = useTranslation(); + const { setState } = useResourceActionContext(); + const { resource, targetKey } = props.collectionResource || {}; + const { [targetKey]: filterByTk, titleField } = useRecord(); + const [loadingRecord, setLoadingRecord] = React.useState(null); + const { updateCollection } = useCollectionManager(); + + const columns: TableColumnProps[] = [ + { + dataIndex: ['uiSchema', 'title'], + title: t('Field display name'), + render: (value) =>
{compile(value)}
, + }, + { + dataIndex: 'name', + title: t('Field name'), + width: CELL_WIDTH + 20, + }, + { + dataIndex: 'interface', + title: t('Field interface'), + width: CELL_WIDTH, + render: (value) => {compile(getInterface(value)?.title)}, + }, + { + dataIndex: 'titleField', + title: t('Title field'), + width: CELL_WIDTH, + render: function Render(_, record) { + const handleChange = (checked) => { + setLoadingRecord(record); + resource + .update({ filterByTk, values: { titleField: checked ? record.name : 'id' } }) + .then(async () => { + const data = await props.refreshAsync(); + if (data?.data) { + updateCollection(data.data); + } + setLoadingRecord(null); + }) + .catch((err) => { + setLoadingRecord(null); + console.error(err); + }); + }; + + return expectTypes.includes(record.type) && !excludeInterfaces.includes(record.interface) ? ( + + + + ) : null; + }, + }, + { + dataIndex: 'actions', + title: t('Actions'), + width: CELL_WIDTH, + render: (_, record) => { + const deleteProps = { + confirm: { + title: t('Delete record'), + content: t('Are you sure you want to delete it?'), + }, + useAction: useDestroyActionAndRefreshCM, + disabled: isDeleteButtonDisabled(record), + title: t('Delete'), + }; + + return ( + + + + + + + ); + }, + }, + ]; + return ( + { + setState((state) => { + const result = [...(state.selectedRowKeys || []), ...selectedRowKeys]; + return { + ...state, + selectedRowKeys: result, + }; + }); + }, + }} + className={indentStyle} + /> + ); +}; + +const InheritFields = (props) => { + const compile = useCompile(); + const { getInterface } = useCollectionManager(); + const { resource, targetKey } = props.collectionResource || {}; + const { [targetKey]: filterByTk, titleField, name } = useRecord(); + const [loadingRecord, setLoadingRecord] = React.useState(null); + const { t } = useTranslation(); + const { updateCollection } = useCollectionManager(); + + const columns: TableColumnProps[] = [ + { + dataIndex: ['uiSchema', 'title'], + title: t('Field display name'), + render: (value) =>
{compile(value)}
, + }, + { + dataIndex: 'name', + title: t('Field name'), + width: CELL_WIDTH + 20, + }, + { + dataIndex: 'interface', + title: t('Field interface'), + width: CELL_WIDTH, + render: (value) => {compile(getInterface(value)?.title)}, + }, + { + dataIndex: 'titleField', + title: t('Title field'), + width: CELL_WIDTH, + render(_, record) { + const handleChange = (checked) => { + setLoadingRecord(record); + resource + .update({ filterByTk, values: { titleField: checked ? record.name : 'id' } }) + .then(async () => { + const data = await props.refreshAsync(); + if (data?.data) { + updateCollection(data.data); + } + setLoadingRecord(null); + }) + .catch((err) => { + setLoadingRecord(null); + console.error(err); + }); + }; + + return expectTypes.includes(record.type) && !excludeInterfaces.includes(record.interface) ? ( + + + + ) : null; + }, + }, + { + dataIndex: 'actions', + title: t('Actions'), + width: CELL_WIDTH, + render: function Render(_, record) { + const overrideProps = { + type: 'primary', + currentCollection: name, + }; + const viewCollectionProps = { + type: 'primary', + }; + + return ( + + + + + + + ); + }, + }, + ]; + return ( +
field.interface)} + /> + ); +}; + +export const CollectionFields = (props) => { + const compile = useCompile(); + const field = useField(); + const { name } = useRecord(); + const { getInterface, getInheritCollections, getCollection, getCurrentCollectionFields } = useCollectionManager(); + const form = useMemo(() => createForm(), []); + const f = useAttach(form.createArrayField({ ...field.props, basePath: '' })); + const { t } = useTranslation(); + const collectionResource = useResourceContext(); + const { refreshAsync } = useContext(ResourceActionContext); + + const inherits = getInheritCollections(name); + + const columns: TableColumnProps[] = [ + { + dataIndex: 'title', + title: t('Field display name'), + render: (value) => ( +
+ {value} +
+ ), + // width: CELL_WIDTH, + }, + { + dataIndex: 'name', + title: t('Field name'), + width: CELL_WIDTH + 20, + }, + { + dataIndex: 'interface', + title: t('Field interface'), + width: CELL_WIDTH, + }, + { + dataIndex: 'titleField', + title: t('Title field'), + width: CELL_WIDTH, + }, + { + dataIndex: 'actions', + title: t('Actions'), + width: CELL_WIDTH, + }, + ]; + + const fields = getCurrentCollectionFields(name); + + const groups = { + pf: [], + association: [], + general: [], + system: [], + }; + + fields.forEach((field) => { + if (field.primaryKey || field.isForeignKey) { + groups.pf.push(field); + } else if (field.interface) { + const conf = getInterface(field.interface); + if (conf.group === 'systemInfo') { + groups.system.push(field); + } else if (['m2m', 'm2o', 'o2b', 'o2m', 'linkTo'].includes(field.interface)) { + groups.association.push(field); + } else { + groups.general.push(field); + } + } + }); + + const dataSource = [ + { + key: 'pf', + title: t('PK & FK fields'), + fields: groups.pf, + }, + { + key: 'association', + title: t('Association fields'), + fields: groups.association, + }, + { + key: 'general', + title: t('General fields'), + fields: groups.general, + }, + { + key: 'system', + title: t('System fields'), + fields: groups.system, + }, + ]; + + dataSource.push( + ...inherits.map((key) => { + const collection = getCollection(key); + return { + key, + title: `${t('Inherited fields')} - ` + compile(collection.title), + inherit: true, + fields: collection.fields, + }; + }), + ); + + const resourceActionProps = { + association: { + sourceKey: 'name', + targetKey: 'name', + }, + collection, + request: { + resource: 'collections.fields', + action: 'list', + params: { + paginate: false, + filter: { + $or: [{ 'interface.$not': null }, { 'options.source.$notEmpty': true }], + }, + sort: ['sort'], + }, + }, + }; + + const deleteProps = useMemo( + () => ({ + useAction: useBulkDestroyActionAndRefreshCM, + title: t('Delete'), + icon: 'DeleteOutlined', + confirm: { + title: t('Delete record'), + content: t('Are you sure you want to delete it?'), + }, + }), + [t], + ); + const addProps = { type: 'primary' }; + const syncProps = { type: 'primary' }; + + return ( + + + + + + + + +
d.fields.length)} + pagination={false} + expandable={{ + defaultExpandAllRows: true, + expandedRowClassName: () => rowStyle, + expandedRowRender: (record) => + record.inherit ? ( + + ) : ( + + ), + }} + /> + + + + ); +}; diff --git a/packages/core/client/src/collection-manager/Configuration/CollectionFieldsTableArray.tsx b/packages/core/client/src/collection-manager/Configuration/CollectionFieldsTableArray.tsx index b2594082d..1356dd31e 100644 --- a/packages/core/client/src/collection-manager/Configuration/CollectionFieldsTableArray.tsx +++ b/packages/core/client/src/collection-manager/Configuration/CollectionFieldsTableArray.tsx @@ -14,7 +14,7 @@ import { useCompile, useRecord, useRequest, - useSchemaInitializer + useSchemaInitializer, } from '../..'; import { overridingSchema } from '../Configuration/schemas/collectionFields'; @@ -192,10 +192,9 @@ export const CollectionFieldsTableArray: React.FC = observer((props) => { }); }; - - const expandedRowRender = (record: CategorizeDataItem, index, indent, expanded) => { - if(!props.loading){ - const columns = useTableColumns(); + const ExpandedRowRender = (record: CategorizeDataItem, index, indent, expanded) => { + const columns = useTableColumns(); + if (!props.loading) { if (inherits.includes(record.key)) { columns.pop(); columns.push({ @@ -244,7 +243,6 @@ export const CollectionFieldsTableArray: React.FC = observer((props) => { /> ); } - }; return (
= observer((props) => { dataSource={categorizeData} pagination={false} expandable={{ - expandedRowRender, + expandedRowRender: ExpandedRowRender, expandedRowKeys: expandedKeys, }} onExpand={(expanded, record) => { diff --git a/packages/core/client/src/collection-manager/Configuration/ConfigurationTable.tsx b/packages/core/client/src/collection-manager/Configuration/ConfigurationTable.tsx index b3de1e03b..9e4c6d1ac 100644 --- a/packages/core/client/src/collection-manager/Configuration/ConfigurationTable.tsx +++ b/packages/core/client/src/collection-manager/Configuration/ConfigurationTable.tsx @@ -12,10 +12,11 @@ import { CollectionCategroriesContext } from '../context'; import { useCollectionManager } from '../hooks/useCollectionManager'; import { DataSourceContext } from '../sub-table'; import { AddSubFieldAction } from './AddSubFieldAction'; +import { CollectionFields } from './CollectionFields'; import { EditSubFieldAction } from './EditSubFieldAction'; import { FieldSummary } from './components/FieldSummary'; +import { TemplateSummay } from './components/TemplateSummay'; import { collectionSchema } from './schemas/collections'; -import {TemplateSummay} from './components/TemplateSummay'; /** * @param service @@ -166,6 +167,7 @@ export const ConfigurationTable = () => { FieldSummary, TemplateSummay, CollectionFieldsTable, + CollectionFields, }} scope={{ useDestroySubField, diff --git a/packages/core/client/src/collection-manager/Configuration/ConfigurationTabs.tsx b/packages/core/client/src/collection-manager/Configuration/ConfigurationTabs.tsx index 513cfc47d..a4b672fb0 100644 --- a/packages/core/client/src/collection-manager/Configuration/ConfigurationTabs.tsx +++ b/packages/core/client/src/collection-manager/Configuration/ConfigurationTabs.tsx @@ -9,14 +9,15 @@ import { useSensor, useSensors } from '@dnd-kit/core'; -import { observer, RecursionField } from '@formily/react'; +import { RecursionField, observer } from '@formily/react'; import { uid } from '@formily/shared'; import { Badge, Card, Dropdown, Menu, Modal, Tabs } from 'antd'; import React, { useContext, useState } from 'react'; import { useAPIClient } from '../../api-client'; import { SchemaComponent, SchemaComponentOptions, useCompile } from '../../schema-component'; -import { CollectionCategroriesContext } from '../context'; import { useResourceActionContext } from '../ResourceActionProvider'; +import { CollectionCategroriesContext } from '../context'; +import { CollectionFields } from './CollectionFields'; import { collectionTableSchema } from './schemas/collections'; function Draggable(props) { @@ -240,6 +241,7 @@ export const ConfigurationTabs = () => { > diff --git a/packages/core/client/src/collection-manager/Configuration/EditCollectionAction.tsx b/packages/core/client/src/collection-manager/Configuration/EditCollectionAction.tsx index 59d5d5da1..52e42f6ec 100644 --- a/packages/core/client/src/collection-manager/Configuration/EditCollectionAction.tsx +++ b/packages/core/client/src/collection-manager/Configuration/EditCollectionAction.tsx @@ -8,10 +8,10 @@ import { useTranslation } from 'react-i18next'; import { useRequest } from '../../api-client'; import { RecordProvider, useRecord } from '../../record-provider'; import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component'; +import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider'; import { useCancelAction } from '../action-hooks'; import { useCollectionManager } from '../hooks'; import { IField } from '../interfaces/types'; -import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider'; import * as components from './components'; const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => { @@ -26,10 +26,10 @@ const getSchema = (schema: IField, record: any, compile, getContainer): ISchema name: { 'x-component': 'CollectionField', 'x-decorator': 'FormItem', - 'x-disabled': true, + // 'x-disabled': true, }, }; - properties.name['x-disabled'] = true; + // properties.name['x-disabled'] = true; if (schema.hasDefaultValue === true) { properties['defaultValue'] = cloneDeep(schema.default.uiSchema); properties['defaultValue']['title'] = compile('{{ t("Default value") }}'); diff --git a/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx b/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx index 624b27af4..7c5ebe953 100644 --- a/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx +++ b/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx @@ -8,10 +8,10 @@ import { useTranslation } from 'react-i18next'; import { useAPIClient, useRequest } from '../../api-client'; import { RecordProvider, useRecord } from '../../record-provider'; import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component'; +import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider'; import { useCancelAction, useUpdateAction } from '../action-hooks'; import { useCollectionManager } from '../hooks'; import { IField } from '../interfaces/types'; -import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider'; import * as components from './components'; const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => { @@ -24,7 +24,7 @@ const getSchema = (schema: IField, record: any, compile, getContainer): ISchema } if (schema.hasDefaultValue === true) { - properties['defaultValue'] = cloneDeep(schema.default.uiSchema)||{}; + properties['defaultValue'] = cloneDeep(schema.default.uiSchema) || {}; properties['defaultValue']['title'] = compile('{{ t("Default value") }}'); properties['defaultValue']['x-decorator'] = 'FormItem'; properties['defaultValue']['x-reactions'] = { diff --git a/packages/core/client/src/collection-manager/Configuration/OverridingCollectionField.tsx b/packages/core/client/src/collection-manager/Configuration/OverridingCollectionField.tsx index a7245cd33..73088f33a 100644 --- a/packages/core/client/src/collection-manager/Configuration/OverridingCollectionField.tsx +++ b/packages/core/client/src/collection-manager/Configuration/OverridingCollectionField.tsx @@ -8,10 +8,10 @@ import { useTranslation } from 'react-i18next'; import { useAPIClient, useRequest } from '../../api-client'; import { RecordProvider, useRecord } from '../../record-provider'; import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component'; +import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider'; import { useCancelAction } from '../action-hooks'; import { useCollectionManager } from '../hooks'; import { IField } from '../interfaces/types'; -import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider'; import * as components from './components'; const getSchema = (schema: IField, record: any, compile, getContainer): ISchema => { diff --git a/packages/core/client/src/collection-manager/Configuration/schemas/collectionFields.ts b/packages/core/client/src/collection-manager/Configuration/schemas/collectionFields.ts index b2296be02..b89e4f03d 100644 --- a/packages/core/client/src/collection-manager/Configuration/schemas/collectionFields.ts +++ b/packages/core/client/src/collection-manager/Configuration/schemas/collectionFields.ts @@ -2,7 +2,7 @@ import { ISchema } from '@formily/react'; import { CollectionOptions } from '../../types'; import { CollectionFieldInterface } from '../components/CollectionFieldInterface'; -const collection: CollectionOptions = { +export const collection: CollectionOptions = { name: 'fields', fields: [ { diff --git a/packages/core/client/src/collection-manager/Configuration/schemas/collections.ts b/packages/core/client/src/collection-manager/Configuration/schemas/collections.ts index b2bed6ca1..1428c711d 100644 --- a/packages/core/client/src/collection-manager/Configuration/schemas/collections.ts +++ b/packages/core/client/src/collection-manager/Configuration/schemas/collections.ts @@ -1,14 +1,12 @@ import { ISchema, Schema } from '@formily/react'; -import { message } from 'antd'; import { uid } from '@formily/shared'; +import { message } from 'antd'; import { useTranslation } from 'react-i18next'; import { useAPIClient } from '../../../api-client'; import { i18n } from '../../../i18n'; import { CollectionOptions } from '../../types'; -import { CollectionTemplate } from '../components/CollectionTemplate'; import { CollectionCategory } from '../components/CollectionCategory'; -import { collectionFieldSchema } from './collectionFields'; - +import { CollectionTemplate } from '../components/CollectionTemplate'; const compile = (source) => { return Schema.compile(source, { t: i18n.t }); }; @@ -255,6 +253,7 @@ export const collectionTableSchema: ISchema = { 'x-component': 'Action.Drawer', 'x-component-props': { destroyOnClose: true, + width: '70%', }, 'x-reactions': (field) => { const i = field.path.segments[1]; @@ -265,7 +264,10 @@ export const collectionTableSchema: ISchema = { } }, properties: { - collectionFieldSchema, + collectionFieldSchema: { + type: 'void', + 'x-component': 'CollectionFields', + }, }, }, }, diff --git a/packages/core/client/src/collection-manager/action-hooks.ts b/packages/core/client/src/collection-manager/action-hooks.ts index 9942b9ad4..08a2b4bbf 100644 --- a/packages/core/client/src/collection-manager/action-hooks.ts +++ b/packages/core/client/src/collection-manager/action-hooks.ts @@ -202,7 +202,7 @@ export const useCollectionFilterOptions = (collectionName: string) => { export const useLinkageCollectionFilterOptions = (collectionName: string) => { const { getCollectionFields, getInterface } = useCollectionManager(); - const fields = getCollectionFields(collectionName).filter((v)=>!['o2m', 'm2m'].includes(v.interface)) + const fields = getCollectionFields(collectionName).filter((v) => !['o2m', 'm2m'].includes(v.interface)); const field2option = (field, depth) => { if (!field.interface) { return; @@ -232,7 +232,7 @@ export const useLinkageCollectionFilterOptions = (collectionName: string) => { option['children'] = children; } if (nested) { - const targetFields = getCollectionFields(field.target).filter((v)=>!['o2m', 'm2m'].includes(v.interface)) + const targetFields = getCollectionFields(field.target).filter((v) => !['o2m', 'm2m'].includes(v.interface)); const options = getOptions(targetFields, depth + 1).filter(Boolean); option['children'] = option['children'] || []; option['children'].push(...options); @@ -253,7 +253,6 @@ export const useLinkageCollectionFilterOptions = (collectionName: string) => { return options; }; - export const useFilterDataSource = (options) => { const { name } = useCollection(); const data = useCollectionFilterOptions(name); @@ -378,7 +377,7 @@ export const useDestroyAction = () => { export const useBulkDestroyAction = () => { const { state, setState, refresh } = useResourceActionContext(); - const { resource, targetKey } = useResourceContext(); + const { resource } = useResourceContext(); return { async run() { await resource.destroy({ @@ -431,8 +430,13 @@ export const useDestroyActionAndRefreshCM = () => { }; }; -export const useDeleteButtonDisabled = () => { - const { interface: i, deletable = true } = useRecord(); +export const useDeleteButtonDisabled = (record?: any) => { + const recordFromProvider = useRecord(); + return isDeleteButtonDisabled(record || recordFromProvider); +}; + +export const isDeleteButtonDisabled = (record?: any) => { + const { interface: i, deletable = true } = record || {}; return !deletable || i === 'id'; }; diff --git a/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts b/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts index 74e93421b..0c2f5b550 100644 --- a/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts +++ b/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts @@ -7,7 +7,8 @@ import { CollectionManagerContext } from '../context'; import { CollectionFieldOptions } from '../types'; export const useCollectionManager = () => { - const { refreshCM, service, interfaces, collections, templates } = useContext(CollectionManagerContext); + const { refreshCM, updateCollection, service, interfaces, collections, templates } = + useContext(CollectionManagerContext); const compile = useCompile(); const getInheritedFields = (name) => { const inheritKeys = getInheritCollections(name); @@ -241,6 +242,7 @@ export const useCollectionManager = () => { getInheritCollections, getChildrenCollections, refreshCM: () => refreshCM?.(), + updateCollection, get(name: string) { return collections?.find((collection) => collection.name === name); }, diff --git a/packages/core/client/src/collection-manager/types.ts b/packages/core/client/src/collection-manager/types.ts index 5bf91f5a8..f4a0410de 100644 --- a/packages/core/client/src/collection-manager/types.ts +++ b/packages/core/client/src/collection-manager/types.ts @@ -6,6 +6,7 @@ export interface CollectionManagerOptions { collections?: any[]; templates?: any; refreshCM?: () => Promise; + updateCollection?: (collection: any) => void; } export interface FieldOptions { diff --git a/packages/core/client/src/locale/en_US.ts b/packages/core/client/src/locale/en_US.ts index 98e2afb5c..d46178143 100644 --- a/packages/core/client/src/locale/en_US.ts +++ b/packages/core/client/src/locale/en_US.ts @@ -213,6 +213,7 @@ export default { "Optional fields": "Optional fields", "System fields": "System fields", "General fields": "General fields", + "Inherited fields": "Inherited fields", "Parent collection fields": "Parent collection fields", "Basic": "Basic", "Single line text": "Single line text", diff --git a/packages/core/client/src/locale/ja_JP.ts b/packages/core/client/src/locale/ja_JP.ts index 78bdec976..7ad5f0fe6 100644 --- a/packages/core/client/src/locale/ja_JP.ts +++ b/packages/core/client/src/locale/ja_JP.ts @@ -595,4 +595,14 @@ export default { 'Click or drag file to this area to upload': 'クリックまたはドラッグしてファイルをアップロード', 'Support for a single or bulk upload, file size should not exceed': '単一または複数のファイルをアップロードできます。ファイルサイズは', + 'Default title for each record': '各レコードのデフォルトタイトル', + + 'If collection inherits, choose inherited collections as templates': 'コレクションが継承されている場合、継承されたコレクションをテンプレートとして選択してください', + 'Select an existing piece of data as the initialization data for the form': '既存のデータを選択して、フォームの初期化データとして使用します', + 'Only the selected fields will be used as the initialization data for the form': '選択したフィールドのみがフォームの初期化データとして使用されます', + 'Template Data': 'テンプレートデータ', + 'Data fields': 'データフィールド', + 'Add template': 'テンプレートを追加', + 'Display data template selector': 'データテンプレートセレクターを表示', + 'Form data templates': 'フォームデータテンプレート', } diff --git a/packages/core/client/src/locale/pt_BR.ts b/packages/core/client/src/locale/pt_BR.ts index 65143d859..da702d87c 100644 --- a/packages/core/client/src/locale/pt_BR.ts +++ b/packages/core/client/src/locale/pt_BR.ts @@ -173,6 +173,7 @@ export default { "Optional fields": "Campos opcionais", "System fields": "Campos do sistema", "General fields": "Campos gerais", + "Inherited fields": "Campos herdados", "Parent collection fields": "Campos da coleção pai", "Basic": "Básico", "Single line text": "Texto de uma linha", @@ -647,4 +648,14 @@ export default { 'Click or drag file to this area to upload': 'Clique ou arraste o arquivo para esta área para fazer o upload', 'Support for a single or bulk upload, file size should not exceed': 'Suporte para upload único ou em massa, o tamanho do arquivo não deve exceder', + 'Default title for each record': 'Título padrão para cada registro', + + 'If collection inherits, choose inherited collections as templates': 'Se a coleção herda, escolha as coleções herdadas como modelos', + 'Select an existing piece of data as the initialization data for the form': 'Selecione um pedaço de dados existente como os dados de inicialização para o formulário', + 'Only the selected fields will be used as the initialization data for the form': 'Somente os campos selecionados serão usados como dados de inicialização para o formulário', + 'Template Data': 'Dados do modelo', + 'Data fields': 'Campos de dados', + 'Add template': 'Adicionar modelo', + 'Display data template selector': 'Exibir seletor de modelo de dados', + 'Form data templates': 'Modelos de dados do formulário', }; diff --git a/packages/core/client/src/locale/ru_RU.ts b/packages/core/client/src/locale/ru_RU.ts index 54ba05fa8..7ac20d20a 100644 --- a/packages/core/client/src/locale/ru_RU.ts +++ b/packages/core/client/src/locale/ru_RU.ts @@ -502,4 +502,14 @@ export default { 'Click or drag file to this area to upload': "Нажмите или перетащите файл в эту область, чтобы загрузить", 'Support for a single or bulk upload, file size should not exceed': "Поддержка одиночной или массовой загрузки, размер файла не должен превышать", + 'Default title for each record': "Заголовок по умолчанию для каждой записи", + + 'If collection inherits, choose inherited collections as templates': "Если коллекция наследуется, выберите наследуемые коллекции в качестве шаблонов", + 'Select an existing piece of data as the initialization data for the form': "Выберите существующие данные в качестве исходных данных для формы", + 'Only the selected fields will be used as the initialization data for the form': "Только выбранные поля будут использоваться в качестве исходных данных для формы", + 'Template Data': "Шаблон данных", + 'Data fields': "Поля данных", + 'Add template': "Добавить шаблон", + 'Display data template selector': "Отображать селектор шаблона данных", + 'Form data templates': "Шаблоны данных формы", } diff --git a/packages/core/client/src/locale/tr_TR.ts b/packages/core/client/src/locale/tr_TR.ts index be0855bcb..c843eace1 100644 --- a/packages/core/client/src/locale/tr_TR.ts +++ b/packages/core/client/src/locale/tr_TR.ts @@ -174,6 +174,7 @@ export default { "Field display name": "Alan görünen adı", "Field type": "Alan türü", "Field interface": "Alan arayüzü", + "Title field": "Başlık alanı", "Date format": "Tarih formatı", "Year/Month/Day": "Yıl/Ay/Gün", "Year-Month-Day": "Yıl-Ay-Gün", @@ -273,7 +274,6 @@ export default { "Allow linking to multiple records": "Birden çok kayda bağlanmaya izin ver", "Allow uploading multiple files": "Birden çok dosya yüklemeye izin ver", "Configure calendar": "Takvimi yapılandır", - "Title field": "Başlık alanı", "Start date field": "Başlangıç tarihi alanı", "End date field": "Bitiş tarihi alanı", "Navigate": "Navigate", @@ -501,4 +501,14 @@ export default { 'Click or drag file to this area to upload': "Dosyayı yüklemek için buraya tıklayın veya sürükleyin", 'Support for a single or bulk upload, file size should not exceed': "Tek veya toplu yükleme destekler, dosya boyutu aşmamalıdır", + 'Default title for each record': "Her kayıt için varsayılan başlık", + + 'If collection inherits, choose inherited collections as templates': "Koleksiyon miras alırsa, kalıtılan koleksiyonları şablon olarak seçin", + 'Select an existing piece of data as the initialization data for the form': 'Formun başlangıç ​​verileri olarak mevcut bir veri parçasını seçin', + 'Only the selected fields will be used as the initialization data for the form': 'Yalnızca seçilen alanlar, formun başlangıç ​​verileri olarak kullanılacaktır', + 'Template Data': 'Şablon Verisi', + 'Data fields': 'Veri alanları', + 'Add template': 'Şablon ekle', + 'Display data template selector': 'Veri şablonu seçicisini görüntüle', + 'Form data templates': 'Form veri şablonları', } diff --git a/packages/core/client/src/locale/zh_CN.ts b/packages/core/client/src/locale/zh_CN.ts index 922d074e4..0bba0bfc8 100644 --- a/packages/core/client/src/locale/zh_CN.ts +++ b/packages/core/client/src/locale/zh_CN.ts @@ -227,6 +227,7 @@ export default { "Optional fields": "可选字段", "System fields": "系统字段", "General fields": "普通字段", + "Inherited fields": "继承字段", "Parent collection fields": "父表字段", "Basic": "基本类型", "Single line text": "单行文本", @@ -743,4 +744,14 @@ export default { 'Click or drag file to this area to upload': '点击或拖拽文件到此区域上传', 'Support for a single or bulk upload, file size should not exceed': '支持单个或批量上传,文件大小不能超过', + 'Default title for each record': '用作数据的默认标题', + + 'If collection inherits, choose inherited collections as templates': '当前表有继承关系时,可选择继承链路上的表作为模板来源', + 'Select an existing piece of data as the initialization data for the form': '选择一条已有的数据作为表单的初始化数据', + 'Only the selected fields will be used as the initialization data for the form': '仅选择的字段才会作为表单的初始化数据', + 'Template Data': '模板数据', + 'Data fields': '数据字段', + 'Add template': '添加模板', + 'Display data template selector': '显示数据模板选择框', + 'Form data templates': '表单数据模板', } diff --git a/packages/core/client/src/schema-component/antd/action/Action.tsx b/packages/core/client/src/schema-component/antd/action/Action.tsx index eb1a1af93..6f3e2d68d 100644 --- a/packages/core/client/src/schema-component/antd/action/Action.tsx +++ b/packages/core/client/src/schema-component/antd/action/Action.tsx @@ -89,7 +89,7 @@ export const Action: ComposedAction = observer((props: any) => { const values = useRecord(); const designerProps = fieldSchema['x-designer-props']; const openMode = fieldSchema?.['x-component-props']?.['openMode']; - const disabled = form.disabled || field.disabled; + const disabled = form.disabled || field.disabled || props.disabled; const openSize = fieldSchema?.['x-component-props']?.['openSize']; const linkageRules = fieldSchema?.['x-linkage-rules'] || []; const { designable } = useDesignable(); diff --git a/packages/core/client/src/schema-component/antd/table/Table.Array.tsx b/packages/core/client/src/schema-component/antd/table/Table.Array.tsx index 37aeb56af..b398cea18 100644 --- a/packages/core/client/src/schema-component/antd/table/Table.Array.tsx +++ b/packages/core/client/src/schema-component/antd/table/Table.Array.tsx @@ -2,16 +2,16 @@ import { MenuOutlined } from '@ant-design/icons'; import { css } from '@emotion/css'; import { ArrayField, Field } from '@formily/core'; import { - observer, RecursionField, Schema, + SchemaExpressionScopeContext, + observer, useField, useFieldSchema, - SchemaExpressionScopeContext, } from '@formily/react'; import { Table, TableColumnProps } from 'antd'; import { default as classNames, default as cls } from 'classnames'; -import React, { useState, useContext } from 'react'; +import React, { useContext, useState } from 'react'; import ReactDragListView from 'react-drag-listview'; import { DndContext } from '../..'; import { RecordIndexProvider, RecordProvider, useRequest, useSchemaInitializer } from '../../../'; @@ -35,7 +35,7 @@ const useTableColumns = () => { if (isColumnComponent(s) && useScope(s['x-visible'])) { return buf.concat([s]); } - return buf + return buf; }, []) .map((s: Schema) => { return { diff --git a/packages/core/client/src/schema-settings/DataTemplates/FormDataTemplates.tsx b/packages/core/client/src/schema-settings/DataTemplates/FormDataTemplates.tsx index ddfbc725a..a740da360 100644 --- a/packages/core/client/src/schema-settings/DataTemplates/FormDataTemplates.tsx +++ b/packages/core/client/src/schema-settings/DataTemplates/FormDataTemplates.tsx @@ -1,6 +1,8 @@ import { connect, mapProps, observer } from '@formily/react'; import { Tree as AntdTree } from 'antd'; import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useCollectionManager } from '../../collection-manager'; import { AssociationSelect, SchemaComponent } from '../../schema-component'; import { AsDefaultTemplate } from './components/AsDefaultTemplate'; import { ArrayCollapse } from './components/DataTemplateTitle'; @@ -19,6 +21,9 @@ export const FormDataTemplates = observer((props: any) => { const { useProps } = props; const { defaultValues, collectionName } = useProps(); const { collectionList, getEnableFieldTree } = useCollectionState(collectionName); + const { getCollection } = useCollectionManager(); + const collection = getCollection(collectionName); + const { t } = useTranslation(); return ( { type: 'string', title: '{{ t("Collection") }}', required: true, - description: '当前表有继承关系时,可选择继承链路上的表作为模板来源', + description: t('If collection inherits, choose inherited collections as templates'), default: collectionName, 'x-display': collectionList.length > 1 ? 'visible' : 'hidden', 'x-decorator': 'FormItem', @@ -67,7 +72,7 @@ export const FormDataTemplates = observer((props: any) => { type: 'number', title: '{{ t("Template Data") }}', required: true, - description: '选择一条已有的数据作为表单的初始化数据', + description: t('Select an existing piece of data as the initialization data for the form'), 'x-decorator': 'FormItem', 'x-component': AssociationSelect, 'x-component-props': { @@ -79,14 +84,14 @@ export const FormDataTemplates = observer((props: any) => { objectValue: false, manual: false, mapOptions: (item) => { - // TODO: 应该使用 item.title 字段的值作为 label return { - label: item.id, + ...item, + [collection.titleField || 'label']: `#${item.id} ${item[collection.titleField] || ''}`, value: item.id, }; }, fieldNames: { - label: 'label', + label: collection.titleField || 'label', value: 'value', }, }, @@ -110,7 +115,7 @@ export const FormDataTemplates = observer((props: any) => { type: 'array', title: '{{ t("Data fields") }}', required: true, - description: '仅选择的字段才会作为表单的初始化数据', + description: t('Only the selected fields will be used as the initialization data for the form'), 'x-decorator': 'FormItem', 'x-component': Tree, 'x-component-props': { diff --git a/packages/plugins/client/src/locale/en-US.json b/packages/plugins/client/src/locale/en-US.json index af4e9f16b..c498f84fb 100644 --- a/packages/plugins/client/src/locale/en-US.json +++ b/packages/plugins/client/src/locale/en-US.json @@ -164,6 +164,7 @@ "Optional fields": "Optional fields", "System fields": "System fields", "General fields": "General fields", + "Inherited fields": "Inherited fields", "Parent collection fields": "Parent collection fields", "Basic": "Basic", "Single line text": "Single line text", diff --git a/packages/plugins/client/src/locale/pt-BR.json b/packages/plugins/client/src/locale/pt-BR.json index d35b666e9..cb88534bb 100644 --- a/packages/plugins/client/src/locale/pt-BR.json +++ b/packages/plugins/client/src/locale/pt-BR.json @@ -149,6 +149,7 @@ "Optional fields": "Campos opcionais", "System fields": "Campos do sistema", "General fields": "Campos gerais", + "Inherited fields": "Campos herdados", "Parent collection fields": "Campos da coleção pai", "Basic": "Básico", "Single line text": "Texto de linha única", diff --git a/packages/plugins/client/src/locale/zh-CN.json b/packages/plugins/client/src/locale/zh-CN.json index 5ec114e3d..0f8e08c27 100644 --- a/packages/plugins/client/src/locale/zh-CN.json +++ b/packages/plugins/client/src/locale/zh-CN.json @@ -164,6 +164,7 @@ "Optional fields": "可选字段", "System fields": "系统字段", "General fields": "普通字段", + "Inherited fields": "继承字段", "Parent collection fields": "父表字段", "Basic": "基本类型", "Single line text": "单行文本",