mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 10:01:26 +00:00
refactor(client): add component to support data source select (#3691)
This commit is contained in:
parent
d904d13c52
commit
f68b2fb04a
@ -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) => {
|
||||
|
@ -25,3 +25,4 @@ export * from './collectionPlugin';
|
||||
export * from './mixins/InheritanceCollectionMixin';
|
||||
export * from './sub-table';
|
||||
export * from './CollectionHistoryProvider';
|
||||
export * from './utils';
|
||||
|
16
packages/core/client/src/collection-manager/utils.ts
Normal file
16
packages/core/client/src/collection-manager/utils.ts
Normal file
@ -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}`;
|
||||
}
|
@ -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": "认证与安全",
|
||||
|
@ -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<any, any> & {
|
||||
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
|
||||
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 (
|
||||
<Select
|
||||
// @ts-ignore
|
||||
@ -52,10 +64,7 @@ export const CollectionSelect = connect(
|
||||
popupMatchSelectWidth={false}
|
||||
{...others}
|
||||
showSearch
|
||||
filterOption={(input, option) =>
|
||||
(option?.label.toLowerCase() ?? '').includes(input.toLocaleLowerCase()) ||
|
||||
(option?.value.toString().toLowerCase() ?? '').includes(input.toLocaleLowerCase())
|
||||
}
|
||||
filterOption={optionFilter}
|
||||
options={options}
|
||||
/>
|
||||
);
|
||||
@ -65,7 +74,7 @@ export const CollectionSelect = connect(
|
||||
(props: CollectionSelectProps) => {
|
||||
const { mode } = props;
|
||||
const compile = useCompile();
|
||||
const options = useOptions(props).filter((option) => {
|
||||
const options = useCollectionOptions(props).filter((option) => {
|
||||
if (mode === 'multiple') {
|
||||
return (props.value ?? []).includes(option.value);
|
||||
}
|
||||
@ -86,3 +95,88 @@ export const CollectionSelect = connect(
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
export type DataSourceSelectProps = SelectProps<any, any> & {
|
||||
filter?: (item: any, index: number, array: any[]) => boolean;
|
||||
};
|
||||
|
||||
function useDataSourceOptions({ filter }: DataSourceSelectProps) {
|
||||
const compile = useCompile();
|
||||
const dataSourceManager = useDataSourceManager();
|
||||
const dataSources = dataSourceManager.getDataSources();
|
||||
return useMemo(
|
||||
() => [
|
||||
{
|
||||
label: compile('Main'),
|
||||
value: 'main',
|
||||
},
|
||||
...(typeof filter === 'function' ? dataSources.filter(filter) : dataSources).map((item) => ({
|
||||
label: item.displayName,
|
||||
value: item.key,
|
||||
})),
|
||||
],
|
||||
[dataSources, filter],
|
||||
);
|
||||
}
|
||||
|
||||
export const DataSourceSelect = connect((props: DataSourceSelectProps) => {
|
||||
const { filter, ...others } = props;
|
||||
const options = useDataSourceOptions(props);
|
||||
const { t } = useTranslation();
|
||||
const optionFilter = useCallback(
|
||||
(input, option) =>
|
||||
(option?.label.toLowerCase() ?? '').includes(input.toLocaleLowerCase()) ||
|
||||
(option?.value.toString().toLowerCase() ?? '').includes(input.toLocaleLowerCase()),
|
||||
[],
|
||||
);
|
||||
return (
|
||||
<Select
|
||||
// @ts-ignore
|
||||
role="button"
|
||||
data-testid="select-datasource"
|
||||
placeholder={t('Select data source')}
|
||||
popupMatchSelectWidth={false}
|
||||
{...others}
|
||||
showSearch
|
||||
filterOption={optionFilter}
|
||||
options={options}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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 <Cascader showSearch {...others} options={options} value={path} onChange={handleChange} />;
|
||||
});
|
||||
|
@ -9,3 +9,4 @@ export * from './load-default-actions';
|
||||
export * from './types';
|
||||
|
||||
export * from './data-source-with-database';
|
||||
export * from './utils';
|
||||
|
9
packages/core/data-source-manager/src/utils.ts
Normal file
9
packages/core/data-source-manager/src/utils.ts
Normal file
@ -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];
|
||||
}
|
Loading…
Reference in New Issue
Block a user