diff --git a/packages/shared/lib/api/sqle/service/SqlDEVRecord/index.d.ts b/packages/shared/lib/api/sqle/service/SqlDEVRecord/index.d.ts index 07594aa656..8a51eb270a 100644 --- a/packages/shared/lib/api/sqle/service/SqlDEVRecord/index.d.ts +++ b/packages/shared/lib/api/sqle/service/SqlDEVRecord/index.d.ts @@ -13,6 +13,8 @@ export interface IGetSqlDEVRecordListParams { filter_instance_name?: string; + filter_db_type?: string; + filter_source?: GetSqlDEVRecordListFilterSourceEnum; filter_creator?: string; @@ -31,3 +33,23 @@ export interface IGetSqlDEVRecordListParams { } export interface IGetSqlDEVRecordListReturn extends IGetSqlDEVRecordListResp {} + +export interface IExportSqlDEVRecordParams { + project_name: string; + + fuzzy_search_sql_fingerprint?: string; + + filter_instance_name?: string; + + filter_db_type?: string; + + filter_source?: GetSqlDEVRecordListFilterSourceEnum; + + filter_creator?: string; + + filter_last_receive_time_from?: string; + + filter_last_receive_time_to?: string; + + filter_sql_dev_record_ids?: string; +} diff --git a/packages/shared/lib/api/sqle/service/SqlDEVRecord/index.ts b/packages/shared/lib/api/sqle/service/SqlDEVRecord/index.ts index 6371b7625e..5c01da395e 100644 --- a/packages/shared/lib/api/sqle/service/SqlDEVRecord/index.ts +++ b/packages/shared/lib/api/sqle/service/SqlDEVRecord/index.ts @@ -7,6 +7,7 @@ import ServiceBase from '../Service.base'; import { AxiosRequestConfig } from 'axios'; import { + IExportSqlDEVRecordParams, IGetSqlDEVRecordListParams, IGetSqlDEVRecordListReturn } from './index.d'; @@ -26,6 +27,21 @@ class SqlDEVRecordService extends ServiceBase { options ); } + + public ExportSqlDEVRecord( + params: IExportSqlDEVRecordParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_name = paramsData.project_name; + delete paramsData.project_name; + + return this.get( + `/v1/projects/${project_name}/sql_dev_records/exports`, + paramsData, + options + ); + } } export default new SqlDEVRecordService(); diff --git a/packages/shared/lib/api/sqle/service/common.d.ts b/packages/shared/lib/api/sqle/service/common.d.ts index d5a8aa737e..8b03d1d1f3 100644 --- a/packages/shared/lib/api/sqle/service/common.d.ts +++ b/packages/shared/lib/api/sqle/service/common.d.ts @@ -2432,6 +2432,8 @@ export interface ISqlAverageExecutionTime { export interface ISqlDEVRecord { audit_result?: IAuditResult[]; + db_type?: string; + creator?: string; first_appear_timestamp?: string; diff --git a/packages/sqle/src/locale/en-US/pluginAudit.ts b/packages/sqle/src/locale/en-US/pluginAudit.ts index 8c0afc0003..f2db6ac2b1 100644 --- a/packages/sqle/src/locale/en-US/pluginAudit.ts +++ b/packages/sqle/src/locale/en-US/pluginAudit.ts @@ -14,12 +14,17 @@ export default { sqlFingerprint: 'SQL fingerprint', source: 'DB instance', schema: 'Schema', + dbType: 'Database type', result: 'Audit result', count: 'Occurrences', firstAppearTime: 'First appearance time', lastReceiveTime: 'Last appearance time', creator: 'Creator', - createWhitelist: 'Add to SQL management whitelist' + createWhitelist: 'Add to SQL management whitelist', + exportReport: 'Export report', + exporting: 'Exporting file', + exportSuccessTips: 'Export file successfully', + exportFailedTips: 'Export file failed' }, drawerTitle: 'IDE audit result' }; diff --git a/packages/sqle/src/locale/zh-CN/pluginAudit.ts b/packages/sqle/src/locale/zh-CN/pluginAudit.ts index c268f33de3..4e920d729d 100644 --- a/packages/sqle/src/locale/zh-CN/pluginAudit.ts +++ b/packages/sqle/src/locale/zh-CN/pluginAudit.ts @@ -13,12 +13,17 @@ export default { sqlFingerprint: 'SQL指纹', source: '数据源', schema: 'Schema', + dbType: '数据库类型', result: '审核结果', count: '出现次数', firstAppearTime: '最早出现时间', lastReceiveTime: '最近一次出现时间', creator: '创建人', - createWhitelist: '添加为审核SQL例外' + createWhitelist: '添加为审核SQL例外', + exportReport: '导出报表', + exporting: '正在导出文件', + exportSuccessTips: '导出文件成功', + exportFailedTips: '导出文件失败' }, drawerTitle: 'IDE审核结果' }; diff --git a/packages/sqle/src/page/PluginAudit/List/__snapshots__/index.test.tsx.snap b/packages/sqle/src/page/PluginAudit/List/__snapshots__/index.test.tsx.snap index 95bce96869..595e294db2 100644 --- a/packages/sqle/src/page/PluginAudit/List/__snapshots__/index.test.tsx.snap +++ b/packages/sqle/src/page/PluginAudit/List/__snapshots__/index.test.tsx.snap @@ -96,6 +96,41 @@ exports[`sqle/PluginAudit/List click sql fingerprint and open ide audit result 1
+
+
+
+ +
+
+
+ + @@ -224,6 +263,31 @@ exports[`sqle/PluginAudit/List click sql fingerprint and open ide audit result 1 class="ant-table-thead" > + +
+ +
+ Schema + + 数据库类型 + + + + @@ -402,6 +491,11 @@ exports[`sqle/PluginAudit/List click sql fingerprint and open ide audit result 1 > dms + + - + @@ -760,6 +854,41 @@ exports[`sqle/PluginAudit/List render empty prompt when request failed 1`] = `
+
+
+
+ +
+
+
+ + @@ -888,6 +1021,32 @@ exports[`sqle/PluginAudit/List render empty prompt when request failed 1`] = ` class="ant-table-thead" > + +
+ +
+ Schema + + 数据库类型 +
+
+
+
+ +
+
+
+ + @@ -1359,6 +1563,31 @@ exports[`sqle/PluginAudit/List render table data 1`] = ` class="ant-table-thead" > + +
+ +
+ Schema + + 数据库类型 + + + + @@ -1537,6 +1791,11 @@ exports[`sqle/PluginAudit/List render table data 1`] = ` > dms + + - + @@ -1641,6 +1900,25 @@ exports[`sqle/PluginAudit/List render table data 1`] = ` class="ant-table-row ant-table-row-level-0" data-row-key="2" > + + + @@ -1749,6 +2027,11 @@ exports[`sqle/PluginAudit/List render table data 1`] = ` > dms + + - + @@ -1843,6 +2126,25 @@ exports[`sqle/PluginAudit/List render table data 1`] = ` class="ant-table-row ant-table-row-level-0" data-row-key="3" > + + + @@ -1857,6 +2159,11 @@ exports[`sqle/PluginAudit/List render table data 1`] = ` + + - + diff --git a/packages/sqle/src/page/PluginAudit/List/columns.tsx b/packages/sqle/src/page/PluginAudit/List/columns.tsx index 663617232d..632dc5b354 100644 --- a/packages/sqle/src/page/PluginAudit/List/columns.tsx +++ b/packages/sqle/src/page/PluginAudit/List/columns.tsx @@ -16,6 +16,12 @@ export type PluginAuditListTableFilterParamType = PageInfoWithoutIndexAndSize< 'project_name' >; +export const PLUGIN_AUDIT_DB_TYPE_FILTER_OPTIONS = [ + { label: 'MySQL', value: 'MySQL' }, + { label: 'TDSQL For InnoDB', value: 'TDSQL For InnoDB' }, + { label: 'TBase', value: 'TBase' } +]; + export const PluginAuditListColumns: ( onOpenDrawer: (record: ISqlDEVRecord) => void ) => ActiontechTableColumn = ( @@ -70,6 +76,15 @@ export const PluginAuditListColumns: ( dataIndex: 'schema_name', title: () => t('pluginAudit.table.schema') }, + { + dataIndex: 'db_type', + title: () => t('pluginAudit.table.dbType'), + filterCustomType: 'select', + filterKey: 'filter_db_type', + render: (db_type) => { + return db_type || '-'; + } + }, { dataIndex: 'audit_result', title: () => t('pluginAudit.table.result'), diff --git a/packages/sqle/src/page/PluginAudit/List/index.tsx b/packages/sqle/src/page/PluginAudit/List/index.tsx index 66f71fbb1d..611870121b 100644 --- a/packages/sqle/src/page/PluginAudit/List/index.tsx +++ b/packages/sqle/src/page/PluginAudit/List/index.tsx @@ -1,8 +1,9 @@ import { useRequest, useBoolean } from 'ahooks'; -import { useEffect, useMemo, useRef } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import DefaultPrompts from '../components/DefaultPrompts'; import sqlDEVRecord from '@actiontech/shared/lib/api/sqle/service/SqlDEVRecord'; import { ISqlDEVRecord } from '@actiontech/shared/lib/api/sqle/service/common'; +import { IExportSqlDEVRecordParams } from '@actiontech/shared/lib/api/sqle/service/SqlDEVRecord/index.d'; import { useCurrentProject, useCurrentUser @@ -10,7 +11,8 @@ import { import { PluginAuditListColumns, PluginAuditListTableFilterParamType, - PluginAuditListActions + PluginAuditListActions, + PLUGIN_AUDIT_DB_TYPE_FILTER_OPTIONS } from './columns'; import useInstance from '../../../hooks/useInstance'; import useUsername from '../../../hooks/useUsername'; @@ -30,12 +32,17 @@ import { TableToolbar, FilterCustomProps, ColumnsSettingProps, - useTableRequestParams + useTableRequestParams, + ActiontechTableToolbarActionMeta } from '@actiontech/shared/lib/components/ActiontechTable'; import { ResponseCode } from '../../../data/common'; import AddWhitelistModal from '../../Whitelist/Drawer/AddWhitelist'; import useWhitelistRedux from '../../Whitelist/hooks/useWhitelistRedux'; import { MatchConditionReqV1TypeEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum'; +import { message } from 'antd'; +import { TableRowSelection } from 'antd/es/table/interface'; +import { DownArrowLineOutlined } from '@actiontech/icons'; +import { t } from '../../../locale'; const PluginAuditList = () => { const dispatch = useDispatch(); @@ -51,6 +58,9 @@ const PluginAuditList = () => { actionPermission } = useWhitelistRedux(); + const [messageApi, messageContextHolder] = message.useMessage(); + const [selectedRowKeys, setSelectedRowKeys] = useState([]); + const { tableFilterInfo, updateTableFilterInfo, @@ -71,6 +81,11 @@ const PluginAuditList = () => { const [showEmptyPrompt, { setTrue: setEmptyPromptShow }] = useBoolean(); + const [ + exportButtonDisabled, + { setFalse: finishExport, setTrue: startExport } + ] = useBoolean(false); + const { data, loading, refresh } = useRequest( () => { const params = { @@ -100,6 +115,44 @@ const PluginAuditList = () => { } ); + useEffect(() => { + setSelectedRowKeys([]); + }, [tableFilterInfo, searchKeyword]); + + const buildExportParams = useCallback((): IExportSqlDEVRecordParams => { + const params: IExportSqlDEVRecordParams = { + project_name: projectName, + ...tableFilterInfo, + fuzzy_search_sql_fingerprint: searchKeyword || undefined + }; + if (selectedRowKeys.length > 0) { + params.filter_sql_dev_record_ids = selectedRowKeys.join(','); + } + return params; + }, [projectName, tableFilterInfo, searchKeyword, selectedRowKeys]); + + const handleExport = useCallback(() => { + startExport(); + const hideLoading = messageApi.loading(t('pluginAudit.table.exporting')); + sqlDEVRecord + .ExportSqlDEVRecord(buildExportParams(), { responseType: 'blob' }) + .then((res) => { + if ( + (res.data as unknown as { code?: number }).code === + ResponseCode.SUCCESS + ) { + messageApi.success(t('pluginAudit.table.exportSuccessTips')); + } + }) + .catch((e: Error) => { + messageApi.error(e?.message ?? t('pluginAudit.table.exportFailedTips')); + }) + .finally(() => { + hideLoading(); + finishExport(); + }); + }, [buildExportParams, finishExport, messageApi, startExport]); + const tableSetting = useMemo( () => ({ tableName: 'plugin_audit_list', @@ -134,6 +187,12 @@ const PluginAuditList = () => { options: usernameOptions.map((i) => ({ ...i, value: i.text })) } ], + [ + 'db_type', + { + options: PLUGIN_AUDIT_DB_TYPE_FILTER_OPTIONS + } + ], [ 'last_receive_timestamp', { @@ -160,6 +219,31 @@ const PluginAuditList = () => { const { filterButtonMeta, filterContainerMeta, updateAllSelectedFilterItem } = useTableFilterContainer(columns, updateTableFilterInfo); + const rowSelection = useMemo>( + () => ({ + selectedRowKeys, + onChange: (keys) => { + setSelectedRowKeys(keys.filter((v) => v) as number[]); + } + }), + [selectedRowKeys] + ); + + const toolbarActions = useMemo( + () => [ + { + key: 'export-report', + text: t('pluginAudit.table.exportReport'), + buttonProps: { + icon: , + disabled: exportButtonDisabled, + onClick: handleExport + } + } + ], + [exportButtonDisabled, handleExport] + ); + useEffect(() => { updateUsernameList({ filter_project: projectName }); updateInstanceList({ @@ -170,6 +254,7 @@ const PluginAuditList = () => { return ( }> <> + {messageContextHolder} { refreshBySearchKeyword(); } }} + actions={toolbarActions} loading={loading} /> { rowKey={(record: ISqlDEVRecord) => { return `${record?.id}`; }} + rowSelection={rowSelection} pagination={{ total: data?.total ?? 0, current: pagination.page_index diff --git a/packages/sqle/src/page/PluginAudit/test/__snapshots__/index.test.tsx.snap b/packages/sqle/src/page/PluginAudit/test/__snapshots__/index.test.tsx.snap index 7e3348193f..3cc3140d6a 100644 --- a/packages/sqle/src/page/PluginAudit/test/__snapshots__/index.test.tsx.snap +++ b/packages/sqle/src/page/PluginAudit/test/__snapshots__/index.test.tsx.snap @@ -109,6 +109,41 @@ exports[`sqle/PluginAudit render table data 1`] = `
+
+
+
+ +
+
+
+ + @@ -237,6 +276,31 @@ exports[`sqle/PluginAudit render table data 1`] = ` class="ant-table-thead" > + +
+ +
+ Schema + + 数据库类型 + + + + @@ -415,6 +504,11 @@ exports[`sqle/PluginAudit render table data 1`] = ` > dms + + - + @@ -519,6 +613,25 @@ exports[`sqle/PluginAudit render table data 1`] = ` class="ant-table-row ant-table-row-level-0" data-row-key="2" > + + + @@ -627,6 +740,11 @@ exports[`sqle/PluginAudit render table data 1`] = ` > dms + + - + @@ -721,6 +839,25 @@ exports[`sqle/PluginAudit render table data 1`] = ` class="ant-table-row ant-table-row-level-0" data-row-key="3" > + + + @@ -735,6 +872,11 @@ exports[`sqle/PluginAudit render table data 1`] = ` + + - + diff --git a/packages/sqle/src/testUtils/mockApi/sqlDEVRecord/index.ts b/packages/sqle/src/testUtils/mockApi/sqlDEVRecord/index.ts index 2ca4bdae93..ba6563323d 100644 --- a/packages/sqle/src/testUtils/mockApi/sqlDEVRecord/index.ts +++ b/packages/sqle/src/testUtils/mockApi/sqlDEVRecord/index.ts @@ -20,6 +20,16 @@ class SqlDEVRecord implements MockSpyApy { ); return spy; } + + public exportSqlDEVRecord() { + const spy = jest.spyOn(sqlDEVRecord, 'ExportSqlDEVRecord'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: new Blob(['mock']) + }) + ); + return spy; + } } export default new SqlDEVRecord();