diff --git a/src/component/Task/component/TaskTable/index.tsx b/src/component/Task/component/TaskTable/index.tsx index d88d2738e..486ce2d28 100644 --- a/src/component/Task/component/TaskTable/index.tsx +++ b/src/component/Task/component/TaskTable/index.tsx @@ -476,6 +476,7 @@ const TaskTable: React.FC = inject( activeTaskLabel: activeTaskLabel, }, ), //`新建${activeTaskLabel}` + disabled: disabledOpt, isPrimary: true, onClick: () => { props.onMenuClick(taskTabType); diff --git a/src/page/Project/Sensitive/SensitiveContext.ts b/src/page/Project/Sensitive/SensitiveContext.ts index f499acf84..138750271 100644 --- a/src/page/Project/Sensitive/SensitiveContext.ts +++ b/src/page/Project/Sensitive/SensitiveContext.ts @@ -21,7 +21,7 @@ import { SelectItemProps } from './interface'; import React from 'react'; -interface ISensitiveContext { +export interface ISensitiveContext { projectId: number; maskingAlgorithms: IMaskingAlgorithm[]; diff --git a/src/page/Project/Sensitive/components/SensitiveColumn/components/FormSensitiveColumnDrawer.tsx b/src/page/Project/Sensitive/components/SensitiveColumn/components/FormSensitiveColumnDrawer.tsx index 2734e840c..f0e0c6235 100644 --- a/src/page/Project/Sensitive/components/SensitiveColumn/components/FormSensitiveColumnDrawer.tsx +++ b/src/page/Project/Sensitive/components/SensitiveColumn/components/FormSensitiveColumnDrawer.tsx @@ -14,26 +14,32 @@ * limitations under the License. */ -import { - batchCreateSensitiveColumns, - getScanningResults, - ScannResultType, - startScanning, -} from '@/common/network/sensitiveColumn'; +import { batchCreateSensitiveColumns } from '@/common/network/sensitiveColumn'; import { ESensitiveColumnType, ISensitiveColumn } from '@/d.ts/sensitiveColumn'; import ProjectContext from '@/page/Project/ProjectContext'; import { AddSensitiveColumnType, ScanTableData } from '@/page/Project/Sensitive/interface'; import { formatMessage } from '@/util/intl'; import { Button, Drawer, message, Space } from 'antd'; -import { useForm } from 'antd/es/form/Form'; +import { useForm, useWatch } from 'antd/es/form/Form'; import { useContext, useEffect, useRef, useState } from 'react'; import styles from './index.less'; import ScanForm from './ScanForm'; import tracert from '@/util/tracert'; import SensitiveRule from '../../SensitiveRule'; -const defaultScanTableData: Array = []; -const checkResult = (resData: Array = []) => +import { merge } from 'lodash'; +export const defaultScanTableData: Array = []; +export const checkResult = (resData: Array = []) => resData?.length > 0 ? resData : defaultScanTableData; + +export function getTitle(addSensitiveColumnType: AddSensitiveColumnType) { + return addSensitiveColumnType === AddSensitiveColumnType.Manual + ? formatMessage({ + id: 'odc.SensitiveColumn.components.FormSensitiveColumnDrawer.ManuallyAddSensitiveColumns', + }) //手动添加敏感列 + : formatMessage({ + id: 'odc.SensitiveColumn.components.FormSensitiveColumnDrawer.ScanToAddSensitiveColumns', + }); //扫描添加敏感列 +} const FormSensitiveColumnDrawer = ({ isEdit, visible, @@ -44,190 +50,26 @@ const FormSensitiveColumnDrawer = ({ }) => { const [formRef] = useForm(); const [_formRef] = useForm(); - const timer = useRef(null); + const ref = useRef(null); + const scanTableData = useWatch('scanTableData', _formRef); const context = useContext(ProjectContext); - const [scanTableData, setScanTableData] = useState([]); - const [originScanTableData, setOriginScanTableData] = useState([]); const [submiting, setSubmiting] = useState(false); const [sensitiveColumns, setSensitiveColumns] = useState([]); - const [sensitiveColumnMap, setSensitiveColumnMap] = useState>(new Map()); - const [taskId, setTaskId] = useState(); - const [scanStatus, setScanStatus] = useState(); - const [scanLoading, setScanLoading] = useState(false); - const [hasScan, setHasScan] = useState(false); - const [percent, setPercent] = useState(0); - const [successful, setSuccessful] = useState(false); - const [searchText, setSearchText] = useState(''); const [manageSensitiveRuleDrawerOpen, setManageSensitiveRuleDrawerOpen] = useState( false, ); - const [scanTableDataMap, setScanTableDataMap] = useState({}); - const [activeKeys, setActiveKeys] = useState(['0']); - const handleSearchChange = (e) => { - setSearchText(e.target.value); - }; - const onSearch = () => { - if (searchText.trim() === '') { - return; - } - const resData = []; - sensitiveColumnMap.forEach((sc, key) => { - const filterColumn = sc?.dataSource?.filter((item) => - item?.columnName?.toLowerCase()?.includes(searchText?.toLocaleLowerCase()), - ); - if (filterColumn?.length > 0) { - resData.push({ - header: sc?.header, - dataSource: filterColumn, - }); - } - }); - setScanTableData(checkResult(resData)); - }; - const resetSearch = () => { - setSearchText(''); - setScanTableData(originScanTableData); - }; - const reset = () => { - setTaskId(null); - setScanStatus(null); - setScanLoading(false); - setPercent(0); - setSuccessful(false); - setHasScan(false); - setSearchText(''); - }; - const resetScanTableData = () => { - formRef.resetFields(); - _formRef.resetFields(); - setScanTableData(defaultScanTableData); - setOriginScanTableData(defaultScanTableData); - setSubmiting(false); - setSensitiveColumns([]); - setSensitiveColumnMap(new Map()); - setTaskId(''); - setScanStatus(null); - setScanLoading(false); - setHasScan(false); - setPercent(0); - setSuccessful(false); - setSearchText(''); - clearTimeout(timer.current); - }; - const handleScanTableDataDelete = (database: string, tableName: string, columnName: string) => { - const key = `${database}_${tableName}`; - const filterDataSource = - sensitiveColumnMap.get(key).dataSource.filter((ds) => ds?.columnName !== columnName) || []; - sensitiveColumnMap.get(key).dataSource = filterDataSource; - if (filterDataSource?.length === 0) { - sensitiveColumnMap.delete(key); - } - const resData = []; - if (!!searchText) { - sensitiveColumnMap?.forEach((dsItem) => { - const newDataSource = dsItem?.dataSource?.filter((ds) => - ds?.columnName?.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()), - ); - if (newDataSource?.length > 0) { - resData.push({ - header: dsItem?.header, - dataSource: newDataSource, - }); - } - }); - } else { - // 没有searchText 纯删除 - sensitiveColumnMap?.forEach((dsItem) => { - resData.push(dsItem); - }); - } - const newTableData = checkResult(resData); - setScanTableData(newTableData); - setOriginScanTableData(newTableData); - newTableData?.length === 0 && setActiveKeys(['0']); - setSensitiveColumnMap(sensitiveColumnMap); - }; - const handleScanTableDataDeleteByTableName = (database: string, tableName: string) => { - const key = `${database}_${tableName}`; - const resData = []; - if (!!searchText) { - sensitiveColumnMap.get(key).dataSource = sensitiveColumnMap - .get(key) - .dataSource?.filter( - (item) => !item.columnName?.toLowerCase()?.includes(searchText?.toLowerCase()), - ); - const originResData = []; - sensitiveColumnMap?.forEach((dsItem) => { - if (dsItem?.dataSource?.length > 0) { - originResData.push(dsItem); - } - }); - const newTableData = checkResult(originResData); - newTableData?.length === 0 && setActiveKeys(['0']); - setOriginScanTableData(newTableData); - sensitiveColumnMap?.forEach((dsItem, dsKey) => { - if (dsItem?.dataSource?.length > 0) { - resData.push(dsItem); - } else { - sensitiveColumnMap.delete(key); - } - }); - } else { - sensitiveColumnMap.delete(key); - sensitiveColumnMap?.forEach((dsItem) => { - resData.push(dsItem); - }); - const newTableData = checkResult(resData); - setOriginScanTableData(newTableData); - newTableData?.length === 0 && setActiveKeys(['0']); - } - setScanTableData(checkResult(resData)); - setSensitiveColumnMap(sensitiveColumnMap); - }; - const handleStartScan = async () => { - reset(); - setScanTableData(defaultScanTableData); - setOriginScanTableData(defaultScanTableData); - const rawData = await formRef.validateFields().catch(); - if (rawData.databaseIds?.includes(-1)) { - rawData.allDatabases = true; - rawData.databaseIds = []; - } else { - rawData.allDatabases = false; - } - if (rawData.sensitiveRuleIds?.includes(-1)) { - rawData.allSensitiveRules = true; - rawData.sensitiveRuleIds = []; - } else { - rawData.allSensitiveRules = false; - } - setScanLoading(true); - const taskId = await startScanning(context.projectId, rawData); - if (taskId) { - setTaskId(taskId); - setScanStatus(ScannResultType.CREATED); - } else { - setScanLoading(false); - reset(); - } - }; + const [formData, setFormData] = useState({}); + const parseData = (rawFormData: Object) => { - const data = []; + const obj = {}; Object.keys(rawFormData)?.forEach((database) => { if (rawFormData[database]?.[ESensitiveColumnType.TABLE_COLUMN]) { for (const tableName in rawFormData[database]?.[ESensitiveColumnType.TABLE_COLUMN]) { for (const columnName in rawFormData[database]?.[ESensitiveColumnType.TABLE_COLUMN][ tableName ]) { - const item = { - ...scanTableDataMap[ - `${database}_${ESensitiveColumnType.TABLE_COLUMN}_${tableName}_${columnName}` - ], - maskingAlgorithmId: - rawFormData[database]?.[ESensitiveColumnType.TABLE_COLUMN][tableName][columnName], - enabled: true, - }; - data.push(item); + obj[`${database}_${ESensitiveColumnType.TABLE_COLUMN}_${tableName}_${columnName}`] = + rawFormData[database]?.[ESensitiveColumnType.TABLE_COLUMN][tableName][columnName]; } } } @@ -236,28 +78,23 @@ const FormSensitiveColumnDrawer = ({ for (const columnName in rawFormData[database]?.[ESensitiveColumnType.VIEW_COLUMN][ viewName ]) { - const item = { - ...scanTableDataMap[ - `${database}_${ESensitiveColumnType.VIEW_COLUMN}_${viewName}_${columnName}` - ], - maskingAlgorithmId: - rawFormData[database]?.[ESensitiveColumnType.VIEW_COLUMN][viewName][columnName], - enabled: true, - }; - data.push(item); + obj[`${database}_${ESensitiveColumnType.VIEW_COLUMN}_${viewName}_${columnName}`] = + rawFormData[database]?.[ESensitiveColumnType.VIEW_COLUMN][viewName][columnName]; } } } }); - return data; + return obj; }; const handleScanSubmit = async () => { await formRef.validateFields().catch(); const { scanTableData: rawFormData } = await _formRef.validateFields().catch(); const rawData = []; + const sensitiveColumnMap = ref.current?.getColumnMap() || new Map(); + const map = parseData(merge(formData, rawFormData)); sensitiveColumns.forEach((sensitiveColumn) => { - const key = `${sensitiveColumn.database.name}_${sensitiveColumn.tableName}`; - if (sensitiveColumnMap.get(key)) { + const key = `${sensitiveColumn.database.name}_${sensitiveColumn.type}_${sensitiveColumn.tableName}`; + if (sensitiveColumnMap.has(key)) { const column = sensitiveColumnMap .get(key) ?.dataSource.find((item) => item.columnName === sensitiveColumn.columnName); @@ -265,17 +102,13 @@ const FormSensitiveColumnDrawer = ({ rawData.push({ ...sensitiveColumn, enabled: true, - maskingAlgorithmId: column.maskingAlgorithmId, + maskingAlgorithmId: map[`${key}_${sensitiveColumn.columnName}`], }); } } }); - const data = parseData(rawFormData); - if (data?.length === 0) { - return; - } setSubmiting(true); - const res = await batchCreateSensitiveColumns(context.projectId, data); + const res = await batchCreateSensitiveColumns(context.projectId, rawData); setSubmiting(false); if (res) { tracert.click('a3112.b64002.c330861.d367391'); @@ -284,10 +117,8 @@ const FormSensitiveColumnDrawer = ({ id: 'odc.SensitiveColumn.components.FormSensitiveColumnDrawer.New', }), //新建成功 ); - onOk(); - reset(); - resetScanTableData(); + ref.current?.reset(); } else { message.error( formatMessage({ @@ -298,149 +129,17 @@ const FormSensitiveColumnDrawer = ({ }; const hanldeClose = () => { - onClose(() => { - formRef?.resetFields(); - _formRef?.resetFields(); - setSuccessful(false); - setScanTableData(defaultScanTableData); - setOriginScanTableData(defaultScanTableData); - setSensitiveColumnMap(new Map()); - setScanTableDataMap({}); - setSensitiveColumns([]); - setTaskId(null); - setScanStatus(null); - setScanLoading(false); - setPercent(0); - setSearchText(''); - clearTimeout(timer.current); + onClose(async () => { + await formRef?.resetFields(); + await _formRef?.resetFields(); + setSubmiting(false); + setManageSensitiveRuleDrawerOpen(false); + setFormData({}); + ref.current?.reset(); + ref.current = null; }); }; - const initScanTableDataMap = (rawFormData: ScanTableData[]) => { - const scanTableData = {}; - const newScanTableDataMap = {}; - rawFormData?.forEach(({ dataSource = [], header = {} }) => { - const { database = '', tableName, type, databaseId } = header; - scanTableData[database] = scanTableData?.[database] || { - [ESensitiveColumnType.TABLE_COLUMN]: {}, - [ESensitiveColumnType.VIEW_COLUMN]: {}, - }; - scanTableData[database][type][tableName] = {}; - dataSource?.forEach(({ columnName, maskingAlgorithmId }) => { - scanTableData[database][type][tableName][columnName] = maskingAlgorithmId; - newScanTableDataMap[ - `${database}_${type}_${tableName}_${columnName}` - ] = sensitiveColumns?.find( - (item) => - item?.database?.databaseId === databaseId && - item.type === type && - item.tableName === tableName && - item.columnName === columnName, - ); - }); - }); - return { scanTableData, newScanTableDataMap }; - }; - const handleScanning = async (taskId: string) => { - const rawData = await getScanningResults(context.projectId, taskId); - const { status, sensitiveColumns, allTableCount, finishedTableCount } = rawData; - if ([ScannResultType.FAILED, ScannResultType.SUCCESS].includes(status)) { - const dataSourceMap = new Map(); - setSensitiveColumns(sensitiveColumns); - sensitiveColumns?.forEach((d) => { - const key = `${d.database.name}_${d.tableName}`; - if (dataSourceMap.has(key)) { - dataSourceMap.get(key)?.dataSource?.push({ - columnName: d.columnName, - sensitiveRuleId: d.sensitiveRuleId, - maskingAlgorithmId: d.maskingAlgorithmId, - }); - } else { - dataSourceMap.set(key, { - header: { - database: d.database.name, - databaseId: d.database.databaseId, - tableName: d.tableName, - type: d.type, - }, - dataSource: [ - { - columnName: d.columnName, - sensitiveRuleId: d.sensitiveRuleId, - maskingAlgorithmId: d.maskingAlgorithmId, - }, - ], - }); - } - }); - dataSourceMap.forEach((value, key) => { - value.dataSource = value.dataSource.sort((a, b) => - a?.columnName?.localeCompare(b?.columnName), - ); - dataSourceMap.set(key, value); - }); - setSensitiveColumnMap(dataSourceMap); - const resData = []; - dataSourceMap?.forEach((ds) => { - resData.push(ds); - }); - const rawFormData = checkResult(resData); - setActiveKeys( - rawFormData?.length === 0 - ? ['0'] - : rawFormData?.map( - ({ header: { database, tableName, type }, dataSource }, index) => - `${database}_${type}_${tableName}`, - ), - ); - setScanTableData(rawFormData); - setOriginScanTableData(rawFormData); - // const { - // scanTableData, - // newScanTableDataMap - // } = initScanTableDataMap(rawFormData); - const scanTableData = {}; - const newScanTableDataMap = {}; - rawFormData?.forEach(({ dataSource = [], header = {} }) => { - const { database = '', tableName, type, databaseId } = header; - scanTableData[database] = scanTableData?.[database] || { - [ESensitiveColumnType.TABLE_COLUMN]: {}, - [ESensitiveColumnType.VIEW_COLUMN]: {}, - }; - scanTableData[database][type][tableName] = {}; - dataSource?.forEach(({ columnName, maskingAlgorithmId }) => { - scanTableData[database][type][tableName][columnName] = maskingAlgorithmId; - newScanTableDataMap[ - `${database}_${type}_${tableName}_${columnName}` - ] = sensitiveColumns?.find( - (item) => - item?.database?.databaseId === databaseId && - item.type === type && - item.tableName === tableName && - item.columnName === columnName, - ); - }); - }); - setScanTableDataMap(newScanTableDataMap); - await _formRef.setFieldsValue({ - scanTableData, - }); - setScanStatus(ScannResultType.SUCCESS); - setSuccessful(true); - setPercent(Math.floor((finishedTableCount * 100) / allTableCount)); - setScanLoading(false); - } else { - setScanStatus(ScannResultType.RUNNING); - setHasScan(true); - setActiveKeys(['0']); - setScanTableDataMap({}); - setPercent(Math.floor((finishedTableCount * 100) / allTableCount)); - timer.current = setTimeout(() => { - handleScanning(taskId); - clearTimeout(timer.current); - }, 1000); - } - }; useEffect(() => { if (!isEdit) { formRef.setFieldsValue({ @@ -456,94 +155,50 @@ const FormSensitiveColumnDrawer = ({ }); } }, [isEdit, visible]); - useEffect(() => { - if (successful && searchText === '') { - const resData = []; - sensitiveColumnMap?.forEach((ds) => { - resData.push(ds); - }); - setScanTableData(checkResult(resData)); - setOriginScanTableData(checkResult(resData)); - } - }, [searchText, successful]); - useEffect(() => { - if (taskId && [ScannResultType.CREATED, ScannResultType.RUNNING].includes(scanStatus)) { - handleScanning(taskId); - } - return () => { - clearTimeout(timer.current); - }; - }, [taskId, scanStatus]); + const title = getTitle(addSensitiveColumnType); + const DrawerFooter = () => ( +
+ + + + +
+ ); return ( <> - - - - - - } + footer={} className={styles.drawer} > diff --git a/src/page/Project/Sensitive/components/SensitiveColumn/components/ManualForm.tsx b/src/page/Project/Sensitive/components/SensitiveColumn/components/ManualForm.tsx index 841049901..5e51d3ef0 100644 --- a/src/page/Project/Sensitive/components/SensitiveColumn/components/ManualForm.tsx +++ b/src/page/Project/Sensitive/components/SensitiveColumn/components/ManualForm.tsx @@ -99,7 +99,7 @@ const ManualForm: React.FC = ({ modalOpen, setModalOpen, callba }); setDatabaseOptions(resData); }; - const handleDatabaseSelect = debounce(async (value: number, args) => { + const handleDatabaseSelect = async (value: number) => { if (value === -1) { setDatabaseIds(databaseOptions?.map((option) => option.value as number)); return; @@ -107,7 +107,10 @@ const ManualForm: React.FC = ({ modalOpen, setModalOpen, callba if (!databaseIds?.includes(value)) { setDatabaseIds(databaseIds.concat(value)); } - }, 500); + }; + const handleDatabaseClear = () => { + setDatabaseIds([]); + }; const handleDatabaseDeselect = debounce(async (value: number) => { setDatabaseIds(databaseIds.filter((id) => id !== value)); }, 500); @@ -205,6 +208,7 @@ const ManualForm: React.FC = ({ modalOpen, setModalOpen, callba } onSelect={handleDatabaseSelect} onDeselect={handleDatabaseDeselect} + onClear={handleDatabaseClear} optionLabelProp="label" allowClear={true} > @@ -831,7 +835,7 @@ const SelectedSensitiveColumn = forwardRef(function ( ); }, [defaultActiveKey, data]); - useEffect(() => { + const handleDatabaseChange = debounce(() => { setAllColumns(0); setCheckedColumns(0); setCheckedKeys([]); @@ -850,6 +854,9 @@ const SelectedSensitiveColumn = forwardRef(function ( setOriginData([]); setFormData({}); } + }, 500); + useEffect(() => { + handleDatabaseChange(); }, [databaseIds]); useEffect(() => { handleCheckedKeysChange(); diff --git a/src/page/Project/Sensitive/components/SensitiveColumn/components/SacnRule.tsx b/src/page/Project/Sensitive/components/SensitiveColumn/components/SacnRule.tsx index 71d513edc..ea548dcf5 100644 --- a/src/page/Project/Sensitive/components/SensitiveColumn/components/SacnRule.tsx +++ b/src/page/Project/Sensitive/components/SensitiveColumn/components/SacnRule.tsx @@ -23,11 +23,13 @@ import { formatMessage } from '@/util/intl'; import { Button, Divider, Form, Select } from 'antd'; import { useContext, useEffect, useState } from 'react'; import SensitiveContext from '../../../SensitiveContext'; +import { useWatch } from 'antd/es/form/Form'; const ScanRule = ({ formRef, reset, setManageSensitiveRuleDrawerOpen }) => { const context = useContext(ProjectContext); const sensitiveContext = useContext(SensitiveContext); const [dataSourceId, setDataSourceId] = useState(-1); const [databaseId, setDatabaseId] = useState(0); + const databaseIds = useWatch('databaseIds', formRef); const [selectOpen, setSelectOpen] = useState(false); const [dataSourceOptions, setDataSourceOptions] = useState([]); const [databaseIdsOptions, setDatabaseIdsOptions] = useState([]); @@ -203,11 +205,7 @@ const ScanRule = ({ formRef, reset, setManageSensitiveRuleDrawerOpen }) => { }) //请选择 } maxTagCount="responsive" - disabled={ - databaseIdsOptions?.length === 1 || - dataSourceOptions?.length === 0 || - dataSourceId === -1 - } + disabled={databaseIdsOptions?.length === 1 || dataSourceId === -1} style={{ width: '262px', }} @@ -240,7 +238,11 @@ const ScanRule = ({ formRef, reset, setManageSensitiveRuleDrawerOpen }) => { options={sensitiveOptions} onSelect={handleSensitiveRuleIdsSelect} disabled={ - databaseIdsOptions?.length === 1 || sensitiveOptions?.length === 1 || databaseId === 0 + dataSourceId === -1 || + databaseIdsOptions?.length === 1 || + databaseIds?.length === 0 || + databaseId === 0 || + sensitiveOptions?.length === 1 } maxTagCount="responsive" placeholder={ diff --git a/src/page/Project/Sensitive/components/SensitiveColumn/components/ScanForm.tsx b/src/page/Project/Sensitive/components/SensitiveColumn/components/ScanForm.tsx index 0ba250d99..b96b710ad 100644 --- a/src/page/Project/Sensitive/components/SensitiveColumn/components/ScanForm.tsx +++ b/src/page/Project/Sensitive/components/SensitiveColumn/components/ScanForm.tsx @@ -34,19 +34,401 @@ import { ScanTableData, ScanTableDataItem } from '../../../interface'; import styles from './index.less'; import ScanRule from './SacnRule'; import classnames from 'classnames'; -import { ESensitiveColumnType } from '@/d.ts/sensitiveColumn'; +import { ESensitiveColumnType, ISensitiveColumn } from '@/d.ts/sensitiveColumn'; import TableOutlined from '@/svgr/menuTable.svg'; import ViewSvg from '@/svgr/menuView.svg'; import { MaskRyleTypeMap } from '@/d.ts'; import { PopoverContainer } from '..'; -import { useCallback, useContext, useEffect, useLayoutEffect, useState } from 'react'; -import SensitiveContext from '../../../SensitiveContext'; +import { forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState } from 'react'; +import SensitiveContext, { ISensitiveContext } from '../../../SensitiveContext'; +import { + ScannResultType, + getScanningResults, + startScanning, +} from '@/common/network/sensitiveColumn'; +import ProjectContext from '@/page/Project/ProjectContext'; +import { checkResult, defaultScanTableData } from './FormSensitiveColumnDrawer'; +import React from 'react'; +interface IScanFormProps { + formRef: FormInstance; + _formRef: FormInstance; + + setSensitiveColumns: React.Dispatch>; + setFormData: React.Dispatch>; + setManageSensitiveRuleDrawerOpen: React.Dispatch>; +} +const ScanForm = (props: IScanFormProps, ref) => { + const { + formRef, + _formRef, + setFormData, + setSensitiveColumns, + setManageSensitiveRuleDrawerOpen, + } = props; + const projectContext = useContext(ProjectContext); + const sensitiveContext = useContext(SensitiveContext); + const timer = useRef(null); + const [taskId, setTaskId] = useState(); + const [scanStatus, setScanStatus] = useState(); + const [scanLoading, setScanLoading] = useState(false); + const [hasScan, setHasScan] = useState(false); + const [percent, setPercent] = useState(0); + const [successful, setSuccessful] = useState(false); + const [searchText, setSearchText] = useState(''); + const [scanTableData, setScanTableData] = useState([]); + const [originScanTableData, setOriginScanTableData] = useState([]); + const [activeKeys, setActiveKeys] = useState(['0']); + const [sensitiveColumnMap, setSensitiveColumnMap] = useState>(new Map()); + const reset = () => { + setTaskId(null); + setScanStatus(null); + setScanLoading(false); + setHasScan(false); + setPercent(0); + setSuccessful(false); + setSearchText(''); + setScanTableData([]); + setOriginScanTableData([]); + setActiveKeys(['0']); + setSensitiveColumnMap(new Map()); + + setFormData({}); + setSensitiveColumns([]); + }; + + const handleSearchChange = (e) => { + setSearchText(e.target.value); + }; + const onSearch = () => { + if (searchText.trim() === '') { + return; + } + const resData = []; + sensitiveColumnMap.forEach((sc, key) => { + const filterColumn = sc?.dataSource?.filter((item) => + item?.columnName?.toLowerCase()?.includes(searchText?.toLocaleLowerCase()), + ); + if (filterColumn?.length > 0) { + resData.push({ + header: sc?.header, + dataSource: filterColumn, + }); + } + }); + setScanTableData(checkResult(resData)); + }; + const resetSearch = () => { + setSearchText(''); + setScanTableData(originScanTableData); + }; + const handleStartScan = async () => { + const rawData = await formRef.validateFields().catch(); + setScanTableData(defaultScanTableData); + setOriginScanTableData(defaultScanTableData); + if (rawData.databaseIds?.includes(-1)) { + rawData.allDatabases = true; + rawData.databaseIds = []; + } else { + rawData.allDatabases = false; + } + if (rawData.sensitiveRuleIds?.includes(-1)) { + rawData.allSensitiveRules = true; + rawData.sensitiveRuleIds = []; + } else { + rawData.allSensitiveRules = false; + } + setScanLoading(true); + const taskId = await startScanning(projectContext.projectId, rawData); + if (taskId) { + setTaskId(taskId); + setScanStatus(ScannResultType.CREATED); + } + }; + const handleScanning = async (taskId: string) => { + const rawData = await getScanningResults(projectContext.projectId, taskId); + const { status, sensitiveColumns, allTableCount, finishedTableCount } = rawData; + if ([ScannResultType.FAILED, ScannResultType.SUCCESS].includes(status)) { + const dataSourceMap = new Map(); + setSensitiveColumns(sensitiveColumns); + sensitiveColumns?.forEach((d) => { + const key = `${d.database.name}_${d.type}_${d.tableName}`; + if (dataSourceMap.has(key)) { + dataSourceMap.get(key)?.dataSource?.push({ + columnName: d.columnName, + sensitiveRuleId: d.sensitiveRuleId, + maskingAlgorithmId: d.maskingAlgorithmId, + }); + } else { + dataSourceMap.set(key, { + header: { + database: d.database.name, + databaseId: d.database.databaseId, + tableName: d.tableName, + type: d.type, + }, + dataSource: [ + { + columnName: d.columnName, + sensitiveRuleId: d.sensitiveRuleId, + maskingAlgorithmId: d.maskingAlgorithmId, + }, + ], + }); + } + }); + dataSourceMap.forEach((value, key) => { + value.dataSource = value.dataSource.sort((a, b) => + a?.columnName?.localeCompare(b?.columnName), + ); + dataSourceMap.set(key, value); + }); + setSensitiveColumnMap(dataSourceMap); + const resData = []; + dataSourceMap?.forEach((ds) => { + resData.push(ds); + }); + const rawFormData = checkResult(resData); + setActiveKeys( + rawFormData?.length === 0 + ? ['0'] + : rawFormData?.map( + ({ header: { database, tableName, type }, dataSource }, index) => + `${database}_${type}_${tableName}`, + ), + ); + setScanTableData(rawFormData); + setOriginScanTableData(rawFormData); + + const scanTableData = {}; + const newScanTableDataMap = {}; + rawFormData?.forEach(({ dataSource = [], header = {} }) => { + const { database = '', tableName, type, databaseId } = header; + scanTableData[database] = scanTableData?.[database] || { + [ESensitiveColumnType.TABLE_COLUMN]: {}, + [ESensitiveColumnType.VIEW_COLUMN]: {}, + }; + scanTableData[database][type][tableName] = {}; + dataSource?.forEach(({ columnName, maskingAlgorithmId }) => { + scanTableData[database][type][tableName][columnName] = maskingAlgorithmId; + newScanTableDataMap[ + `${database}_${type}_${tableName}_${columnName}` + ] = sensitiveColumns?.find( + (item) => + item?.database?.databaseId === databaseId && + item.type === type && + item.tableName === tableName && + item.columnName === columnName, + ); + }); + }); + setFormData(scanTableData); + setSuccessful(true); + setScanStatus(ScannResultType.SUCCESS); + setPercent(Math.floor((finishedTableCount * 100) / allTableCount)); + await _formRef.setFieldsValue({ + scanTableData, + }); + setScanLoading(false); + } else { + setScanStatus(ScannResultType.RUNNING); + setHasScan(true); + setSuccessful(false); + setActiveKeys(['0']); + setScanLoading(true); + setPercent(Math.floor((finishedTableCount * 100) / allTableCount)); + timer.current = setTimeout(() => { + handleScanning(taskId); + clearTimeout(timer.current); + }, 500); + } + }; + + const handleScanTableDataDelete = ( + database: string, + type: string, + tableName: string, + columnName: string, + ) => { + const key = `${database}_${type}_${tableName}`; + const filterDataSource = + sensitiveColumnMap.get(key).dataSource.filter((ds) => ds?.columnName !== columnName) || []; + sensitiveColumnMap.get(key).dataSource = filterDataSource; + if (filterDataSource?.length === 0) { + sensitiveColumnMap.delete(key); + } + const resData = []; + if (!!searchText) { + sensitiveColumnMap?.forEach((dsItem) => { + const newDataSource = dsItem?.dataSource?.filter((ds) => + ds?.columnName?.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()), + ); + if (newDataSource?.length > 0) { + resData.push({ + header: dsItem?.header, + dataSource: newDataSource, + }); + } + }); + } else { + // 没有searchText 纯删除 + sensitiveColumnMap?.forEach((dsItem) => { + resData.push(dsItem); + }); + } + const newTableData = checkResult(resData); + setScanTableData(newTableData); + setOriginScanTableData(newTableData); + newTableData?.length === 0 && setActiveKeys(['0']); + setSensitiveColumnMap(sensitiveColumnMap); + }; + const handleScanTableDataDeleteByTableName = ( + database: string, + type: string, + tableName: string, + ) => { + const key = `${database}_${type}_${tableName}`; + const resData = []; + if (!!searchText) { + sensitiveColumnMap.get(key).dataSource = sensitiveColumnMap + .get(key) + .dataSource?.filter( + (item) => !item.columnName?.toLowerCase()?.includes(searchText?.toLowerCase()), + ); + const originResData = []; + sensitiveColumnMap?.forEach((dsItem) => { + if (dsItem?.dataSource?.length > 0) { + originResData.push(dsItem); + } + }); + const newTableData = checkResult(originResData); + newTableData?.length === 0 && setActiveKeys(['0']); + setOriginScanTableData(newTableData); + sensitiveColumnMap?.forEach((dsItem, dsKey) => { + if (dsItem?.dataSource?.length > 0) { + resData.push(dsItem); + } else { + sensitiveColumnMap.delete(key); + } + }); + } else { + sensitiveColumnMap.delete(key); + sensitiveColumnMap?.forEach((dsItem) => { + resData.push(dsItem); + }); + const newTableData = checkResult(resData); + setOriginScanTableData(newTableData); + newTableData?.length === 0 && setActiveKeys(['0']); + } + setScanTableData(checkResult(resData)); + setSensitiveColumnMap(sensitiveColumnMap); + }; + + useImperativeHandle(ref, () => { + return { + getColumnMap: () => { + return sensitiveColumnMap; + }, + reset, + }; + }); + useEffect(() => { + if (taskId && [ScannResultType.CREATED, ScannResultType.RUNNING].includes(scanStatus)) { + handleScanning(taskId); + } + return () => { + clearTimeout(timer.current); + }; + }, [taskId, scanStatus]); + + useEffect(() => { + if (successful && searchText === '') { + const resData = []; + sensitiveColumnMap?.forEach((ds) => { + resData.push(ds); + }); + setScanTableData(checkResult(resData)); + setOriginScanTableData(checkResult(resData)); + } + }, [searchText, successful]); + return ( + <> +
+ + + + +
+
+ {originScanTableData?.length === 0 ? ( + + ) : ( + + )} + +
+ + ); +}; + const EmptyOrSpin: React.FC<{ + empty?: boolean; + isSearch?: boolean; hasScan: boolean; percent: number; successful: boolean; scanLoading: boolean; -}> = ({ scanLoading, hasScan, percent, successful }) => { +}> = ({ empty = false, isSearch = false, scanLoading, hasScan, percent, successful }) => { + const gentDescription = () => { + if (hasScan && isSearch && isSearch) { + return '扫描结果中的敏感列不包含搜索内容'; + } + if (hasScan && successful && empty) { + return '选中数据库目前暂无可选敏感列'; + } + if (hasScan && !successful) { + return '扫描失败'; + } + return '暂无数据'; + }; return (
- ) : hasScan && successful ? ( - ) : ( - + )} ); }; - -const ScanForm: React.FC<{ - formRef: FormInstance; - _formRef: FormInstance; - - hasScan: boolean; - percent: number; +const ScanButton: React.FC<{ + scanLoading: boolean; successful: boolean; - activeKeys: string | string[]; + handleStartScan: () => void; +}> = ({ scanLoading, successful, handleStartScan }) => { + return ( + + + {successful && ( + + +
+ { + formatMessage({ + id: 'odc.SensitiveColumn.components.ScanForm.ScanCompleted', + }) /*扫描完成*/ + } +
+
+ )} +
+ ); +}; +const getColumns = ( + database: string, + type: ESensitiveColumnType, + tableName: string, + sensitiveContext: Partial, + handleScanTableDataDelete: ( + database: string, + type: string, + tableName: string, + columnName: string, + ) => void, +) => { + return [ + { + title: formatMessage({ + id: 'odc.SensitiveColumn.components.ScanForm.Column', + }), + //列 + width: 146, + dataIndex: 'columnName', + key: 'columnName', + }, + { + title: formatMessage({ + id: 'odc.SensitiveColumn.components.ScanForm.IdentificationRules', + }), + //识别规则 + width: 126, + dataIndex: 'sensitiveRuleId', + key: 'sensitiveRuleId', + render: (text) => sensitiveContext?.sensitiveRuleIdMap?.[text], + }, + { + title: formatMessage({ + id: 'odc.SensitiveColumn.components.ScanForm.DesensitizationAlgorithm', + }), + //脱敏算法 + width: 180, + dataIndex: 'maskingAlgorithmId', + key: 'maskingAlgorithmId', + render: (text, record, _index) => { + return ( + + + + ); + }, + }, + { + title: formatMessage({ + id: 'odc.SensitiveColumn.components.ScanForm.Operation', + }), + //操作 + width: 88, + key: 'action', + render: (_, record) => ( + + + handleScanTableDataDelete( + database, + type, + tableName, + (record as ScanTableDataItem)?.columnName, + ) + } + > + { + formatMessage({ + id: 'odc.SensitiveColumn.components.ScanForm.Delete', + }) /*删除*/ + } + + + ), + }, + ]; +}; +const PreviewHeader: React.FC<{ searchText: string; - scanLoading: boolean; scanTableData: ScanTableData[]; originScanTableData: ScanTableData[]; - reset: () => void; onSearch: () => void; resetSearch: () => void; - setActiveKeys: (keys: string[]) => void; - handleStartScan: () => Promise; - resetScanTableData: () => void; handleSearchChange: (e: any) => void; - handleScanTableDataDelete: (database: string, tableName: string, columnName: string) => void; - setManageSensitiveRuleDrawerOpen: React.Dispatch>; - handleScanTableDataDeleteByTableName: (database: string, tableName: string) => void; }> = ({ - formRef, - _formRef, - activeKeys, - setActiveKeys, - resetSearch, - originScanTableData, - reset, - hasScan, - handleStartScan, - scanLoading, - successful, searchText, - handleSearchChange, - onSearch, scanTableData, - percent, - setManageSensitiveRuleDrawerOpen, - handleScanTableDataDelete, - handleScanTableDataDeleteByTableName, -}) => { - const sensitiveContext = useContext(SensitiveContext); - const { maskingAlgorithms } = sensitiveContext; - const getColumns = (database: string, type: ESensitiveColumnType, tableName: string) => { - return [ - { - title: formatMessage({ - id: 'odc.SensitiveColumn.components.ScanForm.Column', - }), - //列 - width: 146, - dataIndex: 'columnName', - key: 'columnName', - }, - { - title: formatMessage({ - id: 'odc.SensitiveColumn.components.ScanForm.IdentificationRules', - }), - //识别规则 - width: 126, - dataIndex: 'sensitiveRuleId', - key: 'sensitiveRuleId', - render: (text) => sensitiveContext?.sensitiveRuleIdMap?.[text], - }, - { - title: formatMessage({ - id: 'odc.SensitiveColumn.components.ScanForm.DesensitizationAlgorithm', - }), - //脱敏算法 - width: 180, - dataIndex: 'maskingAlgorithmId', - key: 'maskingAlgorithmId', - render: (text, record, _index) => { - return ( - - - - ); - }, - }, + originScanTableData, + onSearch, + resetSearch, + handleSearchChange, +}) => ( + +); +const CollapseHeader: React.FC<{ + database: string; + type: ESensitiveColumnType; + tableName: string; + handleScanTableDataDeleteByTableName: (database: string, type: string, tableName: string) => void; +}> = ({ database, type, tableName, handleScanTableDataDeleteByTableName }) => ( + + + {database} + + +
+
+ + + + + {tableName} + +
+ + { + e.preventDefault(); + e.stopPropagation(); + handleScanTableDataDeleteByTableName(database, type, tableName); + return; + }} + /> + +
+
+
+); +const EmptyCollapse: React.FC<{ + empty?: boolean; + isSearch?: boolean; + percent?: number; + hasScan?: boolean; + scanLoading?: boolean; + successful?: boolean; +}> = ({ empty = false, isSearch = false, percent, hasScan, scanLoading, successful }) => { + return ( + + + - { + {''} + + - - ), - }, - ]; - }; - const WrapCollapse = useCallback(() => { - return ( - { - setActiveKeys(Array.isArray(keys) ? keys : [keys]); - }} - className={ - scanTableData?.length === 0 - ? classnames(styles.collapse) - : classnames(styles.collapse, styles.collapses) + > + {''} + + } > - {scanTableData?.length === 0 ? ( + + + + ); +}; + +const CollapseItemContent: React.FC<{ + activeKeys: string[]; + scanTableData: ScanTableData[]; + sensitiveContext: Partial; + setActiveKeys: (keys: string[]) => void; + handleScanTableDataDelete: ( + database: string, + type: string, + tableName: string, + columnName: string, + ) => void; + handleScanTableDataDeleteByTableName: (database: string, type: string, tableName: string) => void; +}> = ({ + activeKeys, + scanTableData, + sensitiveContext, + setActiveKeys, + handleScanTableDataDelete, + handleScanTableDataDeleteByTableName, +}) => { + return scanTableData?.length === 0 ? ( + + ) : ( + { + setActiveKeys( + Array.isArray(keys) + ? keys?.filter((key) => key !== '0') + : [keys]?.filter((key) => key !== '0'), + ); + }} + className={classnames(styles.collapse, styles.collapses)} + > + {scanTableData?.map(({ header: { database, tableName, type }, dataSource }, index) => { + return ( - - {''} - - - {''} - - + } + key={`${database}_${type}_${tableName}`} > - - - ) : ( - <> - {scanTableData?.map(({ header: { database, tableName, type }, dataSource }, index) => { - return ( - - - {database} - - -
-
- - - - - {tableName} - -
- - { - e.preventDefault(); - e.stopPropagation(); - handleScanTableDataDeleteByTableName(database, tableName); - return; - }} - /> - -
-
- - } - key={`${database}_${type}_${tableName}`} - > - 10 ? false : true, - }} - /> - - ); - })} - - )} - - ); - }, [scanTableData, activeKeys]); - return ( - <> - - - - - {successful && ( - - -
- { - formatMessage({ - id: 'odc.SensitiveColumn.components.ScanForm.ScanCompleted', - }) /*扫描完成*/ - } -
-
- )} -
- -
-
- { - formatMessage({ - id: 'odc.SensitiveColumn.components.ScanForm.PreviewOfScanResults', - }) /*扫描结果预览*/ - } -
- {originScanTableData?.length > 0 ? ( - - 10 ? false : true, }} - onChange={handleSearchChange} - onSearch={onSearch} /> - - - ) : ( - scanTableData?.length > 0 && ( - - ) - )} -
-
-
- - -
- + + ); + })} + ); }; -export default ScanForm; + +export default forwardRef(ScanForm); diff --git a/src/page/Project/Sensitive/components/SensitiveColumn/components/index.less b/src/page/Project/Sensitive/components/SensitiveColumn/components/index.less index e49d39c16..7902c2c51 100644 --- a/src/page/Project/Sensitive/components/SensitiveColumn/components/index.less +++ b/src/page/Project/Sensitive/components/SensitiveColumn/components/index.less @@ -69,7 +69,7 @@ } } .tooltipContent { - max-width: 240px; + max-width: 220px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; diff --git a/src/page/Project/Sensitive/components/SensitiveColumn/index.tsx b/src/page/Project/Sensitive/components/SensitiveColumn/index.tsx index b6260ac54..3ccc942be 100644 --- a/src/page/Project/Sensitive/components/SensitiveColumn/index.tsx +++ b/src/page/Project/Sensitive/components/SensitiveColumn/index.tsx @@ -575,7 +575,6 @@ const SensitiveColumn = ({ <>