diff --git a/packages/core/client/src/collection-manager/action-hooks.ts b/packages/core/client/src/collection-manager/action-hooks.ts index 2d459d8772..d7b6b0418b 100644 --- a/packages/core/client/src/collection-manager/action-hooks.ts +++ b/packages/core/client/src/collection-manager/action-hooks.ts @@ -132,10 +132,10 @@ export const useSelfAndChildrenCollections = (collectionName: string) => { return options; }; -export const useCollectionFilterOptions = (collection: any) => { +export const useCollectionFilterOptions = (collection: any, dataSource?: string) => { const { getCollectionFields, getInterface } = useCollectionManager_deprecated(); return useMemo(() => { - const fields = getCollectionFields(collection); + const fields = getCollectionFields(collection, dataSource); const field2option = (field, depth) => { if (!field.interface) { return; @@ -165,7 +165,7 @@ export const useCollectionFilterOptions = (collection: any) => { option['children'] = children; } if (nested) { - const targetFields = getCollectionFields(field.target); + const targetFields = getCollectionFields(field.target, dataSource); const options = getOptions(targetFields, depth + 1).filter(Boolean); option['children'] = option['children'] || []; option['children'].push(...options); @@ -184,7 +184,7 @@ export const useCollectionFilterOptions = (collection: any) => { }; const options = getOptions(fields, 1); return options; - }, [_.isString(collection) ? collection : collection?.name]); + }, [_.isString(collection) ? collection : collection?.name, dataSource]); }; export const useCollectionFilterOptionsV2 = (collection: any) => { diff --git a/packages/core/client/src/collection-manager/index.tsx b/packages/core/client/src/collection-manager/index.tsx index b6a07d48d5..ce636b4df9 100644 --- a/packages/core/client/src/collection-manager/index.tsx +++ b/packages/core/client/src/collection-manager/index.tsx @@ -25,3 +25,4 @@ export * from './collectionPlugin'; export * from './mixins/InheritanceCollectionMixin'; export * from './sub-table'; export * from './CollectionHistoryProvider'; +export * from './utils'; diff --git a/packages/core/client/src/collection-manager/utils.ts b/packages/core/client/src/collection-manager/utils.ts new file mode 100644 index 0000000000..392a01bd29 --- /dev/null +++ b/packages/core/client/src/collection-manager/utils.ts @@ -0,0 +1,16 @@ +export function parseCollectionName(collection: string) { + if (!collection) { + return []; + } + const dataSourceCollection = collection.split(':'); + const collectionName = dataSourceCollection.pop(); + const dataSourceName = dataSourceCollection[0] ?? 'main'; + return [dataSourceName, collectionName]; +} + +export function joinCollectionName(dataSourceName: string, collectionName: string) { + if (!dataSourceName || dataSourceName === 'main') { + return collectionName; + } + return `${dataSourceName}:${collectionName}`; +} diff --git a/packages/core/client/src/locale/zh-CN.json b/packages/core/client/src/locale/zh-CN.json index 96591b4b72..d0d907b5b2 100644 --- a/packages/core/client/src/locale/zh-CN.json +++ b/packages/core/client/src/locale/zh-CN.json @@ -851,7 +851,7 @@ "loading": "加载中", "name is required": "名称不能为空", "The {{type}} \"{{name}}\" may have been deleted. Please remove this {{blockType}}.": "{{type}} \"{{name}}\" 可能已被删除。请删除当前{{blockType}}.", - "data source": "数据源", + "Data source": "数据源", "DataSource": "数据源", "Data model": "数据模型", "Security": "认证与安全", diff --git a/packages/core/client/src/schema-component/antd/collection-select/CollectionSelect.tsx b/packages/core/client/src/schema-component/antd/collection-select/CollectionSelect.tsx index fab0388f7c..ad0dd3c141 100644 --- a/packages/core/client/src/schema-component/antd/collection-select/CollectionSelect.tsx +++ b/packages/core/client/src/schema-component/antd/collection-select/CollectionSelect.tsx @@ -1,18 +1,20 @@ import { connect, mapReadPretty, observer, useField } from '@formily/react'; -import { Select, SelectProps, Tag } from 'antd'; -import React, { useContext } from 'react'; +import { Cascader, Select, SelectProps, Tag } from 'antd'; +import React, { useCallback, useContext, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelfAndChildrenCollections } from '../../../collection-manager/action-hooks'; import { useCollection_deprecated, useCollectionManager_deprecated } from '../../../collection-manager/hooks'; import { useCompile } from '../../hooks'; import { FilterContext } from '../filter/context'; +import { useDataSourceManager } from '../../../data-source'; +import { parseCollectionName } from '../../../collection-manager'; export type CollectionSelectProps = SelectProps & { filter?: (item: any, index: number, array: any[]) => boolean; isTableOid?: boolean; }; -function useOptions({ filter, isTableOid }: CollectionSelectProps) { +function useCollectionOptions({ filter, isTableOid }: CollectionSelectProps) { const compile = useCompile(); const field: any = useField(); const ctx: any = useContext(FilterContext); @@ -29,20 +31,30 @@ function useOptions({ filter, isTableOid }: CollectionSelectProps) { typeof filter === 'function' ? ((inheritCollections || currentCollections) as any[]).filter(filter) : inheritCollections || currentCollections; - return filtered - .filter((item) => !item.hidden) - .map((item) => ({ - label: compile(item.title || item.label), - value: item.name || item.value, - color: item.category?.color, - })); + return useMemo( + () => + filtered + .filter((item) => !item.hidden) + .map((item) => ({ + label: compile(item.title || item.label), + value: item.name || item.value, + color: item.category?.color, + })), + [filtered], + ); } export const CollectionSelect = connect( (props: CollectionSelectProps) => { const { filter, ...others } = props; - const options = useOptions(props); + const options = useCollectionOptions(props); const { t } = useTranslation(); + const optionFilter = useCallback( + (input, option) => + (option?.label.toLowerCase() ?? '').includes(input.toLocaleLowerCase()) || + (option?.value.toString().toLowerCase() ?? '').includes(input.toLocaleLowerCase()), + [], + ); return ( + ); +}); + +export const DataSourceCollectionCascader = connect((props) => { + const dataSourceManager = useDataSourceManager(); + const compile = useCompile(); + const { value, onChange, dataSourceFilter, collectionFilter, ...others } = props; + const [dataSourceName, collectionName] = parseCollectionName(value); + const path = [dataSourceName, collectionName].filter(Boolean); + const dataSources = dataSourceManager.getDataSources(); + + const options = useMemo(() => { + return (dataSourceFilter ? dataSources.filter(dataSourceFilter) : dataSources).map((dataSource) => { + return { + label: compile(dataSource.displayName), + value: dataSource.key, + children: dataSource.collectionManager.collectionInstancesArr + .filter(collectionFilter ?? ((collection) => !collection.hidden)) + .map((collection) => { + return { + label: compile(collection.title), + value: collection.name, + }; + }), + }; + }); + }, [dataSources, dataSourceFilter, collectionFilter]); + + const handleChange = useCallback( + (value) => { + if (!value) { + return onChange(value); + } + onChange(value[0] === 'main' ? value[1] : value.join(':')); + }, + [onChange], + ); + return ; +}); diff --git a/packages/core/data-source-manager/src/index.ts b/packages/core/data-source-manager/src/index.ts index 3abc107ee1..a7aec23a15 100644 --- a/packages/core/data-source-manager/src/index.ts +++ b/packages/core/data-source-manager/src/index.ts @@ -9,3 +9,4 @@ export * from './load-default-actions'; export * from './types'; export * from './data-source-with-database'; +export * from './utils'; diff --git a/packages/core/data-source-manager/src/utils.ts b/packages/core/data-source-manager/src/utils.ts new file mode 100644 index 0000000000..79eec06f68 --- /dev/null +++ b/packages/core/data-source-manager/src/utils.ts @@ -0,0 +1,9 @@ +export function parseCollectionName(collection: string) { + if (!collection) { + return []; + } + const dataSourceCollection = collection.split(':'); + const collectionName = dataSourceCollection.pop(); + const dataSourceName = dataSourceCollection[0] ?? 'main'; + return [dataSourceName, collectionName]; +}