diff --git a/packages/base/src/data/EmitterKey.ts b/packages/base/src/data/EmitterKey.ts index 1dfe88a44..492004229 100644 --- a/packages/base/src/data/EmitterKey.ts +++ b/packages/base/src/data/EmitterKey.ts @@ -12,7 +12,8 @@ enum EmitterKey { DMS_Sync_Project_Archived_Status = 'DMS_Sync_Project_Archived_Status', DMS_Refresh_Export_Data_Workflow = 'DMS_Refresh_Export_Data_Workflow', DMS_Refresh_Sync_Data_Source = 'DMS_Refresh_Sync_Data_Source', - DMS_Refresh_Global_Data_Source = 'DMS_Refresh_Global_Data_Source' + DMS_Refresh_Global_Data_Source = 'DMS_Refresh_Global_Data_Source', + DMS_Batch_Test_Data_Source_Connection = 'DMS_Batch_Test_Data_Source_Connection' } export default EmitterKey; diff --git a/packages/base/src/hooks/useStaticTips/index.data.ts b/packages/base/src/hooks/useStaticTips/index.data.ts new file mode 100644 index 000000000..c61673f82 --- /dev/null +++ b/packages/base/src/hooks/useStaticTips/index.data.ts @@ -0,0 +1,16 @@ +import { ListDBServicesFilterLastConnectionTestStatusEnum } from '@actiontech/shared/lib/api/base/service/DBService/index.enum'; +import { t } from '../../locale'; + +type IStaticEnumDictionary = { + [key in T]: string; +}; + +export const databaseTestConnectionStatusDictionary: IStaticEnumDictionary = + { + [ListDBServicesFilterLastConnectionTestStatusEnum.connect_failed]: t( + 'dmsDataSource.batchTestConnection.connectFailed' + ), + [ListDBServicesFilterLastConnectionTestStatusEnum.connect_success]: t( + 'dmsDataSource.batchTestConnection.connectSucceed' + ) + }; diff --git a/packages/base/src/hooks/useStaticTips/index.ts b/packages/base/src/hooks/useStaticTips/index.ts new file mode 100644 index 000000000..8c39a3651 --- /dev/null +++ b/packages/base/src/hooks/useStaticTips/index.ts @@ -0,0 +1,22 @@ +import { ListDBServicesFilterLastConnectionTestStatusEnum } from '@actiontech/shared/lib/api/base/service/DBService/index.enum'; +import { SelectProps } from 'antd'; +import { useMemo } from 'react'; +import { databaseTestConnectionStatusDictionary } from './index.data'; + +const useStaticTips = () => { + const generateDatabaseTestConnectionStatusSelectOptions: SelectProps['options'] = + useMemo(() => { + return Object.values( + ListDBServicesFilterLastConnectionTestStatusEnum + ).map((v) => ({ + label: databaseTestConnectionStatusDictionary[v], + value: v + })); + }, []); + + return { + generateDatabaseTestConnectionStatusSelectOptions + }; +}; + +export default useStaticTips; diff --git a/packages/base/src/locale/zh-CN/dmsDataSource.ts b/packages/base/src/locale/zh-CN/dmsDataSource.ts index d539007eb..c23a69ebf 100644 --- a/packages/base/src/locale/zh-CN/dmsDataSource.ts +++ b/packages/base/src/locale/zh-CN/dmsDataSource.ts @@ -10,6 +10,12 @@ export default { instanceName: '数据源名', address: '地址', describe: '描述', + lastTestConnectionStatus: '上一次连接状态', + lastTestConnectionTime: '测试连通性时间', + lastTestConnectionErrorMessage: '测试失败原因', + connectSucceed: '连通性测试成功', + connectFailed: '连通性测试失败', + testConnectionStatusFilterLabel: '数据源连接状态', role: '角色', type: '数据源类型', enabledScanTypes: '启用的扫描类型', @@ -25,6 +31,7 @@ export default { addDatabase: '添加数据源', addDatabaseSuccess: '添加数据源成功', addDatabaseSuccessGuide: '到数据源列表查看刚刚添加的数据源', + batchTestDataSourceConnection: '批量测试数据源连通性', updateDatabase: { title: '编辑数据源', @@ -72,6 +79,13 @@ export default { errorTitle: '数据源{{instanceName}}连通性测试失败' }, + batchTestConnection: { + notFoundData: '当前列表无数据!', + connectFailed: '连接失败', + connectSucceed: '连接成功', + batchTestConnectionSuccessTips: '执行批量测试数据源连通性成功!' + }, + deleteDatabase: { confirmMessage: '确认删除数据源 "{{name}}"?', deletingDatabase: '正在删除数据源 "{{name}}"...', diff --git a/packages/base/src/locale/zh-CN/dmsGlobalDataSource.ts b/packages/base/src/locale/zh-CN/dmsGlobalDataSource.ts index 7972acb21..c8d596537 100644 --- a/packages/base/src/locale/zh-CN/dmsGlobalDataSource.ts +++ b/packages/base/src/locale/zh-CN/dmsGlobalDataSource.ts @@ -8,6 +8,8 @@ export default { instanceName: '数据源名', projectName: '项目名称', address: '地址', + lastTestConnectionStatus: '上一次连接状态', + testConnectionStatusFilterLabel: '数据源连接状态', describe: '描述', role: '角色', type: '数据源类型', @@ -29,7 +31,15 @@ export default { deleteSuccessTips: '删除数据源"{{name}}"成功' }, + batchTestConnection: { + notFoundData: '当前列表无数据!', + connectFailed: '连接失败', + connectSucceed: '连接成功', + batchTestConnectionSuccessTips: '执行批量测试数据源连通性成功!' + }, + addDatabase: '添加数据源', + batchTestDataSourceConnection: '批量测试数据源连通性', backToList: '返回全局数据源列表', batchImportDataSource: { buttonText: '批量导入数据源', diff --git a/packages/base/src/locale/zh-CN/dmsProject.ts b/packages/base/src/locale/zh-CN/dmsProject.ts index 401be5dac..395bdb5eb 100644 --- a/packages/base/src/locale/zh-CN/dmsProject.ts +++ b/packages/base/src/locale/zh-CN/dmsProject.ts @@ -71,10 +71,6 @@ export default { title: '批量导入数据源', successTitle: '批量导入数据源成功', checkSuccess: '校验通过', - testConnectLabel: '请测试数据源联通性', - testConnect: '批量测试数据源连通性', - testConnectSuccess: '测试连通性成功{{count}}个', - testConnectFail: '测试连通性失败{{count}}个,数据源为{{name}}', requestAuditErrorMessage: '当前导入信息存在校验失败,请结合下载文件中的提示进行修改,并重新导入' }, diff --git a/packages/base/src/page/DataExportManagement/Detail/components/ExportDetail/OverviewList/column.tsx b/packages/base/src/page/DataExportManagement/Detail/components/ExportDetail/OverviewList/column.tsx index 200cc674b..23f509747 100644 --- a/packages/base/src/page/DataExportManagement/Detail/components/ExportDetail/OverviewList/column.tsx +++ b/packages/base/src/page/DataExportManagement/Detail/components/ExportDetail/OverviewList/column.tsx @@ -13,7 +13,7 @@ import { InfoCircleOutlined } from '@actiontech/icons'; export const OverviewListColumn: () => ActiontechTableColumn< IGetDataExportTask, - [], + unknown, 'db_service' > = () => { return [ @@ -21,7 +21,7 @@ export const OverviewListColumn: () => ActiontechTableColumn< dataIndex: 'db_service', title: () => t('dmsDataExport.detail.exportResult.overview.column.dbService'), - render: (_, record: IGetDataExportTask) => { + render: (_, record) => { return record.db_info?.name ?? '-'; } }, @@ -29,7 +29,7 @@ export const OverviewListColumn: () => ActiontechTableColumn< dataIndex: 'status', title: () => t('dmsDataExport.detail.exportResult.overview.column.status'), - render: (status: IGetDataExportTask['status']) => { + render: (status) => { return ; } }, @@ -37,25 +37,25 @@ export const OverviewListColumn: () => ActiontechTableColumn< dataIndex: 'export_type', title: () => t('dmsDataExport.detail.exportResult.overview.column.exportType'), - render: (type: string) => type ?? '-' + render: (type) => type ?? '-' }, { dataIndex: 'export_file_type', title: () => t('dmsDataExport.detail.exportResult.overview.column.exportFileType'), - render: (type: string) => type ?? '-' + render: (type) => type ?? '-' }, { dataIndex: 'export_start_time', title: () => t('dmsDataExport.detail.exportResult.overview.column.exportStartTime'), - render: (time: string) => formatTime(time, '-') + render: (time) => formatTime(time, '-') }, { dataIndex: 'export_end_time', title: () => t('dmsDataExport.detail.exportResult.overview.column.exportEndTime'), - render: (time: string) => formatTime(time, '-') + render: (time) => formatTime(time, '-') } ]; }; diff --git a/packages/base/src/page/DataExportManagement/Detail/components/ExportDetail/OverviewList/index.tsx b/packages/base/src/page/DataExportManagement/Detail/components/ExportDetail/OverviewList/index.tsx index d98dbedaf..1fb28e90d 100644 --- a/packages/base/src/page/DataExportManagement/Detail/components/ExportDetail/OverviewList/index.tsx +++ b/packages/base/src/page/DataExportManagement/Detail/components/ExportDetail/OverviewList/index.tsx @@ -1,7 +1,6 @@ import { ActiontechTable } from '@actiontech/shared/lib/components/ActiontechTable'; import useDataExportDetailReduxManage from '../../../hooks/index.redux'; import { OverviewListAction, OverviewListColumn } from './column'; -import { IGetDataExportTask } from '@actiontech/shared/lib/api/base/service/common'; import DataExportTask from '@actiontech/shared/lib/api/base/service/DataExportTask'; import { useCurrentProject, @@ -49,7 +48,7 @@ const OverviewList: React.FC = () => { ? OverviewListAction(downloadLoading, downloadAction) : undefined } - onRow={(record: IGetDataExportTask) => { + onRow={(record) => { return { onClick() { updateCurTaskID(record.task_uid ?? ''); diff --git a/packages/base/src/page/DataSource/components/BatchImportDataSource/__snapshots__/index.test.tsx.snap b/packages/base/src/page/DataSource/components/BatchImportDataSource/__snapshots__/index.test.tsx.snap index 3d636a25a..ca48fbfcf 100644 --- a/packages/base/src/page/DataSource/components/BatchImportDataSource/__snapshots__/index.test.tsx.snap +++ b/packages/base/src/page/DataSource/components/BatchImportDataSource/__snapshots__/index.test.tsx.snap @@ -288,61 +288,6 @@ exports[`base/DataSource/BatchImportDataSource render check api return csv file -
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
@@ -600,61 +545,6 @@ exports[`base/DataSource/BatchImportDataSource render delete file 1`] = `
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
@@ -840,482 +730,6 @@ exports[`base/DataSource/BatchImportDataSource render init snap 1`] = `
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- - -
- -`; - -exports[`base/DataSource/BatchImportDataSource render test connection 1`] = ` - -
-
- -
- -
-
-
-
-

- - - - - 批量导入数据源 - -

-
-
-
- -
-
-
-
-
-
-
- -
- - - - -
-
-
-
-
- - - -
- - test.csv - - - - -
-
-
-
- -
-
-
-
-
- - - - - -
-
- -
-                              校验通过
-                            
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- - - - - -
-
- -
-                              测试连通性成功1个
-                            
-
-
-
-
-
-
-
- - - - - -
-
- -
-                              测试连通性失败1个,数据源为mysql_1
-                            
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/base/src/page/DataSource/components/BatchImportDataSource/index.test.tsx b/packages/base/src/page/DataSource/components/BatchImportDataSource/index.test.tsx index 4ff843582..18976106b 100644 --- a/packages/base/src/page/DataSource/components/BatchImportDataSource/index.test.tsx +++ b/packages/base/src/page/DataSource/components/BatchImportDataSource/index.test.tsx @@ -37,7 +37,6 @@ describe('base/DataSource/BatchImportDataSource', () => { await act(async () => jest.advanceTimersByTime(300)); expect(baseElement).toMatchSnapshot(); expect(screen.getByText('批量导入数据源')).toBeInTheDocument(); - expect(screen.getByText('批量测试数据源连通性')).toBeInTheDocument(); fireEvent.click(screen.getByText('返回数据源列表')); }); @@ -114,33 +113,6 @@ describe('base/DataSource/BatchImportDataSource', () => { expect(baseElement).toMatchSnapshot(); }); - it('render test connection', async () => { - const { baseElement } = superRender(); - await act(async () => jest.advanceTimersByTime(300)); - expect( - screen.getByText('批量测试数据源连通性').closest('button') - ).toBeDisabled(); - const file = new File([''], 'test.csv'); - fireEvent.change(getBySelector('#files', baseElement), { - target: { files: [file] } - }); - await act(async () => jest.advanceTimersByTime(100)); - expect(screen.getByText('test.csv')).toBeInTheDocument(); - await act(async () => jest.advanceTimersByTime(3000)); - expect( - screen.getByText('批量测试数据源连通性').closest('button') - ).not.toBeDisabled(); - fireEvent.click(screen.getByText('批量测试数据源连通性')); - await act(async () => jest.advanceTimersByTime(100)); - expect(dbServicesConnectionSpy).toHaveBeenCalledTimes(1); - await act(async () => jest.advanceTimersByTime(3000)); - expect(screen.getByText('测试连通性成功1个')).toBeInTheDocument(); - expect( - screen.getByText('测试连通性失败1个,数据源为mysql_1') - ).toBeInTheDocument(); - expect(baseElement).toMatchSnapshot(); - }); - it('render upload file', async () => { const { baseElement } = superRender(); await act(async () => jest.advanceTimersByTime(300)); diff --git a/packages/base/src/page/DataSource/components/BatchImportDataSource/index.tsx b/packages/base/src/page/DataSource/components/BatchImportDataSource/index.tsx index f04d491f8..81d1a43a4 100644 --- a/packages/base/src/page/DataSource/components/BatchImportDataSource/index.tsx +++ b/packages/base/src/page/DataSource/components/BatchImportDataSource/index.tsx @@ -124,7 +124,6 @@ const BatchImportDataSource = () => { diff --git a/packages/base/src/page/DataSource/components/List/ConnectionResultColumn.tsx b/packages/base/src/page/DataSource/components/List/ConnectionResultColumn.tsx new file mode 100644 index 000000000..4a94e60dc --- /dev/null +++ b/packages/base/src/page/DataSource/components/List/ConnectionResultColumn.tsx @@ -0,0 +1,74 @@ +import { useTranslation } from 'react-i18next'; +import { BasicTag, BasicToolTips } from '@actiontech/shared'; +import { formatTime } from '@actiontech/shared/lib/utils/Common'; +import { Space, Tag, Typography } from 'antd'; +import { ListDBServiceLastConnectionTestStatusEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; + +type Props = { + connectionStatus?: ListDBServiceLastConnectionTestStatusEnum; + connectionTestTime?: string; + connectionErrorMessage?: string; +}; + +const ConnectionStatusColumn: React.FC = ({ + connectionStatus, + connectionTestTime, + connectionErrorMessage +}) => { + const { t } = useTranslation(); + + if ( + connectionStatus === + ListDBServiceLastConnectionTestStatusEnum.connect_success + ) { + return ( + + {t('dmsDataSource.databaseList.lastTestConnectionTime')}: + {formatTime(connectionTestTime, '-')} + + } + > + + {t('dmsDataSource.databaseList.connectSucceed')} + + + ); + } + + if ( + connectionStatus === + ListDBServiceLastConnectionTestStatusEnum.connect_failed + ) { + return ( + + + {t('dmsDataSource.databaseList.lastTestConnectionTime')}: + {formatTime(connectionTestTime, '-')} + + + + {t('dmsDataSource.databaseList.lastTestConnectionErrorMessage')}: + + {connectionErrorMessage} + + + + } + > + + {t('dmsDataSource.databaseList.connectFailed')} + + + ); + } + + return <>-; +}; + +export default ConnectionStatusColumn; diff --git a/packages/base/src/page/DataSource/components/List/__snapshots__/index.ce.test.tsx.snap b/packages/base/src/page/DataSource/components/List/__snapshots__/index.ce.test.tsx.snap index 61d78f29d..36729d9c3 100644 --- a/packages/base/src/page/DataSource/components/List/__snapshots__/index.ce.test.tsx.snap +++ b/packages/base/src/page/DataSource/components/List/__snapshots__/index.ce.test.tsx.snap @@ -17,6 +17,19 @@ exports[`page/DataSource/DataSourceList render list snap 1`] = `
+
+ +
@@ -234,6 +247,7 @@ exports[`page/DataSource/DataSourceList render list snap 1`] = ` + @@ -254,6 +268,12 @@ exports[`page/DataSource/DataSourceList render list snap 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+
+
@@ -206,6 +210,7 @@ exports[`page/DataSource/DataSourceList render list no permission 1`] = ` + @@ -226,6 +231,12 @@ exports[`page/DataSource/DataSourceList render list no permission 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+
+
+ +
+ @@ -672,6 +706,12 @@ exports[`page/DataSource/DataSourceList render list snap 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+
+
+ +
+
+
+
+ + + + + + + 数据源连接状态 + + + 请选择{{name}} + + + +
+
+
+ @@ -1273,6 +1394,12 @@ exports[`page/DataSource/DataSourceList render table by filter enable masking 1` > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.13:33061 + +
+
+ + 连通性测试成功 + +
+
+ @@ -1493,7 +1647,9 @@ exports[`page/DataSource/DataSourceList render table by filter enable masking 1` + > + - + 10.186.62.13:33062 + +
+
+ + 连通性测试失败 + +
+
+ @@ -1598,11 +1772,7 @@ exports[`page/DataSource/DataSourceList render table by filter enable masking 1` -
- - -
+ - + > + - + +
+ +
+
+
+
+ + + + + + + 数据源连接状态 + + + 请选择{{name}} + + + +
+
+
+ @@ -2265,6 +2509,12 @@ exports[`page/DataSource/DataSourceList render table filter option val 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.13:33061 + +
+
+ + 连通性测试成功 + +
+
+ @@ -2485,7 +2762,9 @@ exports[`page/DataSource/DataSourceList render table filter option val 1`] = ` + > + - + 10.186.62.13:33062 + +
+
+ + 连通性测试失败 + +
+
+ @@ -2590,11 +2887,7 @@ exports[`page/DataSource/DataSourceList render table filter option val 1`] = ` -
- - -
+ - + > + - + +
@@ -3012,6 +3311,7 @@ exports[`page/DataSource/DataSourceList render table for action btn render table + @@ -3032,6 +3332,12 @@ exports[`page/DataSource/DataSourceList render table for action btn render table > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.13:33061 + +
+
+ + 连通性测试成功 + +
+
+ @@ -3252,7 +3585,9 @@ exports[`page/DataSource/DataSourceList render table for action btn render table + > + - + 10.186.62.13:33062 + +
+
+ + 连通性测试失败 + +
+
+ @@ -3315,11 +3668,7 @@ exports[`page/DataSource/DataSourceList render table for action btn render table -
- - -
+ - + > + - + +
+ +
+ @@ -3760,6 +4125,12 @@ exports[`page/DataSource/DataSourceList render table for action btn render table > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.13:33061 + +
+
+ + 连通性测试成功 + +
+
+ @@ -3980,7 +4378,9 @@ exports[`page/DataSource/DataSourceList render table for action btn render table + > + - + +
+ +
+ @@ -4590,6 +5004,12 @@ exports[`page/DataSource/DataSourceList render table for action btn render table > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.13:33061 + +
+
+ + 连通性测试成功 + +
+
+ @@ -4810,7 +5257,9 @@ exports[`page/DataSource/DataSourceList render table for action btn render table + > + - + +
+ +
+ @@ -5420,6 +5883,12 @@ exports[`page/DataSource/DataSourceList render table for api has data 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.13:33061 + +
+
+ + 连通性测试成功 + +
+
+ @@ -5640,7 +6136,9 @@ exports[`page/DataSource/DataSourceList render table for api has data 1`] = ` + > + - + 10.186.62.13:33062 + +
+
+ + 连通性测试失败 + +
+
+ @@ -5745,11 +6261,7 @@ exports[`page/DataSource/DataSourceList render table for api has data 1`] = ` -
- - -
+ - + > + - + +
+ +
+ @@ -6257,6 +6785,12 @@ exports[`page/DataSource/DataSourceList render table for api has data 2`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.13:33061 + +
+
+ + 连通性测试成功 + +
+
+ @@ -6477,7 +7038,9 @@ exports[`page/DataSource/DataSourceList render table for api has data 2`] = ` + > + - + 10.186.62.13:33062 + +
+
+ + 连通性测试失败 + +
+
+ @@ -6582,11 +7163,7 @@ exports[`page/DataSource/DataSourceList render table for api has data 2`] = ` -
- - -
+ - + > + - + +
+ +
+ @@ -7069,6 +7662,12 @@ exports[`page/DataSource/DataSourceList render table for api return no data 1`] > 地址 + + 上一次连接状态 + + +
+   +
+
+
+ +
+ @@ -7490,6 +8112,12 @@ exports[`page/DataSource/DataSourceList render table for api return no data 2`] > 地址 + + 上一次连接状态 + + +
+   +
+
+
+ +
+ @@ -7911,6 +8562,12 @@ exports[`page/DataSource/DataSourceList render table for column val 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+ - + + - + @@ -8168,11 +8839,7 @@ exports[`page/DataSource/DataSourceList render table for column val 1`] = ` -
- - -
+ - => ({ + projectID: string, + batchTestDatabaseConnection: () => void, + batchTestDatabaseConnectionPending: boolean +): Record< + | 'batch-import-data-source' + | 'add-data-source' + | 'batch-test-data-source-connection', + ReactNode +> => ({ + 'batch-test-data-source-connection': ( + + + + ), 'batch-import-data-source': ( t('dmsDataSource.databaseList.lastTestConnectionStatus'), + filterCustomType: 'select', + filterKey: 'filter_last_connection_test_status', + filterLabel: t( + 'dmsDataSource.databaseList.testConnectionStatusFilterLabel' + ), + render: (status, record) => { + return ( + + ); + } + }, { dataIndex: 'source', title: () => t('dmsDataSource.databaseList.source') @@ -53,7 +69,7 @@ export const DataSourceColumns = ( dataIndex: 'desc', title: () => t('dmsDataSource.databaseList.describe'), className: 'ellipsis-column-width', - render: (desc: string) => { + render: (desc) => { return desc ? : '-'; } }, @@ -62,7 +78,7 @@ export const DataSourceColumns = ( title: () => t('dmsDataSource.databaseList.type'), filterCustomType: 'select', filterKey: 'filter_by_db_type', - render: (dbType: string) => { + render: (dbType) => { if (!dbType) return '-'; return ( @@ -77,7 +93,10 @@ export const DataSourceColumns = ( { dataIndex: 'audit_plan_types', title: () => t('dmsDataSource.databaseList.enabledScanTypes'), - render: (scanTypes: IAuditPlanTypes[], record) => { + render: (scanTypes, record) => { + if (!scanTypes || scanTypes.length === 0) { + return '-'; + } return ( t('dmsDataSource.databaseList.dataMask'), filterCustomType: 'select', filterKey: 'is_enable_masking', - render: (value: boolean) => { + render: (value) => { return value ? t('common.enabled') : t('common.notEnabled'); } }, @@ -108,7 +127,10 @@ export const DataSourceColumns = ( { dataIndex: 'maintenance_times', title: () => t('dmsDataSource.databaseList.maintenanceTime'), - render(value: IListDBService['maintenance_times']) { + render(value) { + if (!value || value.length === 0) { + return '-'; + } return value?.map((time, i) => ( {timeAddZero(time.maintenance_start_time?.hour ?? 0)}: diff --git a/packages/base/src/page/DataSource/components/List/index.test.tsx b/packages/base/src/page/DataSource/components/List/index.test.tsx index e7dba851f..8b336c421 100644 --- a/packages/base/src/page/DataSource/components/List/index.test.tsx +++ b/packages/base/src/page/DataSource/components/List/index.test.tsx @@ -25,6 +25,7 @@ describe('page/DataSource/DataSourceList', () => { const projectID = mockProjectInfo.projectID; const navigateSpy = jest.fn(); const useParamsMock: jest.Mock = useParams as jest.Mock; + let CheckProjectDBServicesConnectionsSpy: jest.SpyInstance; const customRender = (params = {}) => { return superRender(, undefined, { @@ -67,6 +68,8 @@ describe('page/DataSource/DataSourceList', () => { useParamsMock.mockReturnValue({ projectID }); dms.mockAllApi(); dbServices.ListDBServicesTips(); + CheckProjectDBServicesConnectionsSpy = + dbServices.CheckProjectDBServicesConnections(); }); afterEach(() => { @@ -197,7 +200,7 @@ describe('page/DataSource/DataSourceList', () => { '.actiontech-table-filter-container-namespace .ant-space-item', baseElement ); - expect(filterItems.length).toBe(3); + expect(filterItems.length).toBe(4); expect(baseElement).toMatchSnapshot(); }); @@ -270,9 +273,9 @@ describe('page/DataSource/DataSourceList', () => { '.actiontech-table-filter-container-namespace .ant-space-item', baseElement ); - expect(filterItems.length).toBe(3); + expect(filterItems.length).toBe(4); expect(baseElement).toMatchSnapshot(); - const enableFilterElement = getBySelector('input', filterItems[2]); + const enableFilterElement = getBySelector('input', filterItems[3]); fireEvent.mouseDown(enableFilterElement); const selectOptions = getAllBySelector('.ant-select-item-option'); await act(async () => { @@ -288,6 +291,42 @@ describe('page/DataSource/DataSourceList', () => { }); }); + it('should display an error message and return if dataSourceList is empty or undefined', async () => { + const requestTableList = dms.getListDBServices(); + requestTableList.mockImplementation(() => + createSpySuccessResponse({ data: [] }) + ); + customRender(); + + await act(async () => jest.advanceTimersByTime(6300)); + + fireEvent.click(screen.getByText('批量测试数据源连通性')); + expect(CheckProjectDBServicesConnectionsSpy).toHaveBeenCalledTimes(0); + expect(screen.getByText('当前列表无数据!')).toBeInTheDocument(); + }); + + it('should initiate the connection test and call DBService.CheckProjectDBServicesConnections when dataSourceList has valid data sources', async () => { + const requestTableList = dms.getListDBServices(); + customRender(); + + await act(async () => jest.advanceTimersByTime(6300)); + + fireEvent.click(screen.getByText('批量测试数据源连通性')); + expect(CheckProjectDBServicesConnectionsSpy).toHaveBeenCalledTimes(1); + expect(CheckProjectDBServicesConnectionsSpy).toHaveBeenCalledWith({ + project_uid: projectID, + db_services: DBServicesList.map((v) => ({ + db_service_uid: v.uid! + })) + }); + + await act(async () => jest.advanceTimersByTime(3000)); + expect(requestTableList).toHaveBeenCalledTimes(2); + expect( + screen.getByText('执行批量测试数据源连通性成功!') + ).toBeInTheDocument(); + }); + describe('render table for action btn', () => { it('render table for edit action', async () => { const requestTableList = dms.getListDBServices(); diff --git a/packages/base/src/page/DataSource/components/List/index.tsx b/packages/base/src/page/DataSource/components/List/index.tsx index 2f89c0633..e7325f5a7 100644 --- a/packages/base/src/page/DataSource/components/List/index.tsx +++ b/packages/base/src/page/DataSource/components/List/index.tsx @@ -12,7 +12,7 @@ import { useDbServiceDriver } from '@actiontech/shared/lib/global'; import useDbService from '../../../../hooks/useDbService'; -import { useRequest } from 'ahooks'; +import { useBoolean, useRequest } from 'ahooks'; import DBService from '@actiontech/shared/lib/api/base/service/DBService'; import { ResponseCode } from '@actiontech/shared/lib/enum'; import { @@ -34,6 +34,7 @@ import { import usePermission from '@actiontech/shared/lib/global/usePermission/usePermission'; import { DataSourceListActions, DataSourcePageHeaderActions } from './actions'; import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import useStaticTips from '../../../../hooks/useStaticTips'; const DataSourceList = () => { const { t } = useTranslation(); @@ -45,6 +46,11 @@ const DataSourceList = () => { const { parse2TableActionPermissions } = usePermission(); const { projectID } = useCurrentProject(); + const [ + batchTestDatabaseConnectionPending, + { setFalse: finishTestConnection, setTrue: startTestConnection } + ] = useBoolean(); + const { dbDriverOptions, getLogoUrlByDbType, @@ -57,6 +63,8 @@ const DataSourceList = () => { updateDbServiceList } = useDbService(); + const { generateDatabaseTestConnectionStatusSelectOptions } = useStaticTips(); + const { tableFilterInfo, updateTableFilterInfo, @@ -214,6 +222,34 @@ const DataSourceList = () => { [messageApi, modalApi, projectID, t] ); + const batchTestDatabaseConnection = () => { + if (!dataSourceList?.list || dataSourceList.list.length === 0) { + messageApi.error(t('dmsDataSource.batchTestConnection.notFoundData')); + return; + } + startTestConnection(); + DBService.CheckProjectDBServicesConnections({ + project_uid: projectID, + db_services: + dataSourceList?.list?.map((v) => ({ + db_service_uid: v.uid! + })) ?? [] + }) + .then((res) => { + if (res.data.code === ResponseCode.SUCCESS) { + refresh(); + messageApi.success( + t( + 'dmsDataSource.batchTestConnection.batchTestConnectionSuccessTips' + ) + ); + } + }) + .finally(() => { + finishTestConnection(); + }); + }; + const columns = useMemo( () => DataSourceColumns(getLogoUrlByDbType), [getLogoUrlByDbType] @@ -232,6 +268,10 @@ const DataSourceList = () => { 'db_type', { options: dbDriverOptions, loading: getDriveOptionsLoading } ], + [ + 'last_connection_test_status', + { options: generateDatabaseTestConnectionStatusSelectOptions } + ], // #if [dms] ['is_enable_masking', { options: filterDataMaskOptions }] // #endif @@ -239,6 +279,7 @@ const DataSourceList = () => { }, [ dbDriverOptions, dbServiceOptions, + generateDatabaseTestConnectionStatusSelectOptions, getDbServiceOptionsLoading, getDriveOptionsLoading ]); @@ -259,7 +300,11 @@ const DataSourceList = () => { testDatabaseConnection, navigateToSqlManagementConf ]); - const pageHeaderActions = DataSourcePageHeaderActions(projectID); + const pageHeaderActions = DataSourcePageHeaderActions( + projectID, + batchTestDatabaseConnection, + batchTestDatabaseConnectionPending + ); useEffect(() => { if (projectID) { @@ -277,6 +322,7 @@ const DataSourceList = () => { title={t('dmsDataSource.databaseListTitle')} extra={ + {pageHeaderActions['batch-test-data-source-connection']} {/* #if [ee] */} {pageHeaderActions['batch-import-data-source']} {/* #endif */} diff --git a/packages/base/src/page/DataSourceManagement/__tests__/__snapshots__/index.test.tsx.snap b/packages/base/src/page/DataSourceManagement/__tests__/__snapshots__/index.test.tsx.snap index 3a5a43329..00677a35f 100644 --- a/packages/base/src/page/DataSourceManagement/__tests__/__snapshots__/index.test.tsx.snap +++ b/packages/base/src/page/DataSourceManagement/__tests__/__snapshots__/index.test.tsx.snap @@ -47,16 +47,106 @@ exports[`test DataSourceManagement should match snapshot 1`] = `
@@ -280,6 +370,12 @@ exports[`test DataSourceManagement should match snapshot 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+
diff --git a/packages/base/src/page/DataSourceManagement/__tests__/index.test.tsx b/packages/base/src/page/DataSourceManagement/__tests__/index.test.tsx index 3dee1b50f..8641a5b22 100644 --- a/packages/base/src/page/DataSourceManagement/__tests__/index.test.tsx +++ b/packages/base/src/page/DataSourceManagement/__tests__/index.test.tsx @@ -26,7 +26,10 @@ describe('test DataSourceManagement', () => { syncTaskList.mockAllApi(); (useNavigate as jest.Mock).mockImplementation(() => navigateSpy); mockUsePermission( - { checkPagePermission: jest.fn().mockReturnValue(true) }, + { + checkPagePermission: jest.fn().mockReturnValue(true), + checkActionPermission: jest.fn().mockReturnValue(true) + }, { useSpyOnMockHooks: true } ); }); @@ -69,6 +72,26 @@ describe('test DataSourceManagement', () => { ); }); + it('should send emit event when click batch test connect button', () => { + const emitSpy = jest.spyOn(eventEmitter, 'emit'); + + const { getByText } = superRender(); + + fireEvent.click(getByText('批量测试数据源连通性')); + + expect(emitSpy).toHaveBeenCalledTimes(1); + expect(emitSpy).toHaveBeenCalledWith( + EmitterKey.DMS_Batch_Test_Data_Source_Connection + ); + + fireEvent.click(getByText('外部数据源同步')); + fireEvent.click(getBySelector('.custom-icon-refresh')); + expect(emitSpy).toHaveBeenCalledTimes(2); + expect(emitSpy).toHaveBeenCalledWith( + EmitterKey.DMS_Refresh_Sync_Data_Source + ); + }); + it('should not render tabs item when use role is not admin or not project manager', () => { mockUsePermission( { diff --git a/packages/base/src/page/DataSourceManagement/action.tsx b/packages/base/src/page/DataSourceManagement/action.tsx index 637e66e9a..6ba9317dd 100644 --- a/packages/base/src/page/DataSourceManagement/action.tsx +++ b/packages/base/src/page/DataSourceManagement/action.tsx @@ -7,9 +7,13 @@ import { t } from '../../locale'; import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; export const DataSourceManagementPageHeaderActions = ( - activeKey: DataSourceManagerSegmentedKey + activeKey: DataSourceManagerSegmentedKey, + onBatchTestConnection: () => void ): Record< - 'add_sync_task' | 'batch_import_db_service' | 'add_db_service', + | 'add_sync_task' + | 'batch_import_db_service' + | 'add_db_service' + | 'batch_test_data_source_connection', ReactNode > => { return { @@ -52,6 +56,19 @@ export const DataSourceManagementPageHeaderActions = ( link={{ to: ROUTE_PATHS.BASE.GLOBAL_DATA_SOURCE.create }} /> + ), + batch_test_data_source_connection: ( + + ) }; }; diff --git a/packages/base/src/page/DataSourceManagement/index.tsx b/packages/base/src/page/DataSourceManagement/index.tsx index b97d183fb..17ff2623b 100644 --- a/packages/base/src/page/DataSourceManagement/index.tsx +++ b/packages/base/src/page/DataSourceManagement/index.tsx @@ -65,12 +65,19 @@ const DataSourceManagement: React.FC = () => { }, [checkPagePermission, t]); // #if [ee] + const onBatchTestConnection = () => { + eventEmitter.emit(EmitterKey.DMS_Batch_Test_Data_Source_Connection); + }; const renderExtra = () => { - const pageHeaderActions = DataSourceManagementPageHeaderActions(activeKey); + const pageHeaderActions = DataSourceManagementPageHeaderActions( + activeKey, + onBatchTestConnection + ); return ( <> {pageHeaderActions['add_sync_task']} + {pageHeaderActions['batch_test_data_source_connection']} {pageHeaderActions['batch_import_db_service']} {pageHeaderActions['add_db_service']} diff --git a/packages/base/src/page/GlobalDataSource/BatchImportDataSource/__tests__/__snapshots__/index.test.tsx.snap b/packages/base/src/page/GlobalDataSource/BatchImportDataSource/__tests__/__snapshots__/index.test.tsx.snap index 26ca108b7..86283df6e 100644 --- a/packages/base/src/page/GlobalDataSource/BatchImportDataSource/__tests__/__snapshots__/index.test.tsx.snap +++ b/packages/base/src/page/GlobalDataSource/BatchImportDataSource/__tests__/__snapshots__/index.test.tsx.snap @@ -284,61 +284,6 @@ exports[`base/GlobalDataSource/BatchImportDataSource render check api return csv
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
@@ -592,61 +537,6 @@ exports[`base/GlobalDataSource/BatchImportDataSource render delete file 1`] = `
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
@@ -828,478 +718,6 @@ exports[`base/GlobalDataSource/BatchImportDataSource render init snap 1`] = `
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- - -
- -`; - -exports[`base/GlobalDataSource/BatchImportDataSource render test connection 1`] = ` - -
-
-
- -
-
- -
-
-
-
-

- - - - - 批量导入数据源 - -

-
-
-
- -
-
-
-
-
-
-
- -
- - - - -
-
-
-
-
- - - -
- - test.csv - - - - -
-
-
-
- -
-
-
-
-
- - - - - -
-
- -
-                              校验通过
-                            
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- - - - - -
-
- -
-                              测试连通性成功1个
-                            
-
-
-
-
-
-
-
- - - - - -
-
- -
-                              测试连通性失败1个,数据源为mysql_1
-                            
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/base/src/page/GlobalDataSource/BatchImportDataSource/__tests__/index.test.tsx b/packages/base/src/page/GlobalDataSource/BatchImportDataSource/__tests__/index.test.tsx index e94e88630..e4e30b6d6 100644 --- a/packages/base/src/page/GlobalDataSource/BatchImportDataSource/__tests__/index.test.tsx +++ b/packages/base/src/page/GlobalDataSource/BatchImportDataSource/__tests__/index.test.tsx @@ -34,7 +34,6 @@ describe('base/GlobalDataSource/BatchImportDataSource', () => { await act(async () => jest.advanceTimersByTime(300)); expect(baseElement).toMatchSnapshot(); expect(screen.getByText('批量导入数据源')).toBeInTheDocument(); - expect(screen.getByText('批量测试数据源连通性')).toBeInTheDocument(); fireEvent.click(screen.getByText('返回全局数据源列表')); }); @@ -111,33 +110,6 @@ describe('base/GlobalDataSource/BatchImportDataSource', () => { expect(baseElement).toMatchSnapshot(); }); - it('render test connection', async () => { - const { baseElement } = superRender(); - await act(async () => jest.advanceTimersByTime(300)); - expect( - screen.getByText('批量测试数据源连通性').closest('button') - ).toBeDisabled(); - const file = new File([''], 'test.csv'); - fireEvent.change(getBySelector('#files', baseElement), { - target: { files: [file] } - }); - await act(async () => jest.advanceTimersByTime(100)); - expect(screen.getByText('test.csv')).toBeInTheDocument(); - await act(async () => jest.advanceTimersByTime(3000)); - expect( - screen.getByText('批量测试数据源连通性').closest('button') - ).not.toBeDisabled(); - fireEvent.click(screen.getByText('批量测试数据源连通性')); - await act(async () => jest.advanceTimersByTime(100)); - expect(dbServicesConnectionSpy).toHaveBeenCalledTimes(1); - await act(async () => jest.advanceTimersByTime(3000)); - expect(screen.getByText('测试连通性成功1个')).toBeInTheDocument(); - expect( - screen.getByText('测试连通性失败1个,数据源为mysql_1') - ).toBeInTheDocument(); - expect(baseElement).toMatchSnapshot(); - }); - it('render upload file', async () => { const { baseElement } = superRender(); await act(async () => jest.advanceTimersByTime(300)); diff --git a/packages/base/src/page/GlobalDataSource/BatchImportDataSource/index.tsx b/packages/base/src/page/GlobalDataSource/BatchImportDataSource/index.tsx index 3c1837f78..8a978cdfa 100644 --- a/packages/base/src/page/GlobalDataSource/BatchImportDataSource/index.tsx +++ b/packages/base/src/page/GlobalDataSource/BatchImportDataSource/index.tsx @@ -111,7 +111,6 @@ const GlobalBatchImportDataSource = () => { diff --git a/packages/base/src/page/GlobalDataSource/List/__tests__/__snapshots__/index.test.tsx.snap b/packages/base/src/page/GlobalDataSource/List/__tests__/__snapshots__/index.test.tsx.snap index b6a03bd6e..d3fb8c9ce 100644 --- a/packages/base/src/page/GlobalDataSource/List/__tests__/__snapshots__/index.test.tsx.snap +++ b/packages/base/src/page/GlobalDataSource/List/__tests__/__snapshots__/index.test.tsx.snap @@ -133,6 +133,7 @@ exports[`page/GlobalDataSource/List render list snap 1`] = ` + @@ -165,6 +166,12 @@ exports[`page/GlobalDataSource/List render list snap 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.41:3306 + +
+
+ + 连通性测试失败 + +
+
+ @@ -552,6 +586,24 @@ exports[`page/GlobalDataSource/List render list snap 1`] = ` > - + +
+
+ + 连通性测试成功 + +
+
+ @@ -675,6 +727,11 @@ exports[`page/GlobalDataSource/List render list snap 1`] = ` > - + + - + @@ -1069,6 +1126,7 @@ exports[`page/GlobalDataSource/List render list snap 2`] = ` + @@ -1101,6 +1159,12 @@ exports[`page/GlobalDataSource/List render list snap 2`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.41:3306 + +
+
+ + 连通性测试失败 + +
+
+ @@ -1488,6 +1579,24 @@ exports[`page/GlobalDataSource/List render list snap 2`] = ` > - + +
+
+ + 连通性测试成功 + +
+
+ @@ -1611,6 +1720,11 @@ exports[`page/GlobalDataSource/List render list snap 2`] = ` > - + + - + @@ -2035,6 +2149,64 @@ exports[`page/GlobalDataSource/List render table filter option val 1`] = ` />
+
+
+
+ + + + + + + 数据源连接状态 + + + 请选择{{name}} + + + +
+
+
+ @@ -2159,6 +2332,12 @@ exports[`page/GlobalDataSource/List render table filter option val 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.41:3306 + +
+
+ + 连通性测试失败 + +
+
+ @@ -2546,6 +2752,24 @@ exports[`page/GlobalDataSource/List render table filter option val 1`] = ` > - + +
+
+ + 连通性测试成功 + +
+
+ @@ -2669,6 +2893,11 @@ exports[`page/GlobalDataSource/List render table filter option val 1`] = ` > - + + - + @@ -3063,6 +3292,7 @@ exports[`page/GlobalDataSource/List render table for action btn render table for + @@ -3095,6 +3325,12 @@ exports[`page/GlobalDataSource/List render table for action btn render table for > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.41:3306 + +
+
+ + 连通性测试失败 + +
+
+ @@ -3882,6 +4145,7 @@ exports[`page/GlobalDataSource/List render table for action btn render table for + @@ -3914,6 +4178,12 @@ exports[`page/GlobalDataSource/List render table for action btn render table for > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.41:3306 + +
+
+ + 连通性测试失败 + +
+
+ @@ -4701,6 +4998,7 @@ exports[`page/GlobalDataSource/List render table for action btn should not rende + @@ -4733,6 +5031,12 @@ exports[`page/GlobalDataSource/List render table for action btn should not rende > 地址 + + 上一次连接状态 + + +
+   +
+ 10.186.62.41:3306 + +
+
+ + 连通性测试失败 + +
+
+ @@ -5078,6 +5409,24 @@ exports[`page/GlobalDataSource/List render table for action btn should not rende > - + +
+
+ + 连通性测试成功 + +
+
+ @@ -5159,6 +5508,11 @@ exports[`page/GlobalDataSource/List render table for action btn should not rende > - + + - + @@ -5511,6 +5865,7 @@ exports[`page/GlobalDataSource/List render table for api return no data 1`] = ` + @@ -5543,6 +5898,12 @@ exports[`page/GlobalDataSource/List render table for api return no data 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+
{ return { @@ -34,6 +36,7 @@ describe('page/GlobalDataSource/List', () => { let listGlobalDBServicesSpy: jest.SpyInstance; let getProjectListSpy: jest.SpyInstance; let listGlobalDBServicesTipsSpy: jest.SpyInstance; + let CheckGlobalDBServicesConnectionsSpy: jest.SpyInstance; const customRender = () => { return superRender(); @@ -46,6 +49,9 @@ describe('page/GlobalDataSource/List', () => { listGlobalDBServicesSpy = dbServices.listGlobalDBServices(); listGlobalDBServicesTipsSpy = dbServices.listGlobalDBServicesTips(); getProjectListSpy = project.getProjectList(); + CheckGlobalDBServicesConnectionsSpy = + project.CheckGlobalDBServicesConnections(); + (useNavigate as jest.Mock).mockImplementation(() => navigateSpy); jest.useFakeTimers(); dms.mockAllApi(); @@ -124,10 +130,47 @@ describe('page/GlobalDataSource/List', () => { '.actiontech-table-filter-container-namespace .ant-space-item', baseElement ); - expect(filterItems.length).toBe(2); + expect(filterItems.length).toBe(3); expect(baseElement).toMatchSnapshot(); }); + it('should display an error message and return if dataSourceList is empty or undefined', async () => { + listGlobalDBServicesSpy.mockImplementation(() => + createSpySuccessResponse({ data: [] }) + ); + customRender(); + + await act(async () => jest.advanceTimersByTime(3000)); + + act(() => { + eventEmitter.emit(EmitterKey.DMS_Batch_Test_Data_Source_Connection); + }); + + expect(CheckGlobalDBServicesConnectionsSpy).toHaveBeenCalledTimes(0); + + await screen.findByText('当前列表无数据!'); + }); + + it('should initiate the connection test and call DBService.CheckProjectDBServicesConnections when dataSourceList has valid data sources', async () => { + customRender(); + + await act(async () => jest.advanceTimersByTime(3000)); + act(() => { + eventEmitter.emit(EmitterKey.DMS_Batch_Test_Data_Source_Connection); + }); + + expect(CheckGlobalDBServicesConnectionsSpy).toHaveBeenCalledTimes(1); + expect(CheckGlobalDBServicesConnectionsSpy).toHaveBeenCalledWith({ + db_services: globalDataSourceMockData.map((v) => ({ + db_service_uid: v.uid! + })) + }); + + await act(async () => jest.advanceTimersByTime(3000)); + expect(listGlobalDBServicesSpy).toHaveBeenCalledTimes(2); + await screen.findByText('执行批量测试数据源连通性成功!'); + }); + describe('render table for action btn', () => { it('render table for edit action', async () => { listGlobalDBServicesSpy.mockImplementationOnce(() => diff --git a/packages/base/src/page/GlobalDataSource/List/columns.tsx b/packages/base/src/page/GlobalDataSource/List/columns.tsx index c60a0e37d..3815ed6a6 100644 --- a/packages/base/src/page/GlobalDataSource/List/columns.tsx +++ b/packages/base/src/page/GlobalDataSource/List/columns.tsx @@ -9,6 +9,8 @@ import { import BasicTypographyEllipsis from '@actiontech/shared/lib/components/BasicTypographyEllipsis'; import { IListGlobalDBServicesParams } from '@actiontech/shared/lib/api/base/service/DBService/index.d'; import { DatabaseTypeLogo } from '@actiontech/shared'; +import ConnectionResultColumn from '../../DataSource/components/List/ConnectionResultColumn'; +import { ListDBServiceLastConnectionTestStatusEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; export type GLobalDataSourceListParamType = PageInfoWithoutIndexAndSize< IListGlobalDBServicesParams & { page_index: number } @@ -46,6 +48,26 @@ export const GlobalDataSourceColumns = ( return `${record.host}:${record.port}`; } }, + { + dataIndex: 'last_connection_test_status', + title: () => t('dmsGlobalDataSource.list.lastTestConnectionStatus'), + filterCustomType: 'select', + filterKey: 'filter_last_connection_test_status', + filterLabel: t( + 'dmsGlobalDataSource.list.testConnectionStatusFilterLabel' + ), + render: (status, record) => { + return ( + + ); + } + }, { dataIndex: 'source', title: t('dmsGlobalDataSource.list.source') @@ -54,7 +76,7 @@ export const GlobalDataSourceColumns = ( dataIndex: 'desc', title: t('dmsGlobalDataSource.list.describe'), className: 'ellipsis-column-width', - render: (desc: string) => { + render: (desc) => { return desc ? : '-'; } }, @@ -63,7 +85,7 @@ export const GlobalDataSourceColumns = ( title: t('dmsGlobalDataSource.list.type'), filterCustomType: 'select', filterKey: 'filter_by_db_type', - render: (dbType: string) => { + render: (dbType) => { if (!dbType) return '-'; return ( diff --git a/packages/base/src/page/GlobalDataSource/List/index.tsx b/packages/base/src/page/GlobalDataSource/List/index.tsx index dfb5f0bcc..1e4e2f528 100644 --- a/packages/base/src/page/GlobalDataSource/List/index.tsx +++ b/packages/base/src/page/GlobalDataSource/List/index.tsx @@ -1,10 +1,11 @@ -import { useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { message, Modal } from 'antd'; import { TestConnectDisableReasonStyleWrapper } from '@actiontech/shared/lib/components/TestDatabaseConnectButton/style'; import { useDbServiceDriver } from '@actiontech/shared/lib/global'; import { useRequest } from 'ahooks'; import DBService from '@actiontech/shared/lib/api/base/service/DBService'; +import ProjectService from '@actiontech/shared/lib/api/base/service/Project'; import { ResponseCode } from '@actiontech/shared/lib/enum'; import { ActiontechTable, @@ -28,6 +29,7 @@ import usePermission from '@actiontech/shared/lib/global/usePermission/usePermis import { GlobalDataSourceListActions } from './action'; import { useTypedNavigate } from '@actiontech/shared'; import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import useStaticTips from '../../../hooks/useStaticTips'; const GlobalDataSourceList = () => { const { t } = useTranslation(); @@ -42,6 +44,8 @@ const GlobalDataSourceList = () => { const { getLogoUrlByDbType, updateDriverList } = useDbServiceDriver(); + const { generateDatabaseTestConnectionStatusSelectOptions } = useStaticTips(); + const { updateDbTypeList, dbTypeOptions, @@ -104,13 +108,18 @@ const GlobalDataSourceList = () => { [ 'project_name', { options: projectIDOptions, loading: getProjectsLoading } + ], + [ + 'last_connection_test_status', + { options: generateDatabaseTestConnectionStatusSelectOptions } ] ]); }, [ dbTypeOptions, getDbTypeListLoading, projectIDOptions, - getProjectsLoading + getProjectsLoading, + generateDatabaseTestConnectionStatusSelectOptions ]); const actions = useMemo(() => { @@ -219,6 +228,30 @@ const GlobalDataSourceList = () => { modalApi ]); + const batchTestDatabaseConnection = useCallback(() => { + if (!dataSourceList?.list || dataSourceList.list.length === 0) { + messageApi.error( + t('dmsGlobalDataSource.batchTestConnection.notFoundData') + ); + return; + } + ProjectService.CheckGlobalDBServicesConnections({ + db_services: + dataSourceList?.list?.map((v) => ({ + db_service_uid: v.uid! + })) ?? [] + }).then((res) => { + if (res.data.code === ResponseCode.SUCCESS) { + refresh(); + messageApi.success( + t( + 'dmsGlobalDataSource.batchTestConnection.batchTestConnectionSuccessTips' + ) + ); + } + }); + }, [dataSourceList?.list, messageApi, refresh, t]); + useEffect(() => { updateDriverList(); updateProjects(); @@ -226,15 +259,21 @@ const GlobalDataSourceList = () => { }, [updateDbTypeList, updateDriverList, updateProjects]); useEffect(() => { - const { unsubscribe } = eventEmitter.subscribe( + const { unsubscribe: unsubscribeRefresh } = eventEmitter.subscribe( EmitterKey.DMS_Refresh_Global_Data_Source, refresh ); + const { unsubscribe: unsubscribeBatchTest } = eventEmitter.subscribe( + EmitterKey.DMS_Batch_Test_Data_Source_Connection, + batchTestDatabaseConnection + ); + return () => { - unsubscribe(); + unsubscribeRefresh(); + unsubscribeBatchTest(); }; - }, [refresh]); + }, [refresh, batchTestDatabaseConnection]); return ( <> diff --git a/packages/base/src/page/GlobalDataSource/__tests__/__snapshots__/index.test.tsx.snap b/packages/base/src/page/GlobalDataSource/__tests__/__snapshots__/index.test.tsx.snap index 64dda3c71..eed24328c 100644 --- a/packages/base/src/page/GlobalDataSource/__tests__/__snapshots__/index.test.tsx.snap +++ b/packages/base/src/page/GlobalDataSource/__tests__/__snapshots__/index.test.tsx.snap @@ -157,6 +157,7 @@ exports[`test base/GlobalDataSource should match snapshot 1`] = ` + @@ -189,6 +190,12 @@ exports[`test base/GlobalDataSource should match snapshot 1`] = ` > 地址 + + 上一次连接状态 + + +
+   +
+
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
diff --git a/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.test.tsx b/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.test.tsx index 4dc0aa681..07d25e7f8 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.test.tsx +++ b/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.test.tsx @@ -34,7 +34,6 @@ describe('base/Project/BatchImportDataSourceForm', () => { @@ -46,10 +45,6 @@ describe('base/Project/BatchImportDataSourceForm', () => { expect(baseElement).toMatchSnapshot(); expect(screen.getByText('请选择导入文件')).toBeInTheDocument(); expect(screen.getByText('下载导入模板')).toBeInTheDocument(); - expect(screen.getByText('批量测试数据源连通性')).toBeInTheDocument(); - expect( - screen.getByText('批量测试数据源连通性').closest('button') - ).toBeDisabled(); }); test('render init snap', async () => { @@ -59,14 +54,6 @@ describe('base/Project/BatchImportDataSourceForm', () => { expect(getImportDBServicesTemplateSpy).toHaveBeenCalledTimes(1); }); - test('render test connection', async () => { - customRender(mockBatchImportDBCheckData); - await act(async () => jest.advanceTimersByTime(300)); - expect( - screen.getByText('批量测试数据源连通性').closest('button') - ).not.toBeDisabled(); - }); - test('render upload file error', async () => { customRender([], { success: false, errorMessage: 'test error' }); }); diff --git a/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.tsx b/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.tsx index 1d76414c3..18cab6de2 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.tsx +++ b/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.tsx @@ -1,4 +1,3 @@ -import { BasicButton, ReminderInformation, EmptyBox } from '@actiontech/shared'; import { useTranslation } from 'react-i18next'; import { FormAreaBlockStyleWrapper, @@ -16,71 +15,17 @@ import { FileUploadCheckStatusType } from '../index.type'; import FileUpload from './FileUpload'; -import { UploadProps, Space } from 'antd'; -import Project from '@actiontech/shared/lib/api/base/service/Project'; -import { useBoolean } from 'ahooks'; -import { useState } from 'react'; -import { IDBServicesConnectionItem } from '@actiontech/shared/lib/api/base/service/common'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; -import { IDBService } from '@actiontech/shared/lib/api/base/service/common'; -import { useEffect } from 'react'; +import { UploadProps } from 'antd'; import { OverviewOutlined } from '@actiontech/icons'; const BatchImportDataSourceForm: React.FC<{ form: BatchImportDataSourceFormType; customRequest: UploadProps['customRequest']; - dbServices?: IDBService[]; uploadCheckStatus: FileUploadCheckStatusType; clearUploadCheckStatus: () => void; -}> = ({ - form, - customRequest, - dbServices, - uploadCheckStatus, - clearUploadCheckStatus -}) => { +}> = ({ form, customRequest, uploadCheckStatus, clearUploadCheckStatus }) => { const { t } = useTranslation(); - const [ - connectionTesting, - { setTrue: setConnectionTesting, setFalse: setConnectionTestingDone } - ] = useBoolean(); - - const [connectionTestResult, setConnectionTestResult] = - useState(); - - const onBatchTestConnection = async () => { - await form.validateFields(); - setConnectionTesting(); - Project.DBServicesConnection({ - db_services: dbServices?.map((i) => { - return { - additional_params: i.additional_params, - db_type: i.db_type ?? '', - host: i.host, - name: i.name, - password: i.password, - port: i.port, - user: i.user - }; - }) - }) - .then((res) => { - if (res.data.code === ResponseCode.SUCCESS) { - setConnectionTestResult(res.data.data); - } - }) - .finally(() => { - setConnectionTestingDone(); - }); - }; - - useEffect(() => { - if (!dbServices?.length) { - setConnectionTestResult(undefined); - } - }, [dbServices]); - return ( { clearUploadCheckStatus(); - setConnectionTestResult(undefined); }} accept=".csv" customRequest={customRequest} uploadCheckStatus={uploadCheckStatus} /> - - - - {t('dmsProject.batchImportDataSource.testConnect')} - - - - - - - - - ); diff --git a/packages/base/src/page/Project/BatchImportDataSource/__snapshots__/index.test.tsx.snap b/packages/base/src/page/Project/BatchImportDataSource/__snapshots__/index.test.tsx.snap index 2e6794bf3..9612cae8d 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/__snapshots__/index.test.tsx.snap +++ b/packages/base/src/page/Project/BatchImportDataSource/__snapshots__/index.test.tsx.snap @@ -288,61 +288,6 @@ exports[`base/Project/BatchImportDataSource render check api return csv file 1`]
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
@@ -600,61 +545,6 @@ exports[`base/Project/BatchImportDataSource render delete file 1`] = `
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
@@ -840,482 +730,6 @@ exports[`base/Project/BatchImportDataSource render init snap 1`] = `
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- - -
- -`; - -exports[`base/Project/BatchImportDataSource render test connection 1`] = ` - -
-
- -
- -
-
-
-
-

- - - - - 批量导入数据源 - -

-
-
-
- -
-
-
-
-
-
-
- -
- - - - -
-
-
-
-
- - - -
- - test.csv - - - - -
-
-
-
- -
-
-
-
-
- - - - - -
-
- -
-                              校验通过
-                            
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- - - - - -
-
- -
-                              测试连通性成功1个
-                            
-
-
-
-
-
-
-
- - - - - -
-
- -
-                              测试连通性失败1个,数据源为mysql_1
-                            
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/base/src/page/Project/BatchImportDataSource/index.test.tsx b/packages/base/src/page/Project/BatchImportDataSource/index.test.tsx index 826d5a999..119789c2b 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/index.test.tsx +++ b/packages/base/src/page/Project/BatchImportDataSource/index.test.tsx @@ -34,7 +34,6 @@ describe('base/Project/BatchImportDataSource', () => { await act(async () => jest.advanceTimersByTime(300)); expect(baseElement).toMatchSnapshot(); expect(screen.getByText('批量导入数据源')).toBeInTheDocument(); - expect(screen.getByText('批量测试数据源连通性')).toBeInTheDocument(); fireEvent.click(screen.getByText('返回项目列表')); }); @@ -111,33 +110,6 @@ describe('base/Project/BatchImportDataSource', () => { expect(baseElement).toMatchSnapshot(); }); - it('render test connection', async () => { - const { baseElement } = superRender(); - await act(async () => jest.advanceTimersByTime(300)); - expect( - screen.getByText('批量测试数据源连通性').closest('button') - ).toBeDisabled(); - const file = new File([''], 'test.csv'); - fireEvent.change(getBySelector('#files', baseElement), { - target: { files: [file] } - }); - await act(async () => jest.advanceTimersByTime(100)); - expect(screen.getByText('test.csv')).toBeInTheDocument(); - await act(async () => jest.advanceTimersByTime(3000)); - expect( - screen.getByText('批量测试数据源连通性').closest('button') - ).not.toBeDisabled(); - fireEvent.click(screen.getByText('批量测试数据源连通性')); - await act(async () => jest.advanceTimersByTime(100)); - expect(dbServicesConnectionSpy).toHaveBeenCalledTimes(1); - await act(async () => jest.advanceTimersByTime(3000)); - expect(screen.getByText('测试连通性成功1个')).toBeInTheDocument(); - expect( - screen.getByText('测试连通性失败1个,数据源为mysql_1') - ).toBeInTheDocument(); - expect(baseElement).toMatchSnapshot(); - }); - it('render upload file', async () => { const { baseElement } = superRender(); await act(async () => jest.advanceTimersByTime(300)); diff --git a/packages/base/src/page/Project/BatchImportDataSource/index.tsx b/packages/base/src/page/Project/BatchImportDataSource/index.tsx index 841a934b8..bf72236ff 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/index.tsx +++ b/packages/base/src/page/Project/BatchImportDataSource/index.tsx @@ -114,7 +114,6 @@ const BatchImportDataSource = () => { diff --git a/packages/base/src/testUtils/mockApi/dbServices/data.ts b/packages/base/src/testUtils/mockApi/dbServices/data.ts index 1d1a54728..226a4e70c 100644 --- a/packages/base/src/testUtils/mockApi/dbServices/data.ts +++ b/packages/base/src/testUtils/mockApi/dbServices/data.ts @@ -4,7 +4,10 @@ import { IListDBServiceTipItem, IListGlobalDBService } from '@actiontech/shared/lib/api/base/service/common'; -import { SQLQueryConfigAllowQueryWhenLessThanAuditLevelEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; +import { + ListGlobalDBServiceLastConnectionTestStatusEnum, + SQLQueryConfigAllowQueryWhenLessThanAuditLevelEnum +} from '@actiontech/shared/lib/api/base/service/common.enum'; export const dbServices: IListDBService[] = [ { @@ -99,7 +102,11 @@ export const globalDataSourceMockData: IListGlobalDBService[] = [ is_enable_masking: false, project_name: 'default', unfinished_workflow_num: 1, - is_enable_audit: true + is_enable_audit: true, + last_connection_test_error_message: 'error message', + last_connection_test_status: + ListGlobalDBServiceLastConnectionTestStatusEnum.connect_failed, + last_connection_test_time: '2024-11-15T15:28:13.315+08:00' }, { uid: '123457', @@ -115,7 +122,11 @@ export const globalDataSourceMockData: IListGlobalDBService[] = [ is_enable_masking: false, project_name: 'project1', unfinished_workflow_num: 0, - is_enable_audit: false + is_enable_audit: false, + last_connection_test_error_message: '', + last_connection_test_status: + ListGlobalDBServiceLastConnectionTestStatusEnum.connect_success, + last_connection_test_time: '2024-11-15T15:28:13.315+08:00' }, { uid: '123458', diff --git a/packages/base/src/testUtils/mockApi/dbServices/index.ts b/packages/base/src/testUtils/mockApi/dbServices/index.ts index 860209b78..8e7cc8506 100644 --- a/packages/base/src/testUtils/mockApi/dbServices/index.ts +++ b/packages/base/src/testUtils/mockApi/dbServices/index.ts @@ -23,6 +23,7 @@ class MockDbServicesApi implements MockSpyApy { this.checkDBServiceIsConnectableById(); this.listGlobalDBServices(); this.listGlobalDBServicesTips(); + this.CheckProjectDBServicesConnections(); } public ListDBServices() { @@ -117,6 +118,16 @@ class MockDbServicesApi implements MockSpyApy { ); return spy; } + + public CheckProjectDBServicesConnections() { + const spy = jest.spyOn(DBService, 'CheckProjectDBServicesConnections'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: globalDBServicesTipsMockData + }) + ); + return spy; + } } export default new MockDbServicesApi(); diff --git a/packages/base/src/testUtils/mockApi/global/data.ts b/packages/base/src/testUtils/mockApi/global/data.ts index 373e4b977..6dfa76cf2 100644 --- a/packages/base/src/testUtils/mockApi/global/data.ts +++ b/packages/base/src/testUtils/mockApi/global/data.ts @@ -5,7 +5,10 @@ import { ICompanyNotice, IListDBService } from '@actiontech/shared/lib/api/base/service/common'; -import { GetUserAuthenticationTypeEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; +import { + GetUserAuthenticationTypeEnum, + ListDBServiceLastConnectionTestStatusEnum +} from '@actiontech/shared/lib/api/base/service/common.enum'; import { SupportLanguage } from '@actiontech/shared/lib/enum'; export const UserInfo = { @@ -73,7 +76,11 @@ export const DBServicesList: IListDBService[] = [ instance_audit_plan_id: 1232, audit_plan_types: [ { type: 'mysql_slow_log', desc: '慢日志', audit_plan_id: 1 } - ] + ], + last_connection_test_error_message: '', + last_connection_test_status: + ListDBServiceLastConnectionTestStatusEnum.connect_success, + last_connection_test_time: '2024-11-15T15:05:10.175+08:00' }, { uid: '1739531942258282496', @@ -97,6 +104,10 @@ export const DBServicesList: IListDBService[] = [ audit_enabled: false } }, - is_enable_masking: false + is_enable_masking: false, + last_connection_test_error_message: 'error message', + last_connection_test_status: + ListDBServiceLastConnectionTestStatusEnum.connect_failed, + last_connection_test_time: '2024-11-15T15:05:10.175+08:00' } ]; diff --git a/packages/base/src/testUtils/mockApi/project/index.ts b/packages/base/src/testUtils/mockApi/project/index.ts index 946748ad4..2ecb290df 100644 --- a/packages/base/src/testUtils/mockApi/project/index.ts +++ b/packages/base/src/testUtils/mockApi/project/index.ts @@ -33,6 +33,7 @@ class MockProjectApi implements MockSpyApy { this.importDBServicesOfProjectsCheck(); this.importDBServicesOfOneProjectCheck(); this.dbServicesConnection(); + this.CheckGlobalDBServicesConnections(); } public getProjectList() { @@ -211,6 +212,12 @@ class MockProjectApi implements MockSpyApy { ); return spy; } + + public CheckGlobalDBServicesConnections() { + const spy = jest.spyOn(Project, 'CheckGlobalDBServicesConnections'); + spy.mockImplementation(() => createSpySuccessResponse({})); + return spy; + } } export default new MockProjectApi(); diff --git a/packages/shared/lib/api/base/service/DBService/index.d.ts b/packages/shared/lib/api/base/service/DBService/index.d.ts index 9dea570ac..b9d8f7cd2 100644 --- a/packages/shared/lib/api/base/service/DBService/index.d.ts +++ b/packages/shared/lib/api/base/service/DBService/index.d.ts @@ -1,6 +1,8 @@ import { ListGlobalDBServicesOrderByEnum, + ListGlobalDBServicesFilterLastConnectionTestStatusEnum, ListDBServicesOrderByEnum, + ListDBServicesFilterLastConnectionTestStatusEnum, ListDBServiceTipsFunctionalModuleEnum } from './index.enum'; @@ -13,6 +15,8 @@ import { IAddDBServiceReply, ICheckDBServiceIsConnectableReq, ICheckDBServiceIsConnectableReply, + ICheckDBServicesIsConnectableReq, + ICheckDBServicesIsConnectableReply, IImportDBServicesOfOneProjectReq, IGenericResp, IListDBServiceTipsReply, @@ -26,6 +30,8 @@ export interface IListGlobalDBServicesParams { order_by?: ListGlobalDBServicesOrderByEnum; + filter_last_connection_test_status?: ListGlobalDBServicesFilterLastConnectionTestStatusEnum; + filter_by_business?: string; filter_by_host?: string; @@ -63,6 +69,8 @@ export interface IListDBServicesParams { filter_by_business?: string; + filter_last_connection_test_status?: ListDBServicesFilterLastConnectionTestStatusEnum; + filter_by_host?: string; filter_by_uid?: string; @@ -75,6 +83,8 @@ export interface IListDBServicesParams { project_uid: string; + filter_by_db_service_ids?: string[]; + fuzzy_keyword?: string; is_enable_masking?: boolean; @@ -96,6 +106,14 @@ export interface ICheckDBServiceIsConnectableParams export interface ICheckDBServiceIsConnectableReturn extends ICheckDBServiceIsConnectableReply {} +export interface ICheckProjectDBServicesConnectionsParams + extends ICheckDBServicesIsConnectableReq { + project_uid: string; +} + +export interface ICheckProjectDBServicesConnectionsReturn + extends ICheckDBServicesIsConnectableReply {} + export interface IImportDBServicesOfOneProjectParams extends IImportDBServicesOfOneProjectReq { project_uid: string; diff --git a/packages/shared/lib/api/base/service/DBService/index.enum.ts b/packages/shared/lib/api/base/service/DBService/index.enum.ts index 015335988..431605f95 100644 --- a/packages/shared/lib/api/base/service/DBService/index.enum.ts +++ b/packages/shared/lib/api/base/service/DBService/index.enum.ts @@ -4,10 +4,22 @@ export enum ListGlobalDBServicesOrderByEnum { 'name' = 'name' } +export enum ListGlobalDBServicesFilterLastConnectionTestStatusEnum { + 'connect_success' = 'connect_success', + + 'connect_failed' = 'connect_failed' +} + export enum ListDBServicesOrderByEnum { 'name' = 'name' } +export enum ListDBServicesFilterLastConnectionTestStatusEnum { + 'connect_success' = 'connect_success', + + 'connect_failed' = 'connect_failed' +} + export enum ListDBServiceTipsFunctionalModuleEnum { 'save_audit_plan' = 'save_audit_plan', diff --git a/packages/shared/lib/api/base/service/DBService/index.ts b/packages/shared/lib/api/base/service/DBService/index.ts index ae7c6f96b..b757455dd 100644 --- a/packages/shared/lib/api/base/service/DBService/index.ts +++ b/packages/shared/lib/api/base/service/DBService/index.ts @@ -17,6 +17,8 @@ import { IAddDBServiceReturn, ICheckDBServiceIsConnectableParams, ICheckDBServiceIsConnectableReturn, + ICheckProjectDBServicesConnectionsParams, + ICheckProjectDBServicesConnectionsReturn, IImportDBServicesOfOneProjectParams, IImportDBServicesOfOneProjectReturn, IImportDBServicesOfOneProjectCheckParams, @@ -104,6 +106,21 @@ class DBServiceService extends ServiceBase { ); } + public CheckProjectDBServicesConnections( + params: ICheckProjectDBServicesConnectionsParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + return this.post( + `/v1/dms/projects/${project_uid}/db_services/connections`, + paramsData, + options + ); + } + public ImportDBServicesOfOneProject( params: IImportDBServicesOfOneProjectParams, options?: AxiosRequestConfig diff --git a/packages/shared/lib/api/base/service/Project/index.d.ts b/packages/shared/lib/api/base/service/Project/index.d.ts index 95815ca48..d74e00ffc 100644 --- a/packages/shared/lib/api/base/service/Project/index.d.ts +++ b/packages/shared/lib/api/base/service/Project/index.d.ts @@ -1,5 +1,6 @@ import { ListProjectsOrderByEnum, + ListProjectsFilterByProjectPriorityEnum, ExportProjectsOrderByEnum } from './index.enum'; @@ -9,6 +10,8 @@ import { IAddProjectReply, IDBServiceConnectionReq, IDBServicesConnectionReply, + IDBServicesConnectionReq, + IDBServicesConnectionReqReply, IImportProjectsReq, IGenericResp, IImportDBServicesOfProjectsReq, @@ -27,6 +30,10 @@ export interface IListProjectsParams { filter_by_name?: string; filter_by_uid?: string; + + filter_by_project_uids?: string[]; + + filter_by_project_priority?: ListProjectsFilterByProjectPriorityEnum; } export interface IListProjectsReturn extends IListProjectReply {} @@ -40,6 +47,12 @@ export interface IDBServicesConnectionParams extends IDBServiceConnectionReq {} export interface IDBServicesConnectionReturn extends IDBServicesConnectionReply {} +export interface ICheckGlobalDBServicesConnectionsParams + extends IDBServicesConnectionReq {} + +export interface ICheckGlobalDBServicesConnectionsReturn + extends IDBServicesConnectionReqReply {} + export interface IExportProjectsParams { order_by?: ExportProjectsOrderByEnum; diff --git a/packages/shared/lib/api/base/service/Project/index.enum.ts b/packages/shared/lib/api/base/service/Project/index.enum.ts index 68863110e..3b3db98a4 100644 --- a/packages/shared/lib/api/base/service/Project/index.enum.ts +++ b/packages/shared/lib/api/base/service/Project/index.enum.ts @@ -4,6 +4,16 @@ export enum ListProjectsOrderByEnum { 'name' = 'name' } +export enum ListProjectsFilterByProjectPriorityEnum { + 'high' = 'high', + + 'medium' = 'medium', + + 'low' = 'low', + + 'unknown' = 'unknown' +} + export enum ExportProjectsOrderByEnum { 'name' = 'name' } diff --git a/packages/shared/lib/api/base/service/Project/index.ts b/packages/shared/lib/api/base/service/Project/index.ts index fdde68c00..e183666f4 100644 --- a/packages/shared/lib/api/base/service/Project/index.ts +++ b/packages/shared/lib/api/base/service/Project/index.ts @@ -13,6 +13,8 @@ import { IAddProjectReturn, IDBServicesConnectionParams, IDBServicesConnectionReturn, + ICheckGlobalDBServicesConnectionsParams, + ICheckGlobalDBServicesConnectionsReturn, IExportProjectsParams, IImportProjectsParams, IImportProjectsReturn, @@ -67,6 +69,18 @@ class ProjectService extends ServiceBase { ); } + public CheckGlobalDBServicesConnections( + params: ICheckGlobalDBServicesConnectionsParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + return this.post( + '/v1/dms/projects/db_services_connections', + paramsData, + options + ); + } + public ExportProjects( params: IExportProjectsParams, options?: AxiosRequestConfig diff --git a/packages/shared/lib/api/base/service/common.d.ts b/packages/shared/lib/api/base/service/common.d.ts index 3e94bcbc6..bf853e4de 100644 --- a/packages/shared/lib/api/base/service/common.d.ts +++ b/packages/shared/lib/api/base/service/common.d.ts @@ -1,9 +1,12 @@ import { + DBServiceIsConnectableReplyConnectionStatusEnum, DMSProxyTargetScenarioEnum, GetDataExportTaskStatusEnum, GetUserAuthenticationTypeEnum, GetUserStatEnum, + ListDBServiceLastConnectionTestStatusEnum, ListDataExportWorkflowStatusEnum, + ListGlobalDBServiceLastConnectionTestStatusEnum, ListMemberRoleWithOpRangeOpRangeTypeEnum, ListOpPermissionRangeTypeEnum, ListProjectProjectPriorityEnum, @@ -345,6 +348,18 @@ export interface ICheckDBServiceIsConnectableReq { db_service?: ICheckDbConnectable; } +export interface ICheckDBServicesIsConnectableReply { + code?: number; + + data?: IDBServiceIsConnectableReply[]; + + message?: string; +} + +export interface ICheckDBServicesIsConnectableReq { + db_services?: IDbServiceConnections[]; +} + export interface ICheckDbConnectable { additional_params?: IAdditionalParam[]; @@ -406,6 +421,8 @@ export interface IDBService { desc?: string; + enable_backup?: boolean; + host: string; is_enable_masking?: boolean; @@ -427,6 +444,16 @@ export interface IDBServiceConnectionReq { db_services?: ICheckDbsConnectable[]; } +export interface IDBServiceIsConnectableReply { + connect_error_message?: string; + + connection_status?: DBServiceIsConnectableReplyConnectionStatusEnum; + + db_service_uid?: string; + + test_connection_time?: string; +} + export interface IDBServiceSyncTask { additional_params?: IParams; @@ -469,6 +496,18 @@ export interface IDBServicesConnectionReply { message?: string; } +export interface IDBServicesConnectionReq { + db_services?: IDbServiceConnections[]; +} + +export interface IDBServicesConnectionReqReply { + code?: number; + + data?: IDBServiceIsConnectableReply[]; + + message?: string; +} + export interface IDMSProxyTarget { addr: string; @@ -515,6 +554,10 @@ export interface IDatabaseDriverOption { params?: IDatabaseDriverAdditionalParam[]; } +export interface IDbServiceConnections { + db_service_uid?: string; +} + export interface IDelDBServicePreCheckReply { code?: number; @@ -1056,12 +1099,20 @@ export interface IListDBService { desc?: string; + enable_backup?: boolean; + host?: string; instance_audit_plan_id?: number; is_enable_masking?: boolean; + last_connection_test_error_message?: string; + + last_connection_test_status?: ListDBServiceLastConnectionTestStatusEnum; + + last_connection_test_time?: string; + maintenance_times?: IMaintenanceTime[]; name?: string; @@ -1220,12 +1271,20 @@ export interface IListGlobalDBService { desc?: string; + enable_backup?: boolean; + host?: string; is_enable_audit?: boolean; is_enable_masking?: boolean; + last_connection_test_error_message?: string; + + last_connection_test_status?: ListGlobalDBServiceLastConnectionTestStatusEnum; + + last_connection_test_time?: string; + maintenance_times?: IMaintenanceTime[]; name?: string; @@ -1880,6 +1939,8 @@ export interface IUpdateDBService { desc?: string; + enable_backup?: boolean; + host: string; is_enable_masking?: boolean; diff --git a/packages/shared/lib/api/base/service/common.enum.ts b/packages/shared/lib/api/base/service/common.enum.ts index 3e0d35164..0dbd3519f 100644 --- a/packages/shared/lib/api/base/service/common.enum.ts +++ b/packages/shared/lib/api/base/service/common.enum.ts @@ -1,3 +1,9 @@ +export enum DBServiceIsConnectableReplyConnectionStatusEnum { + 'connect_success' = 'connect_success', + + 'connect_failed' = 'connect_failed' +} + export enum DMSProxyTargetScenarioEnum { 'internal_service' = 'internal_service', @@ -40,6 +46,12 @@ export enum GetUserStatEnum { 'Unknown' = 'Unknown' } +export enum ListDBServiceLastConnectionTestStatusEnum { + 'connect_success' = 'connect_success', + + 'connect_failed' = 'connect_failed' +} + export enum ListDataExportWorkflowStatusEnum { 'wait_for_approve' = 'wait_for_approve', @@ -56,6 +68,12 @@ export enum ListDataExportWorkflowStatusEnum { 'finish' = 'finish' } +export enum ListGlobalDBServiceLastConnectionTestStatusEnum { + 'connect_success' = 'connect_success', + + 'connect_failed' = 'connect_failed' +} + export enum ListMemberRoleWithOpRangeOpRangeTypeEnum { 'unknown' = 'unknown', @@ -81,7 +99,9 @@ export enum ListProjectProjectPriorityEnum { 'medium' = 'medium', - 'low' = 'low' + 'low' = 'low', + + 'unknown' = 'unknown' } export enum ListRoleStatEnum { @@ -203,7 +223,9 @@ export enum ProjectProjectPriorityEnum { 'medium' = 'medium', - 'low' = 'low' + 'low' = 'low', + + 'unknown' = 'unknown' } export enum SQLQueryConfigAllowQueryWhenLessThanAuditLevelEnum { @@ -227,7 +249,9 @@ export enum UpdateProjectProjectPriorityEnum { 'medium' = 'medium', - 'low' = 'low' + 'low' = 'low', + + 'unknown' = 'unknown' } export enum WorkflowRecordStatusEnum { diff --git a/packages/shared/lib/components/ActiontechTable/Table.tsx b/packages/shared/lib/components/ActiontechTable/Table.tsx index 5341c81ca..ad43b3af8 100644 --- a/packages/shared/lib/components/ActiontechTable/Table.tsx +++ b/packages/shared/lib/components/ActiontechTable/Table.tsx @@ -1,12 +1,10 @@ import { Result, ConfigProvider } from 'antd'; -import { ActiontechTableProps } from './index.type'; +import { ActiontechTableColumn, ActiontechTableProps } from './index.type'; import ToolBar from './components/Toolbar'; import FilterContainer from './components/FilterContainer'; import { useTranslation } from 'react-i18next'; import { ActiontechTableStyleWrapper, tableToken } from './style'; -import useTableAction, { - ACTIONTECH_TABLE_OPERATOR_COLUMN_DATA_INDEX -} from './hooks/useTableAction'; +import useTableAction from './hooks/useTableAction'; import classnames from 'classnames'; import { useEffect, useMemo } from 'react'; import useTableSettings from './hooks/useTableSettings'; @@ -14,7 +12,7 @@ import useTableSettings from './hooks/useTableSettings'; const ActiontechTable = < T extends Record, F extends Record, - OtherColumnKeys extends string = '' + OtherColumnKeys extends string = never >({ className, toolbar, @@ -33,13 +31,15 @@ const ActiontechTable = < const { catchDefaultColumnsInfo, localColumns } = useTableSettings< T, F, - OtherColumnKeys | typeof ACTIONTECH_TABLE_OPERATOR_COLUMN_DATA_INDEX + OtherColumnKeys >(tableName, username); const mergerColumns = useMemo(() => { const operatorColumn = renderActionInTable(props.actions); - return operatorColumn ? [...columns, operatorColumn] : columns; + return ( + operatorColumn ? [...columns, operatorColumn] : columns + ) as ActiontechTableColumn; }, [columns, props.actions, renderActionInTable]); const innerColumns = useMemo(() => { diff --git a/packages/shared/lib/components/ActiontechTable/hooks/useTableAction.tsx b/packages/shared/lib/components/ActiontechTable/hooks/useTableAction.tsx index 4ceb1f75f..d0eb29df1 100644 --- a/packages/shared/lib/components/ActiontechTable/hooks/useTableAction.tsx +++ b/packages/shared/lib/components/ActiontechTable/hooks/useTableAction.tsx @@ -205,7 +205,7 @@ const useTableAction = () => { : actions.title ?? (() => t('common.operate')), fixed: Array.isArray(actions) ? 'right' : actions.fixed ?? 'right', width: Array.isArray(actions) ? maxWidth : actions.width ?? maxWidth, - render: (_, record: T) => renderContent(record) + render: (_: unknown, record: T) => renderContent(record) }; }, [renderAction, t] diff --git a/packages/shared/lib/components/ActiontechTable/hooks/useTableFilterContainer.tsx b/packages/shared/lib/components/ActiontechTable/hooks/useTableFilterContainer.tsx index 417f93587..0edad64c4 100644 --- a/packages/shared/lib/components/ActiontechTable/hooks/useTableFilterContainer.tsx +++ b/packages/shared/lib/components/ActiontechTable/hooks/useTableFilterContainer.tsx @@ -23,7 +23,7 @@ export const mergeFilterButtonMeta = < if (cur.filterCustomType) { result.set(cur.dataIndex, { checked: false, - filterLabel: getColumnsLabel(cur.title), + filterLabel: cur.filterLabel ?? getColumnsLabel(cur.title), filterCustomType: cur.filterCustomType }); } diff --git a/packages/shared/lib/components/ActiontechTable/hooks/useTableSettings.tsx b/packages/shared/lib/components/ActiontechTable/hooks/useTableSettings.tsx index ff1a4045b..f058e9794 100644 --- a/packages/shared/lib/components/ActiontechTable/hooks/useTableSettings.tsx +++ b/packages/shared/lib/components/ActiontechTable/hooks/useTableSettings.tsx @@ -13,7 +13,7 @@ import { isEqual } from 'lodash'; const useTableSettings = < T extends Record, F = Record, - OtherColumnKeys extends string = '' + OtherColumnKeys extends string = never >( tableName: string, username: string diff --git a/packages/shared/lib/components/ActiontechTable/index.type.ts b/packages/shared/lib/components/ActiontechTable/index.type.ts index 1985ac4d2..451dbe838 100644 --- a/packages/shared/lib/components/ActiontechTable/index.type.ts +++ b/packages/shared/lib/components/ActiontechTable/index.type.ts @@ -6,6 +6,7 @@ import { CustomSelectProps } from '../CustomSelect'; import { IBasicButton } from '../BasicButton'; import { ICustomInputProps } from '../CustomInput'; import { TypedLinkProps } from '../TypedRouter'; +import { ExcludeSymbol } from '../../types/common.type'; //======================================= utils @@ -19,7 +20,7 @@ type ComponentBaseType = { */ export type PageInfoWithoutIndexAndSize< T extends TablePagination & Record, - Other extends keyof T = '' + Other extends keyof T = never > = Omit; //======================================= @@ -201,7 +202,7 @@ export type TableRefreshButtonProps = { */ export type CatchTableColumnValueType< T = Record, - OtherColumnKeys extends string = '' + OtherColumnKeys extends string = never > = { /** * key 为用户名 @@ -348,29 +349,39 @@ export type ActiontechTableActionsConfig< * 表格 columns props, 当配置 filterCustomType 和 filterKey 启用该列的筛选功能, 通过 useTableFilterContainer 来生成 筛选项的元数据 * 当需要添加表格列以外的筛选列时, 可以使用 useTableFilterContainer 的第三个参数: extraFilterMeta */ -type ExcludeSymbol = T extends symbol ? never : T; +type ColumnValueType = K extends keyof T + ? T[K] + : never; + +type BaseColumnType> = { + show?: boolean; + dataIndex: ExcludeSymbol; + render?: ( + value: ColumnValueType, + record: T, + index: number + ) => ColumnType['render'] extends (...args: any) => infer R + ? R + : React.ReactNode; +} & Pick< + ActiontechTableFilterMetaValue, + 'filterCustomType' | 'filterKey' | 'filterLabel' +>; + export type ActiontechTableColumn< T = Record, F = Record, OtherColumnKeys extends string = never > = Array< - Omit | ColumnType, 'render' | 'dataIndex'> & - { - [K in keyof Required]: { - show?: boolean; - dataIndex: ExcludeSymbol; - render?: ( - value: K | OtherColumnKeys extends keyof T ? T[K] : never, - record: T, - index: number - ) => ColumnType['render'] extends (...args: any) => infer R - ? R - : React.ReactNode; - } & Pick< - ActiontechTableFilterMetaValue, - 'filterCustomType' | 'filterKey' - >; - }[keyof Required] + Omit | ColumnType, 'dataIndex' | 'render'> & + ( + | { + [K in keyof Required]: BaseColumnType; + }[keyof Required] + | { + [K in OtherColumnKeys]: BaseColumnType; + }[OtherColumnKeys] + ) >; export interface ActiontechTableProps< diff --git a/packages/shared/lib/global/usePermission/__tests__/__snapshots__/index.test.ts.snap b/packages/shared/lib/global/usePermission/__tests__/__snapshots__/index.test.ts.snap index 7272a85f5..df7521e72 100644 --- a/packages/shared/lib/global/usePermission/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/shared/lib/global/usePermission/__tests__/__snapshots__/index.test.ts.snap @@ -20,6 +20,7 @@ exports[`usePermission should match snapshot 1`] = ` "DB_SERVICE": { "ADD": "action:add_db_service", "BATCH_IMPORT": "action:batch_import_db_service", + "BATCH_TEST_CONNECT": "action:batch_test_project_db_service", "CREATE_AUDIT_PLAN": "action:db_service_create_audit_plan", "DELETE": "action:delete_db_service", "EDIT": "action:edit_db_service", @@ -29,6 +30,7 @@ exports[`usePermission should match snapshot 1`] = ` "GLOBAL_DATA_SOURCE": { "ADD": "action:add_global_db_service", "BATCH_IMPORT": "action:batch_import_global_db_service", + "BATCH_TEST_CONNECT": "action:batch_test_global_db_service", "DELETE": "action:delete_global_db_service", "EDIT": "action:edit_global_db_service", "TEST_IN_MORE_BUTTON": "action:test_global_db_service_in_more_button", @@ -285,7 +287,7 @@ exports[`usePermission should match snapshot 2`] = ` "type": "action", }, "action:add_task": { - "id": "action:add_global_db_service", + "id": "action:add_task", "role": [ "admin", "globalManager", @@ -377,6 +379,24 @@ exports[`usePermission should match snapshot 2`] = ` ], "type": "action", }, + "action:batch_test_global_db_service": { + "id": "action:batch_test_global_db_service", + "role": [ + "admin", + "globalManager", + ], + "type": "action", + }, + "action:batch_test_project_db_service": { + "id": "action:batch_test_project_db_service", + "projectArchived": false, + "projectManager": true, + "role": [ + "admin", + "globalManager", + ], + "type": "action", + }, "action:cancel_schedule_time_exec_task": { "id": "action:cancel_schedule_time_exec_task", "projectArchived": false, diff --git a/packages/shared/lib/global/usePermission/permissionManifest.ts b/packages/shared/lib/global/usePermission/permissionManifest.ts index 8ab57718c..d7811df62 100644 --- a/packages/shared/lib/global/usePermission/permissionManifest.ts +++ b/packages/shared/lib/global/usePermission/permissionManifest.ts @@ -140,6 +140,13 @@ export const PERMISSION_MANIFEST: Record< type: 'action', projectArchived: false }, + [PERMISSIONS.ACTIONS.BASE.DB_SERVICE.BATCH_TEST_CONNECT]: { + id: PERMISSIONS.ACTIONS.BASE.DB_SERVICE.BATCH_TEST_CONNECT, + type: 'action', + projectArchived: false, + role: [SystemRole.admin, SystemRole.globalManager], + projectManager: true + }, //用户中心 [PERMISSIONS.ACTIONS.BASE.USER_CENTER.USER.ADD]: { @@ -214,10 +221,15 @@ export const PERMISSION_MANIFEST: Record< id: PERMISSIONS.ACTIONS.BASE.GLOBAL_DATA_SOURCE.TEST_IN_MORE_BUTTON, type: 'action' }, + [PERMISSIONS.ACTIONS.BASE.GLOBAL_DATA_SOURCE.BATCH_TEST_CONNECT]: { + id: PERMISSIONS.ACTIONS.BASE.GLOBAL_DATA_SOURCE.BATCH_TEST_CONNECT, + type: 'action', + role: [SystemRole.admin, SystemRole.globalManager] + }, // 同步外部数据源 [PERMISSIONS.ACTIONS.BASE.SYNC_DATA_SOURCE.ADD]: { - id: PERMISSIONS.ACTIONS.BASE.GLOBAL_DATA_SOURCE.ADD, + id: PERMISSIONS.ACTIONS.BASE.SYNC_DATA_SOURCE.ADD, type: 'action', role: [SystemRole.admin, SystemRole.globalManager] }, diff --git a/packages/shared/lib/global/usePermission/permissions.ts b/packages/shared/lib/global/usePermission/permissions.ts index 8d102b44d..0bb86ccd1 100644 --- a/packages/shared/lib/global/usePermission/permissions.ts +++ b/packages/shared/lib/global/usePermission/permissions.ts @@ -33,7 +33,8 @@ export const PERMISSIONS = { DELETE: 'action:delete_global_db_service', TEST_IN_MORE_BUTTON: 'action:test_global_db_service_in_more_button', ADD: 'action:add_global_db_service', - BATCH_IMPORT: 'action:batch_import_global_db_service' + BATCH_IMPORT: 'action:batch_import_global_db_service', + BATCH_TEST_CONNECT: 'action:batch_test_global_db_service' }, SYNC_DATA_SOURCE: { ADD: 'action:add_task', @@ -48,7 +49,8 @@ export const PERMISSIONS = { DELETE: 'action:delete_db_service', TEST: 'action:test_db_service', TEST_IN_MORE_BUTTON: 'action:test_db_service_in_more_button', - CREATE_AUDIT_PLAN: 'action:db_service_create_audit_plan' + CREATE_AUDIT_PLAN: 'action:db_service_create_audit_plan', + BATCH_TEST_CONNECT: 'action:batch_test_project_db_service' }, SYSTEM: { PUSH_NOTIFICATION: { diff --git a/packages/shared/lib/types/common.type.ts b/packages/shared/lib/types/common.type.ts index 679bc0eab..ff85de117 100644 --- a/packages/shared/lib/types/common.type.ts +++ b/packages/shared/lib/types/common.type.ts @@ -49,3 +49,5 @@ export type RouterConfigItem = BaseRouterConfigItem & { children?: RouterConfigItem[]; }); + +export type ExcludeSymbol = T extends symbol ? never : T; diff --git a/packages/sqle/src/hooks/useBackendTable/useBackendTable.tsx b/packages/sqle/src/hooks/useBackendTable/useBackendTable.tsx index 4b7231d8c..e4d0f6bea 100644 --- a/packages/sqle/src/hooks/useBackendTable/useBackendTable.tsx +++ b/packages/sqle/src/hooks/useBackendTable/useBackendTable.tsx @@ -9,6 +9,7 @@ import { TableFilterContainerProps, TypeFilterElement } from '@actiontech/shared/lib/components/ActiontechTable/index.type'; +import { ExcludeSymbol } from '@actiontech/shared/lib/types/common.type'; import { Tooltip, Typography } from 'antd'; import { ColumnType } from 'antd/es/table'; import { groupBy } from 'lodash'; @@ -108,7 +109,8 @@ const useBackendTable = () => { ? options.columnClassName(cell.type) : options?.columnClassName; return { - dataIndex: cell.field_name ?? '', + dataIndex: cell.field_name as ExcludeSymbol & + string, title: (cell.desc || cell.field_name) ?? '', render: renderMethod, className: cls, diff --git a/packages/sqle/src/page/GlobalDashboard/index.data.ts b/packages/sqle/src/page/GlobalDashboard/index.data.ts index c791f24d9..c0cbd064d 100644 --- a/packages/sqle/src/page/GlobalDashboard/index.data.ts +++ b/packages/sqle/src/page/GlobalDashboard/index.data.ts @@ -6,7 +6,8 @@ export const ProjectPriorityDictionary: { } = { [ProjectProjectPriorityEnum.high]: t('globalDashboard.high'), [ProjectProjectPriorityEnum.medium]: t('globalDashboard.medium'), - [ProjectProjectPriorityEnum.low]: t('globalDashboard.low') + [ProjectProjectPriorityEnum.low]: t('globalDashboard.low'), + [ProjectProjectPriorityEnum.unknown]: t('common.unknown') }; export const ProjectPriorityOptions: Array<{ diff --git a/packages/sqle/src/page/SqlAudit/List/column.tsx b/packages/sqle/src/page/SqlAudit/List/column.tsx index 90ad5a829..e7c515a5c 100644 --- a/packages/sqle/src/page/SqlAudit/List/column.tsx +++ b/packages/sqle/src/page/SqlAudit/List/column.tsx @@ -68,7 +68,7 @@ const SqlAuditListColumn: ( { dataIndex: 'sql_audit_record_id', title: () => t('sqlAudit.list.columns.auditID'), - render: (id: string) => { + render: (id) => { if (!id) { return '-'; } @@ -106,15 +106,17 @@ const SqlAuditListColumn: ( { dataIndex: 'sql_audit_status', title: () => t('sqlAudit.list.columns.auditStatus'), - render: ( - sql_audit_status: getSQLAuditRecordsV1FilterSqlAuditStatusEnum - ) => { + render: (sql_audit_status) => { if (!sql_audit_status) { return '-'; } return ( - + ); } @@ -122,7 +124,7 @@ const SqlAuditListColumn: ( { dataIndex: 'tags', title: () => t('sqlAudit.list.columns.businessTag'), - render: (tags: string[], record) => { + render: (tags, record) => { return ( t('sqlAudit.list.columns.auditTime'), - render(time: string) { + render(time) { return formatTime(time, '-'); }, width: 200 diff --git a/packages/sqle/src/page/SqlExecWorkflow/List/column.tsx b/packages/sqle/src/page/SqlExecWorkflow/List/column.tsx index 70914849d..67c5d4840 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/List/column.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/List/column.tsx @@ -63,14 +63,13 @@ export const SqlExecWorkflowListColumn: ( projectID: string ) => ActiontechTableColumn< IWorkflowDetailResV1, - SqlExecWorkflowListTableFilterParam, - 'address' + SqlExecWorkflowListTableFilterParam > = (projectID) => { return [ { dataIndex: 'workflow_id', title: () => t('execWorkflow.list.id'), - render: (id: string) => { + render: (id) => { return ( @@ -84,7 +83,7 @@ export const SqlExecWorkflowListColumn: ( dataIndex: 'workflow_name', className: 'workflow-list-table-workflow-name-column', title: () => t('execWorkflow.list.name'), - render: (name: string) => ( + render: (name) => ( {name} @@ -95,7 +94,7 @@ export const SqlExecWorkflowListColumn: ( dataIndex: 'desc', title: () => t('execWorkflow.list.desc'), className: 'workflow-list-table-desc-column', - render: (desc: string, record: IWorkflowDetailResV1) => + render: (desc, record) => desc ? ( t('execWorkflow.list.version'), filterCustomType: 'select', filterKey: 'filter_sql_version_id', - render: (versionNames: string[]) => { + render: (versionNames) => { if (!versionNames || versionNames.length === 0) { return '-'; } @@ -149,7 +148,10 @@ export const SqlExecWorkflowListColumn: ( { dataIndex: 'status', title: () => t('execWorkflow.list.status'), - render: (status: IWorkflowDetailResV1['status']) => { + render: (status) => { + if (!status) { + return '-'; + } return ; } }, @@ -158,7 +160,10 @@ export const SqlExecWorkflowListColumn: ( title: () => t('execWorkflow.list.assignee'), filterCustomType: 'select', filterKey: 'filter_current_step_assignee_user_id', - render: (list: string[]) => { + render: (list) => { + if (!list) { + return '-'; + } return list?.map((v) => { return ; });