From 61318075a69a85fafe41d705dab1e9c017ad800b Mon Sep 17 00:00:00 2001 From: zzyangh <799463087@qq.com> Date: Mon, 18 Nov 2024 17:19:10 +0800 Subject: [PATCH 01/20] [chore]: Update Api --- .../shared/lib/api/sqle/service/common.d.ts | 10 ++++++---- .../lib/api/sqle/service/task/index.d.ts | 8 -------- .../lib/api/sqle/service/task/index.enum.ts | 8 ++++++-- .../shared/lib/api/sqle/service/task/index.ts | 17 ----------------- .../lib/api/sqle/service/workflow/index.d.ts | 8 ++++++++ .../api/sqle/service/workflow/index.enum.ts | 4 +++- .../lib/api/sqle/service/workflow/index.ts | 19 ++++++++++++++++++- 7 files changed, 41 insertions(+), 33 deletions(-) diff --git a/packages/shared/lib/api/sqle/service/common.d.ts b/packages/shared/lib/api/sqle/service/common.d.ts index ae90425ff..41d85a881 100644 --- a/packages/shared/lib/api/sqle/service/common.d.ts +++ b/packages/shared/lib/api/sqle/service/common.d.ts @@ -447,6 +447,8 @@ export interface IBackupSqlData { instance_name?: string; origin_sql?: string; + + origin_task_id?: number; } export interface IBackupSqlListRes { @@ -2092,6 +2094,8 @@ export interface IInstanceTableMeta { } export interface IInstanceTipResV1 { + enable_backup?: boolean; + host?: string; instance_id?: string; @@ -2550,18 +2554,16 @@ export interface IRuleTemplateResV1 { desc?: string; - is_default_rule_template?: boolean; - rule_template_name?: string; } export interface IRuleTemplateTipResV1 { db_type?: string; - rule_template_id?: string; - is_default_rule_template?: boolean; + rule_template_id?: string; + rule_template_name?: string; } diff --git a/packages/shared/lib/api/sqle/service/task/index.d.ts b/packages/shared/lib/api/sqle/service/task/index.d.ts index 3ee6ed4f8..1d74a10eb 100644 --- a/packages/shared/lib/api/sqle/service/task/index.d.ts +++ b/packages/shared/lib/api/sqle/service/task/index.d.ts @@ -6,7 +6,6 @@ import { IUpdateSqlFileOrderV1Req, IGetSqlFileOrderMethodResV1, IAuditTaskGroupResV1, - IUpdateTaskBackupStrategyReq, IBaseRes, IGetAuditTaskSQLContentResV1, IGetAuditTaskSQLsResV1, @@ -101,13 +100,6 @@ export interface IGetAuditTaskV1Params { export interface IGetAuditTaskV1Return extends IGetAuditTaskResV1 {} -export interface IUpdateTaskBackupStrategyV1Params - extends IUpdateTaskBackupStrategyReq { - task_id: string; -} - -export interface IUpdateTaskBackupStrategyV1Return extends IBaseRes {} - export interface IDownloadAuditFileParams { task_id: string; } diff --git a/packages/shared/lib/api/sqle/service/task/index.enum.ts b/packages/shared/lib/api/sqle/service/task/index.enum.ts index f8978ebd5..e2bb4f552 100644 --- a/packages/shared/lib/api/sqle/service/task/index.enum.ts +++ b/packages/shared/lib/api/sqle/service/task/index.enum.ts @@ -9,7 +9,9 @@ export enum getAuditTaskSQLsV1FilterExecStatusEnum { 'failed' = 'failed', - 'manually_executed' = 'manually_executed' + 'manually_executed' = 'manually_executed', + + 'execute_rollback' = 'execute_rollback' } export enum getAuditTaskSQLsV1FilterAuditStatusEnum { @@ -45,7 +47,9 @@ export enum getAuditTaskSQLsV2FilterExecStatusEnum { 'terminate_succeeded' = 'terminate_succeeded', - 'terminate_failed' = 'terminate_failed' + 'terminate_failed' = 'terminate_failed', + + 'execute_rollback' = 'execute_rollback' } export enum getAuditTaskSQLsV2FilterAuditStatusEnum { diff --git a/packages/shared/lib/api/sqle/service/task/index.ts b/packages/shared/lib/api/sqle/service/task/index.ts index 06ee4f0eb..9da771583 100644 --- a/packages/shared/lib/api/sqle/service/task/index.ts +++ b/packages/shared/lib/api/sqle/service/task/index.ts @@ -18,8 +18,6 @@ import { IAuditTaskGroupIdV1Return, IGetAuditTaskV1Params, IGetAuditTaskV1Return, - IUpdateTaskBackupStrategyV1Params, - IUpdateTaskBackupStrategyV1Return, IDownloadAuditFileParams, IDownloadAuditFileReturn, IGetAuditTaskSQLContentV1Params, @@ -230,21 +228,6 @@ class TaskService extends ServiceBase { ); } - public UpdateTaskBackupStrategyV1( - params: IUpdateTaskBackupStrategyV1Params, - options?: AxiosRequestConfig - ) { - const paramsData = this.cloneDeep(params); - const task_id = paramsData.task_id; - delete paramsData.task_id; - - return this.patch( - `/v1/tasks/audits/${task_id}/`, - paramsData, - options - ); - } - public DownloadAuditFile( params: IDownloadAuditFileParams, options?: AxiosRequestConfig diff --git a/packages/shared/lib/api/sqle/service/workflow/index.d.ts b/packages/shared/lib/api/sqle/service/workflow/index.d.ts index 4239c324a..a9c47ac0e 100644 --- a/packages/shared/lib/api/sqle/service/workflow/index.d.ts +++ b/packages/shared/lib/api/sqle/service/workflow/index.d.ts @@ -16,6 +16,7 @@ import { IRejectWorkflowReqV1, IGetWorkflowTasksResV1, IUpdateWorkflowScheduleReqV1, + IUpdateTaskBackupStrategyReq, IUpdateSqlBackupStrategyReq, IGetWorkflowStatisticOfInstancesResV1, ICreateWorkflowReqV2, @@ -306,6 +307,13 @@ export interface IUpdateWorkflowScheduleV1Params export interface IUpdateWorkflowScheduleV1Return extends IBaseRes {} +export interface IUpdateTaskBackupStrategyV1Params + extends IUpdateTaskBackupStrategyReq { + task_id: string; +} + +export interface IUpdateTaskBackupStrategyV1Return extends IBaseRes {} + export interface IUpdateSqlBackupStrategyV1Params extends IUpdateSqlBackupStrategyReq { task_id: string; diff --git a/packages/shared/lib/api/sqle/service/workflow/index.enum.ts b/packages/shared/lib/api/sqle/service/workflow/index.enum.ts index 22d6c4a78..b75be7f07 100644 --- a/packages/shared/lib/api/sqle/service/workflow/index.enum.ts +++ b/packages/shared/lib/api/sqle/service/workflow/index.enum.ts @@ -95,5 +95,7 @@ export enum GetBackupSqlListV1FilterExecStatusEnum { 'terminate_succeeded' = 'terminate_succeeded', - 'terminate_failed' = 'terminate_failed' + 'terminate_failed' = 'terminate_failed', + + 'execute_rollback' = 'execute_rollback' } diff --git a/packages/shared/lib/api/sqle/service/workflow/index.ts b/packages/shared/lib/api/sqle/service/workflow/index.ts index ea36c516d..80a58545c 100644 --- a/packages/shared/lib/api/sqle/service/workflow/index.ts +++ b/packages/shared/lib/api/sqle/service/workflow/index.ts @@ -52,6 +52,8 @@ import { IExecuteOneTaskOnWorkflowV1Return, IUpdateWorkflowScheduleV1Params, IUpdateWorkflowScheduleV1Return, + IUpdateTaskBackupStrategyV1Params, + IUpdateTaskBackupStrategyV1Return, IUpdateSqlBackupStrategyV1Params, IUpdateSqlBackupStrategyV1Return, IGetWorkflowStatisticOfInstancesParams, @@ -492,6 +494,21 @@ class WorkflowService extends ServiceBase { ); } + public UpdateTaskBackupStrategyV1( + params: IUpdateTaskBackupStrategyV1Params, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const task_id = paramsData.task_id; + delete paramsData.task_id; + + return this.patch( + `/v1/tasks/audits/${task_id}/backup_strategy`, + paramsData, + options + ); + } + public UpdateSqlBackupStrategyV1( params: IUpdateSqlBackupStrategyV1Params, options?: AxiosRequestConfig @@ -504,7 +521,7 @@ class WorkflowService extends ServiceBase { delete paramsData.sql_id; return this.patch( - `/v1/tasks/audits/${task_id}/sqls/${sql_id}/`, + `/v1/tasks/audits/${task_id}/sqls/${sql_id}/backup_strategy`, paramsData, options ); From 0450b911f74668283451280322efd675d61f1e17 Mon Sep 17 00:00:00 2001 From: zzyangh <799463087@qq.com> Date: Tue, 19 Nov 2024 14:19:52 +0800 Subject: [PATCH 02/20] [feature](SqlExecWorkflow): Add support configuration backup --- packages/shared/lib/data/routePaths.ts | 2 +- packages/sqle/src/data/EmitterKey.ts | 4 +- packages/sqle/src/locale/zh-CN/audit.ts | 3 +- .../sqle/src/locale/zh-CN/execWorkflow.ts | 44 +++++++++-- .../components/SqlBackupSwitcher.tsx | 79 +++++++++++++++++++ .../components/SwitchField.tsx | 44 +++++++++++ .../SqlStatementFormItem/index.tsx | 8 +- .../hooks/useRenderDatabaseSelectionItems.tsx | 15 ++-- .../DatabaseSelectionItems/index.tsx | 16 ++-- .../SqlAuditInfoFormItem/index.tsx | 4 +- .../Create/hooks/useAuditWorkflow.tsx | 2 + .../Create/hooks/useCreationMode.ts | 38 +++++---- .../src/page/SqlExecWorkflow/Create/index.tsx | 47 +++++++++-- .../page/SqlExecWorkflow/Create/index.type.ts | 3 + 14 files changed, 265 insertions(+), 44 deletions(-) create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx diff --git a/packages/shared/lib/data/routePaths.ts b/packages/shared/lib/data/routePaths.ts index 864f5220a..3492923ee 100644 --- a/packages/shared/lib/data/routePaths.ts +++ b/packages/shared/lib/data/routePaths.ts @@ -179,7 +179,7 @@ export const ROUTE_PATHS = { prefix: '/sqle/project/:projectID/exec-workflow', path: 'create', query: - 'sourceWorkflowId&versionId&versionName&compression_data&from&gen_modified_sql_params' + 'sourceWorkflowId&versionId&versionName&compression_data&from&gen_modified_sql_params&rollbackWorkflowId' }, detail: { prefix: '/sqle/project/:projectID/exec-workflow', diff --git a/packages/sqle/src/data/EmitterKey.ts b/packages/sqle/src/data/EmitterKey.ts index 5a6560461..dcf8263a3 100644 --- a/packages/sqle/src/data/EmitterKey.ts +++ b/packages/sqle/src/data/EmitterKey.ts @@ -39,7 +39,9 @@ enum EmitterKey { Refresh_Global_Dashboard_Pending_Work_Order = 'Refresh_Global_Dashboard_Pending_Work_Order', Refresh_Global_Dashboard_Pending_Sql = 'Refresh_Global_Dashboard_Pending_Work_Order', - Refresh_Global_Dashboard_Initiated_Work_Order = 'Refresh_Global_Dashboard_Initiated_Work_Order' + Refresh_Global_Dashboard_Initiated_Work_Order = 'Refresh_Global_Dashboard_Initiated_Work_Order', + + Refresh_Sql_Exec_workflow_Audit_Result_List = 'Refresh_Sql_Exec_workflow_Audit_Result_List' } export default EmitterKey; diff --git a/packages/sqle/src/locale/zh-CN/audit.ts b/packages/sqle/src/locale/zh-CN/audit.ts index 9d4457bc6..caa0137e2 100644 --- a/packages/sqle/src/locale/zh-CN/audit.ts +++ b/packages/sqle/src/locale/zh-CN/audit.ts @@ -40,7 +40,8 @@ export default { terminate_fail: '中止失败', terminate_succ: '中止成功', terminating: '正在中止', - allStatus: '全部状态' + allStatus: '全部状态', + rollback: '执行回滚' }, auditStatus: { diff --git a/packages/sqle/src/locale/zh-CN/execWorkflow.ts b/packages/sqle/src/locale/zh-CN/execWorkflow.ts index 74be07a53..d44ceebb5 100644 --- a/packages/sqle/src/locale/zh-CN/execWorkflow.ts +++ b/packages/sqle/src/locale/zh-CN/execWorkflow.ts @@ -104,7 +104,12 @@ export default { '当前支持MySQL、Oracle、PG类型数据源按文件模式上线', executeSqlMode: 'SQL模式', executeFileMode: '文件模式', - selectFileSortMethod: '选择文件排序方式' + selectFileSortMethod: '选择文件排序方式', + switchSqlBackup: '是否选择开启备份', + cancelSwitchSqlBackupTips: + '当前应用的数据源已开启备份需求,是否确认关闭备份?', + cancelSwitchSqlBackupTipsWithInstanceName: + '{instanceName}已开启备份需求,是否确认关闭备份?' }, tour: { modifyName: '修改工单名称', @@ -121,7 +126,17 @@ export default { submitWorkflowConfirmationMessage: '项目 {{currentProject}} 创建工单时最高只能允许有 {{allowAuditLevel}} 等级的审核错误,但是当前审核结果中最高包含 {{currentAuditLevel}} 等级的审核结果。', mustHaveAuditResultTips: '不能对审核结果为空的SQL进行创建工单', - leaveTip: '是否离开本页面?当前工单暂未提交!' + leaveTip: '是否离开本页面?当前工单暂未提交!', + switchDatabaseBackupPolicy: '切换数据源备份策略', + switchDatabaseBackupPolicyTips: '统一变更当前数据源上SQL的备份回滚策略为', + editBackupStrategy: '切换SQL备份回滚策略', + editBackupStrategySuccessTips: '切换SQL备份回滚策略成功' + }, + backupStrategy: { + reverseSql: '基于反向SQL回滚', + originRow: '基于行级备份回滚', + manual: '自行手工备份回滚', + none: '无' }, createResult: { success: '工单创建成功', @@ -174,6 +189,8 @@ export default { unknown: '未知步骤', refreshWorkflow: '刷新工单', backToDetail: '返回工单详情', + retry: '重试', + rollback: '回滚', maintenanceTime: '定时上线的时间点必须在运维时间之内,当前数据源的运维时间为: \n', @@ -237,7 +254,18 @@ export default { '当前操作将立即执行该数据源上的SQL语句, 是否确认立即上线' } }, - taskResult: {} + taskResult: {}, + + rollback: { + allSql: '全部SQL', + selectedRollbackSql: '被选中回滚SQL', + backupStrategy: '备份策略', + instance: '数据源', + execStatus: '执行状态', + remark: '备注', + addRemark: '添加备注', + originSql: '原始SQL' + } }, audit: { @@ -247,6 +275,7 @@ export default { duplicate: '是否去重', downloadSql: '下载SQL语句', downloadReport: '下载审核报告', + downloadRollbackSql: '下载回滚语句', table: { number: '序号', auditLevel: '规则等级', @@ -260,7 +289,11 @@ export default { describe: '说明', analyze: '分析', addDescribe: '添加说明', - createWhitelist: '添加为审核SQL例外' + createWhitelist: '添加为审核SQL例外', + backupPolicy: '备份回滚策略', + backupPolicyTips: + '平台将综合评估数据丢失风险及备份成本后,推荐每条SQL适用的备份回滚策略', + backupConflictTips: '当前SQL未按预期开启备份' }, filterForm: { @@ -336,7 +369,8 @@ export default { terminate_fail: '中止失败', terminate_succ: '中止成功', terminating: '正在中止', - allStatus: '全部状态' + allStatus: '全部状态', + rollback: '执行回滚' } } }; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx new file mode 100644 index 000000000..9608bc0e4 --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx @@ -0,0 +1,79 @@ +import { FormItemLabel } from '@actiontech/shared/lib/components/FormCom'; +import { useTranslation } from 'react-i18next'; +import { EmptyBox } from '@actiontech/shared'; +import { Form } from 'antd'; +import { SqlAuditInfoFormFields } from '../../../../Create/index.type'; +import { SqlBackupSwitcherProps } from './index.type'; +import { CreateAuditTasksGroupReqV1ExecModeEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum'; +import { useMemo } from 'react'; + +import SwitchField from './SwitchField'; + +const SqlBackupSwitcher: React.FC = ({ + fieldPrefixPath, + databaseInfo +}) => { + const { t } = useTranslation(); + + const form = Form.useFormInstance(); + + const currentExecuteMode = Form.useWatch( + [fieldPrefixPath, 'exec_mode'], + form + ); + const isSameSqlForAll = Form.useWatch('isSameSqlForAll', form); + + const getInitValue = () => { + if (isSameSqlForAll) { + return databaseInfo.some((item) => item.enableBackup); + } + return ( + databaseInfo.find((item) => item.key === fieldPrefixPath)?.enableBackup ?? + false + ); + }; + + const enableBackupInstanceName = useMemo(() => { + let nameStr = ''; + databaseInfo.forEach((item, index) => { + if (item.enableBackup) { + nameStr += `${item.instanceName}${ + index === databaseInfo.length - 1 ? '' : ',' + }`; + } + }); + return nameStr; + }, [databaseInfo]); + + return ( + + + + + + ); +}; + +export default SqlBackupSwitcher; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx new file mode 100644 index 000000000..569c5911c --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx @@ -0,0 +1,44 @@ +import { BasicSwitch } from '@actiontech/shared'; +import { Popconfirm } from 'antd'; +import { useTranslation } from 'react-i18next'; +import { useBoolean } from 'ahooks'; + +const SwitchField: React.FC<{ + checked?: boolean; + onChange?: (v: boolean) => void; + title?: string; +}> = ({ checked, onChange }) => { + const { t } = useTranslation(); + + const [ + popconfirmOpen, + { setTrue: showPopconfirm, setFalse: hidePopconfirm } + ] = useBoolean(); + + return ( + { + onChange?.(false); + hidePopconfirm(); + }} + onCancel={hidePopconfirm} + > + { + if (!checked) { + onChange?.(true); + } else { + showPopconfirm(); + } + }} + /> + + ); +}; + +export default SwitchField; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/index.tsx index 3440dabcf..fa5cee03e 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/index.tsx @@ -14,6 +14,7 @@ import { SqlAuditInfoFormProps } from '../../../Create/components/FormStep/SqlAu import SqlExecModeSelector from './components/SqlExecModeSelector'; import SqlFormatterAndSubmitter from './components/SqlFormatterAndSubmitter'; import { RingPieFilled } from '@actiontech/icons'; +import SqlBackupSwitcher from './components/SqlBackupSwitcher'; const SqlStatementFormItem: React.FC = ({ fieldPrefixPath, @@ -83,7 +84,12 @@ const SqlStatementFormItem: React.FC = ({ isSupportFileModeExecuteSql={isSupportFileModeExecuteSql} isAtRejectStep={isAtRejectStep} /> - + {/* #if [ee] */} + + {/* #endif */} ) => { +> & { instanceList: IInstanceTipResV1[] }) => { const { t } = useTranslation(); const { projectName, projectID } = useCurrentProject(); const { sqleTheme } = useThemeStyleData(); - const { isCloneMode } = useCreationMode(); + const { isCloneMode, isRollbackMode } = useCreationMode(); const sqlExecWorkflowReduxState = useSelector((state: IReduxState) => { return { @@ -39,7 +41,7 @@ const useRenderDatabaseSelectionItems = ({ }); useEffect(() => { - if (isCloneMode) { + if (isCloneMode || isRollbackMode) { sqlExecWorkflowReduxState.clonedExecWorkflowSqlAuditInfo?.databaseInfo?.forEach( (database, index) => { const key = `${index}`; @@ -114,7 +116,10 @@ const useRenderDatabaseSelectionItems = ({ ruleTemplate: undefined, dbType: undefined, testConnectResult: undefined, - isSupportFileModeExecuteSql: true + isSupportFileModeExecuteSql: true, + enableBackup: + instanceList.find((i) => i.instance_name === instanceName) + ?.enable_backup ?? false }); updateSchemaList(key, instanceName); updateRuleTemplateNameAndDbType(key, instanceName); diff --git a/packages/sqle/src/page/SqlExecWorkflow/Create/components/FormStep/SqlAuditInfoForm/SqlAuditInfoFormItem/DatabaseSelectionItems/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Create/components/FormStep/SqlAuditInfoForm/SqlAuditInfoFormItem/DatabaseSelectionItems/index.tsx index dfbf37246..cbdb14693 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Create/components/FormStep/SqlAuditInfoForm/SqlAuditInfoFormItem/DatabaseSelectionItems/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Create/components/FormStep/SqlAuditInfoForm/SqlAuditInfoFormItem/DatabaseSelectionItems/index.tsx @@ -64,6 +64,13 @@ const DatabaseSelectionItem: React.FC = ({ instanceTestConnectResults: sharedStepDetail.instanceTestConnectResults }); + const { + loading: instanceTipsLoading, + updateInstanceList, + instanceOptions, + instanceList + } = useInstance(); + const { handleInstanceChange, handleInstanceSchemaChange, @@ -74,7 +81,8 @@ const DatabaseSelectionItem: React.FC = ({ renderAddItemButton } = useRenderDatabaseSelectionItems({ dbSourceInfoCollection: sharedStepDetail.dbSourceInfoCollection, - sqlStatementTabActiveKey: sharedStepDetail.sqlStatementTabActiveKey + sqlStatementTabActiveKey: sharedStepDetail.sqlStatementTabActiveKey, + instanceList }); useSetFormValuesWithGenModifiedSqlParams({ @@ -85,12 +93,6 @@ const DatabaseSelectionItem: React.FC = ({ setGetModifiedSQLsPending: sharedStepDetail.getModifiedSQLsPending.set }); - const { - loading: instanceTipsLoading, - updateInstanceList, - instanceOptions - } = useInstance(); - const versionFirstStageInstanceOptions = useMemo(() => { const newOptions: SelectProps['options'] = []; instanceOptions.forEach((item) => { diff --git a/packages/sqle/src/page/SqlExecWorkflow/Create/components/FormStep/SqlAuditInfoForm/SqlAuditInfoFormItem/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Create/components/FormStep/SqlAuditInfoForm/SqlAuditInfoFormItem/index.tsx index 595ee4e32..b9280714f 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Create/components/FormStep/SqlAuditInfoForm/SqlAuditInfoFormItem/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Create/components/FormStep/SqlAuditInfoForm/SqlAuditInfoFormItem/index.tsx @@ -31,7 +31,9 @@ const SqlAuditInfoFormItem = forwardRef( sharedStepDetail.dbSourceInfoCollection.value?.[key] ?.instanceName, schemaName: - sharedStepDetail.dbSourceInfoCollection.value?.[key]?.schemaName + sharedStepDetail.dbSourceInfoCollection.value?.[key]?.schemaName, + enableBackup: + sharedStepDetail.dbSourceInfoCollection.value?.[key]?.enableBackup }; }) .filter((v) => !!v.instanceName); diff --git a/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useAuditWorkflow.tsx b/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useAuditWorkflow.tsx index 392b298d3..ed1f5e06a 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useAuditWorkflow.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useAuditWorkflow.tsx @@ -140,6 +140,7 @@ const useAuditWorkflow = () => { ) { const auditTaskPrams: IAuditTaskGroupIdV1Params = { task_group_id: taskGroupInfo.data.data?.task_group_id, + enable_backup: sqlStatementInfo.backup, ...getSqlSourceWithUploadType(sqlStatementInfo) }; const res = await task.auditTaskGroupIdV1(auditTaskPrams); @@ -191,6 +192,7 @@ const useAuditWorkflow = () => { ...getSqlSourceWithUploadType(sqlStatementInfo), exec_mode: sqlStatementInfo.exec_mode as unknown as CreateAuditTaskReqV1ExecModeEnum, + enable_backup: sqlStatementInfo.backup, // #if [ee] file_order_method: sqlStatementInfo.file_sort_method // #endif diff --git a/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useCreationMode.ts b/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useCreationMode.ts index 0f7e5054a..65a3216eb 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useCreationMode.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useCreationMode.ts @@ -5,25 +5,35 @@ import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; const useCreationMode = () => { const extraQueries = useTypedQuery(); - const { isAssociationVersionMode, versionId, versionName, isCloneMode } = - useMemo(() => { - const searchParams = extraQueries( - ROUTE_PATHS.SQLE.SQL_EXEC_WORKFLOW.create - ); - return { - isAssociationVersionMode: - !!searchParams?.versionId && !!searchParams?.versionName, - versionId: searchParams?.versionId, - versionName: searchParams?.versionName, - isCloneMode: !!searchParams?.sourceWorkflowId - }; - }, [extraQueries]); + const { + isAssociationVersionMode, + versionId, + versionName, + isCloneMode, + isRollbackMode, + rollbackWorkflowId + } = useMemo(() => { + const searchParams = extraQueries( + ROUTE_PATHS.SQLE.SQL_EXEC_WORKFLOW.create + ); + return { + isAssociationVersionMode: + !!searchParams?.versionId && !!searchParams?.versionName, + versionId: searchParams?.versionId, + versionName: searchParams?.versionName, + isCloneMode: !!searchParams?.sourceWorkflowId, + isRollbackMode: !!searchParams?.rollbackWorkflowId, + rollbackWorkflowId: searchParams?.rollbackWorkflowId + }; + }, [extraQueries]); return { isCloneMode, isAssociationVersionMode, versionId, - versionName + versionName, + isRollbackMode, + rollbackWorkflowId }; }; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Create/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Create/index.tsx index 57bd38677..a85a40f56 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Create/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Create/index.tsx @@ -16,7 +16,10 @@ import { useTranslation } from 'react-i18next'; import workflow from '@actiontech/shared/lib/api/sqle/service/workflow'; import { useCurrentProject } from '@actiontech/shared/lib/global'; import { ResponseCode } from '@actiontech/shared/lib/enum'; -import { ICreateWorkflowV2Params } from '@actiontech/shared/lib/api/sqle/service/workflow/index.d'; +import { + ICreateWorkflowV2Params, + ICreateRollbackWorkflowParams +} from '@actiontech/shared/lib/api/sqle/service/workflow/index.d'; import useCheckTaskAuditSqlCount from './hooks/useCheckTaskAuditSqlCount'; import { LazyLoadComponent } from '@actiontech/shared'; import { useSelector } from 'react-redux'; @@ -33,20 +36,26 @@ const CreateSqlExecWorkflow: React.FC = () => { const { updateTaskRecordCount, checkTaskCountIsEmpty } = useCheckTaskAuditSqlCount(); - const { isCloneMode, isAssociationVersionMode, versionId } = - useCreationMode(); + const { + isCloneMode, + isAssociationVersionMode, + versionId, + isRollbackMode, + rollbackWorkflowId + } = useCreationMode(); const sqlExecWorkflowReduxState = useSelector((state: IReduxState) => { return { clonedExecWorkflowSqlAuditInfo: state.sqlExecWorkflow.clonedExecWorkflowSqlAuditInfo, clonedExecWorkflowBaseInfo: - state.sqlExecWorkflow.clonedExecWorkflowBaseInfo + state.sqlExecWorkflow.clonedExecWorkflowBaseInfo, + workflowRollbackSqlIds: state.sqlExecWorkflow.workflowRollbackSqlIds }; }); useEffect(() => { - if (isCloneMode) { + if (isCloneMode || isRollbackMode) { baseInfoForm.setFieldsValue({ workflow_subject: sqlExecWorkflowReduxState.clonedExecWorkflowBaseInfo @@ -152,11 +161,30 @@ const CreateSqlExecWorkflow: React.FC = () => { return; } - const createWorkflowParam: ICreateWorkflowV2Params = { + const commonParams = { task_ids: taskInfos.map((v) => v.task_id!), desc: baseInfo?.desc, workflow_subject: baseInfo?.workflow_subject, - project_name: projectName, + project_name: projectName + }; + + if (isRollbackMode) { + const params: ICreateRollbackWorkflowParams = { + ...commonParams, + rollback_sql_ids: + sqlExecWorkflowReduxState.workflowRollbackSqlIds ?? [], + workflow_id: rollbackWorkflowId ?? '' + }; + return workflow.CreateRollbackWorkflow(params).then((res) => { + if (res.data.code === ResponseCode.SUCCESS) { + goToCreateResultStep(); + createdWorkflowID.current = res.data.data?.workflow_id ?? ''; + } + }); + } + + const createWorkflowParam: ICreateWorkflowV2Params = { + ...commonParams, sql_version_id: isAssociationVersionMode ? Number(versionId) : undefined }; return workflow.createWorkflowV2(createWorkflowParam).then((res) => { @@ -174,7 +202,10 @@ const CreateSqlExecWorkflow: React.FC = () => { t, taskInfos, isAssociationVersionMode, - versionId + versionId, + isRollbackMode, + rollbackWorkflowId, + sqlExecWorkflowReduxState ]); usePrompt(t('execWorkflow.create.auditResult.leaveTip'), isAtAuditResultStep); diff --git a/packages/sqle/src/page/SqlExecWorkflow/Create/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Create/index.type.ts index 536238ab3..e7277e5c8 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Create/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Create/index.type.ts @@ -26,12 +26,14 @@ export type SqlStatementFields = Record< exec_mode: CreateAuditTasksGroupReqV1ExecModeEnum; file_sort_method: string; currentUploadType: AuditTaskResV1SqlSourceEnum; + backup?: boolean; }; export type CreateWorkflowDatabaseInfo = Array<{ key: string; instanceName?: string; schemaName?: string; + enableBackup?: boolean; }>; export type SqlAuditInfoFormFields = { @@ -60,6 +62,7 @@ export type DataSourceSchemaCollection = Record< ruleTemplate?: IRuleTemplateV2; testConnectResult?: IInstanceConnectionResV1; isSupportFileModeExecuteSql?: boolean; + enableBackup?: boolean; } >; From 12e866d609f3361249b34f2007a210549ded6232 Mon Sep 17 00:00:00 2001 From: zzyangh <799463087@qq.com> Date: Tue, 19 Nov 2024 14:22:41 +0800 Subject: [PATCH 03/20] [feature](SqlExecWorkflow): Add support for switching backup strategies[skip ci] --- .../Table/SwitchSqlBackupStrategyModal.tsx | 73 ++++++++++ .../Common/AuditResultList/Table/column.tsx | 38 +++++- .../AuditResultList/Table/index.data.ts | 49 +++++++ .../Common/AuditResultList/Table/index.tsx | 127 +++++++++++++----- .../AuditResultList/Table/index.type.ts | 1 + .../Common/AuditResultList/Table/style.ts | 20 +++ .../Common/AuditResultList/index.tsx | 19 ++- .../Common/AuditResultList/index.type.ts | 2 + .../Common/AuditResultList/style.ts | 6 + .../components/index.type.ts | 5 + .../BatchSwitchBackupStrategyModal/index.tsx | 82 +++++++++++ .../components/AuditResultStep/index.tsx | 27 ++++ 12 files changed, 416 insertions(+), 33 deletions(-) create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/SwitchSqlBackupStrategyModal.tsx create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.data.ts create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/BatchSwitchBackupStrategyModal/index.tsx diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/SwitchSqlBackupStrategyModal.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/SwitchSqlBackupStrategyModal.tsx new file mode 100644 index 000000000..4185b71d0 --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/SwitchSqlBackupStrategyModal.tsx @@ -0,0 +1,73 @@ +import { BasicModal, BasicButton, BasicSelect } from '@actiontech/shared'; +import { Form, message } from 'antd'; +import { useTranslation } from 'react-i18next'; +import workflow from '@actiontech/shared/lib/api/sqle/service/workflow'; +import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { UpdateSqlBackupStrategyReqStrategyEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum'; +import { BackupStrategyOptions } from './index.data'; + +const SwitchSqlBackupStrategyModal: React.FC<{ + sqlID?: number; + open: boolean; + onCancel: () => void; + taskID?: string; + refresh: () => void; +}> = ({ open, onCancel, taskID, sqlID, refresh }) => { + const { t } = useTranslation(); + + const [messageApi, contextHolder] = message.useMessage(); + + const [form] = Form.useForm<{ + strategy: UpdateSqlBackupStrategyReqStrategyEnum; + }>(); + + const onSubmit = async () => { + const values = await form.validateFields(); + workflow + .UpdateSqlBackupStrategyV1({ + task_id: taskID ?? '', + sql_id: `${sqlID}`, + strategy: values.strategy + }) + .then((res) => { + if (res.data.code === ResponseCode.SUCCESS) { + messageApi.success( + t('execWorkflow.create.auditResult.editBackupStrategySuccessTips') + ); + refresh(); + onClose(); + } + }); + }; + + const onClose = () => { + form.resetFields(); + onCancel(); + }; + + return ( + + {t('common.cancel')} + + {t('common.ok')} + + + } + centered + closable={false} + > + {contextHolder} +
+ + + +
+
+ ); +}; + +export default SwitchSqlBackupStrategyModal; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx index a95b0c000..8cb19e2d8 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx @@ -4,10 +4,15 @@ import { EditText, SQLRenderer } from '@actiontech/shared'; import { tooltipsCommonProps } from '@actiontech/shared/lib/components/BasicToolTips'; import { t } from '../../../../../locale'; import ResultIconRender from '../../../../../components/AuditResultMessage/ResultIconRender'; +import { BasicToolTips, BasicTag } from '@actiontech/shared'; +import { AuditResultBackupPolicyColumnStyleWrapper } from './style'; +import { EditFilled } from '@actiontech/icons'; +import { BackupStrategyDictionary } from './index.data'; export const AuditResultForCreateWorkflowColumn = ( updateSqlDescribe: (sqlNum: number, sqlDescribe: string) => void, - onClickAuditResult: (record: IAuditTaskSQLResV2) => void + onClickAuditResult: (record: IAuditTaskSQLResV2) => void, + onSwitchSqlBackupPolicy: (sqlID?: number) => void ): ActiontechTableColumn => { return [ { @@ -48,6 +53,37 @@ export const AuditResultForCreateWorkflowColumn = ( ); } }, + // #if [ee] + { + dataIndex: 'backup_strategy', + title: () => ( + + {t('execWorkflow.audit.table.backupPolicy')} + + ), + className: 'backup-policy-column', + render: (backupStrategy, record) => { + if (!backupStrategy) { + return '-'; + } + return ( + + {BackupStrategyDictionary[backupStrategy]} + { + onSwitchSqlBackupPolicy(record.exec_sql_id); + }} + /> + + ); + } + }, + // #endif { dataIndex: 'description', title: () => t('execWorkflow.audit.table.describe'), diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.data.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.data.ts new file mode 100644 index 000000000..295da5c76 --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.data.ts @@ -0,0 +1,49 @@ +import { UpdateSqlBackupStrategyReqStrategyEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum'; +import { t } from '../../../../../locale/index'; + +export const BackupStrategyDictionary: { + [key in UpdateSqlBackupStrategyReqStrategyEnum]: string; +} = { + [UpdateSqlBackupStrategyReqStrategyEnum.reverse_sql]: t( + 'execWorkflow.create.backupStrategy.reverseSql' + ), + [UpdateSqlBackupStrategyReqStrategyEnum.origin_row]: t( + 'execWorkflow.create.backupStrategy.originRow' + ), + [UpdateSqlBackupStrategyReqStrategyEnum.manual]: t( + 'execWorkflow.create.backupStrategy.manual' + ), + [UpdateSqlBackupStrategyReqStrategyEnum.none]: t( + 'execWorkflow.create.backupStrategy.none' + ) +}; + +export const BackupStrategyOptions: Array<{ + label: string; + value: UpdateSqlBackupStrategyReqStrategyEnum; +}> = [ + { + label: + BackupStrategyDictionary[ + UpdateSqlBackupStrategyReqStrategyEnum.reverse_sql + ], + value: UpdateSqlBackupStrategyReqStrategyEnum.reverse_sql + }, + { + label: + BackupStrategyDictionary[ + UpdateSqlBackupStrategyReqStrategyEnum.origin_row + ], + value: UpdateSqlBackupStrategyReqStrategyEnum.origin_row + }, + { + label: + BackupStrategyDictionary[UpdateSqlBackupStrategyReqStrategyEnum.manual], + value: UpdateSqlBackupStrategyReqStrategyEnum.manual + }, + { + label: + BackupStrategyDictionary[UpdateSqlBackupStrategyReqStrategyEnum.none], + value: UpdateSqlBackupStrategyReqStrategyEnum.none + } +]; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.tsx index 7ef4b0d90..1afc8cdfb 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.tsx @@ -17,6 +17,10 @@ import { AuditResultForCreateWorkflowActions } from './actions'; import { usePermission } from '@actiontech/shared/lib/global'; import { parse2ReactRouterPath } from '@actiontech/shared/lib/components/TypedRouter/utils'; import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import SwitchSqlBackupStrategyModal from './SwitchSqlBackupStrategyModal'; +import { EmptyBox } from '@actiontech/shared'; +import EventEmitter from '../../../../../utils/EventEmitter'; +import EmitterKey from '../../../../../data/EmitterKey'; const AuditResultTable: React.FC = ({ noDuplicate, @@ -24,7 +28,8 @@ const AuditResultTable: React.FC = ({ auditLevelFilterValue, projectID, updateTaskRecordCount, - dbType + dbType, + allowSwitchBackupPolicy = false }) => { const [currentAuditResultRecord, setCurrentAuditResultRecord] = useState(); @@ -32,6 +37,8 @@ const AuditResultTable: React.FC = ({ auditResultDrawerVisibility, { setFalse: closeAuditResultDrawer, setTrue: openAuditResultDrawer } ] = useBoolean(); + const [execSqlID, setExecSqlID] = useState(); + const { pagination, tableChange, setPagination } = useTableRequestParams(); const { requestErrorMessage, handleTableRequestError } = useTableRequestError(); @@ -41,6 +48,14 @@ const AuditResultTable: React.FC = ({ const { openCreateWhitelistModal, updateSelectWhitelistRecord } = useWhitelistRedux(); + const [ + switchBackupPolicyOpen, + { + setTrue: openSwitchBackupPolicyModal, + setFalse: closeSwitchBackupPolicyModal + } + ] = useBoolean(); + const handleClickAnalyze = useCallback( (sqlNum?: number) => { if (typeof sqlNum === 'undefined') { @@ -55,31 +70,6 @@ const AuditResultTable: React.FC = ({ [projectID, taskID] ); const updateSqlDescribeProtect = useRef(false); - const updateSqlDescribe = (sqlNum: number, sqlDescribe: string) => { - if (updateSqlDescribeProtect.current) { - return; - } - updateSqlDescribeProtect.current = true; - task - .updateAuditTaskSQLsV1({ - number: `${sqlNum}`, - description: sqlDescribe, - task_id: taskID! - }) - .then((res) => { - if (res.data.code === ResponseCode.SUCCESS) { - refresh(); - } - }) - .finally(() => { - updateSqlDescribeProtect.current = false; - }); - }; - - const onClickAuditResult = (record: IAuditTaskSQLResV2) => { - openAuditResultDrawer(); - setCurrentAuditResultRecord(record); - }; const { data, loading, refresh } = useRequest( () => @@ -106,6 +96,38 @@ const AuditResultTable: React.FC = ({ } ); + const updateSqlDescribe = useCallback( + (sqlNum: number, sqlDescribe: string) => { + if (updateSqlDescribeProtect.current) { + return; + } + updateSqlDescribeProtect.current = true; + task + .updateAuditTaskSQLsV1({ + number: `${sqlNum}`, + description: sqlDescribe, + task_id: taskID! + }) + .then((res) => { + if (res.data.code === ResponseCode.SUCCESS) { + refresh(); + } + }) + .finally(() => { + updateSqlDescribeProtect.current = false; + }); + }, + [refresh, taskID] + ); + + const onClickAuditResult = useCallback( + (record: IAuditTaskSQLResV2) => { + openAuditResultDrawer(); + setCurrentAuditResultRecord(record); + }, + [openAuditResultDrawer] + ); + // @feature: useTableRequestParams 整合自定义filter info useEffect(() => { setPagination({ @@ -131,15 +153,49 @@ const AuditResultTable: React.FC = ({ ); }, [parse2TableActionPermissions, handleClickAnalyze, onCreateWhitelist]); + const onSwitchSqlBackupPolicy = useCallback( + (sqlId?: number) => { + openSwitchBackupPolicyModal(); + setExecSqlID(sqlId); + }, + [openSwitchBackupPolicyModal] + ); + + const columns = useMemo(() => { + const tableColumns = AuditResultForCreateWorkflowColumn( + updateSqlDescribe, + onClickAuditResult, + onSwitchSqlBackupPolicy + ); + // #if [ee] + if (!allowSwitchBackupPolicy) { + return tableColumns.filter((v) => v.dataIndex !== 'backup_strategy'); + } + // #endif + return tableColumns; + }, [ + onSwitchSqlBackupPolicy, + updateSqlDescribe, + onClickAuditResult, + allowSwitchBackupPolicy + ]); + + useEffect(() => { + if (allowSwitchBackupPolicy) { + const { unsubscribe } = EventEmitter.subscribe( + EmitterKey.Refresh_Sql_Exec_workflow_Audit_Result_List, + refresh + ); + return unsubscribe; + } + }, [allowSwitchBackupPolicy, refresh]); + return ( <> = ({ clickAnalyze={handleClickAnalyze} /> + {/* #if [ee] */} + + + + {/* #endif */} ); }; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.type.ts index 2f2d06a4a..0be296324 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.type.ts @@ -8,6 +8,7 @@ export type AuditResultTableProps = { projectID: string; updateTaskRecordCount?: (taskId: string, sqlNumber: number) => void; dbType?: string; + allowSwitchBackupPolicy?: boolean; }; export type AuditResultDrawerProps = { diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/style.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/style.ts index 6e24d22e9..35f854822 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/style.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/style.ts @@ -1,4 +1,5 @@ import { styled } from '@mui/material/styles'; +import { Space } from 'antd'; export const AuditResultDrawerTitleStyleWrapper = styled(`div`)` display: flex; @@ -14,3 +15,22 @@ export const AuditResultDrawerTitleStyleWrapper = styled(`div`)` line-height: 21px; } `; + +export const AuditResultBackupPolicyColumnStyleWrapper = styled(Space)` + & .ant-space-item { + display: flex; + align-items: center; + } + + .backup-policy-editor { + cursor: pointer; + color: ${({ theme }) => theme.sharedTheme.uiToken.colorPrimary}; + } +`; + +export const AuditResultBackupPolicyPopoverContentStyleWrapper = styled(Space)` + & .ant-space-item:last-of-type { + display: flex; + justify-content: end; + } +`; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/index.tsx index 3f5b8168e..6e5aa03d8 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/index.tsx @@ -1,4 +1,4 @@ -import { BasicSegmented, EmptyBox } from '@actiontech/shared'; +import { BasicSegmented, EmptyBox, BasicButton } from '@actiontech/shared'; import { SegmentedRowStyleWrapper } from '@actiontech/shared/lib/styleWrapper/element'; import { Divider, Space } from 'antd'; import { useTranslation } from 'react-i18next'; @@ -22,7 +22,9 @@ import { const AuditResultList: React.FC = ({ tasks, updateTaskRecordCount, - showTaskTab = true + showTaskTab = true, + allowSwitchBackupPolicy = false, + onBatchSwitchBackupPolicy }) => { const { t } = useTranslation(); const { projectID } = useCurrentProject(); @@ -86,6 +88,18 @@ const AuditResultList: React.FC = ({ )} + {/* #if [ee] */} + + { + onBatchSwitchBackupPolicy?.(currentTaskID); + }} + > + {t('execWorkflow.create.auditResult.switchDatabaseBackupPolicy')} + + + + {/* #endif */} { @@ -125,6 +139,7 @@ const AuditResultList: React.FC = ({ projectID={projectID} updateTaskRecordCount={updateTaskRecordCount} dbType={currentTask?.instance_db_type} + allowSwitchBackupPolicy={allowSwitchBackupPolicy} /> ); diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/index.type.ts index bedf27eb8..bd7dcfa8f 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/index.type.ts @@ -4,4 +4,6 @@ export type AuditResultListProps = { tasks: IAuditTaskResV1[]; updateTaskRecordCount?: (taskId: string, sqlNumber: number) => void; showTaskTab?: boolean; + allowSwitchBackupPolicy?: boolean; + onBatchSwitchBackupPolicy?: (currentTaskID?: string) => void; }; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/style.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/style.ts index 049d34036..225147123 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/style.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/style.ts @@ -11,6 +11,12 @@ export const AuditResultForCreateWorkflowStyleWrapper = styled('section')` cursor: pointer; } + .backup-policy-column { + .ant-tag { + width: max-content; + } + } + .instance-segmented-label { display: flex; align-items: center; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts index 6e54b6839..166e4d9ec 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts @@ -22,3 +22,8 @@ export type SqlFormatterAndSubmitterProps = { | 'databaseInfo' | 'isSameSqlForAll' >; + +export type SqlBackupSwitcherProps = Pick< + SqlStatementFormItemProps, + 'fieldPrefixPath' | 'databaseInfo' +>; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/BatchSwitchBackupStrategyModal/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/BatchSwitchBackupStrategyModal/index.tsx new file mode 100644 index 000000000..13002ba17 --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/BatchSwitchBackupStrategyModal/index.tsx @@ -0,0 +1,82 @@ +import { BasicModal, BasicButton, BasicSelect } from '@actiontech/shared'; +import { Space, Form, Typography, message } from 'antd'; +import { useTranslation } from 'react-i18next'; +import workflow from '@actiontech/shared/lib/api/sqle/service/workflow'; +import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { UpdateTaskBackupStrategyReqStrategyEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum'; +import { BackupStrategyOptions } from '../../../../Common/AuditResultList/Table/index.data'; +import EventEmitter from '../../../../../../utils/EventEmitter'; +import EmitterKey from '../../../../../../data/EmitterKey'; + +const BatchSwitchBackupStrategyModal: React.FC<{ + taskID?: string; + open: boolean; + onCancel: () => void; +}> = ({ taskID, open, onCancel }) => { + const { t } = useTranslation(); + + const [messageApi, contextHolder] = message.useMessage(); + + const [form] = Form.useForm<{ + strategy: UpdateTaskBackupStrategyReqStrategyEnum; + }>(); + + const onSubmit = async () => { + const values = await form.validateFields(); + onClose(); + workflow + .UpdateTaskBackupStrategyV1({ + task_id: taskID ?? '', + strategy: values.strategy + }) + .then((res) => { + if (res.data.code === ResponseCode.SUCCESS) { + messageApi.success( + t( + 'execWorkflow.create.auditResult.switchDatabaseBackupPolicySuccessTips' + ) + ); + EventEmitter.emit( + EmitterKey.Refresh_Sql_Exec_workflow_Audit_Result_List + ); + onClose(); + } + }); + }; + + const onClose = () => { + form.resetFields(); + onCancel(); + }; + + return ( + + {t('common.cancel')} + + {t('common.ok')} + + + } + centered + closable={false} + > + {contextHolder} + + + {t('execWorkflow.create.auditResult.switchDatabaseBackupPolicyTips')} + +
+ + + +
+
+
+ ); +}; + +export default BatchSwitchBackupStrategyModal; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/index.tsx index 071a42708..ea65d987b 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/index.tsx @@ -8,6 +8,8 @@ import { useBoolean } from 'ahooks'; import AuditResultList from '../../../Common/AuditResultList'; import UpdateFormDrawer from './UpdateFormDrawer'; import SubmitWorkflowButton from '../../../Common/SubmitWorkflowButton'; +import BatchSwitchBackupStrategyModal from './BatchSwitchBackupStrategyModal'; +import { useState } from 'react'; const AuditResultStep: React.FC = ({ tasks, @@ -31,6 +33,16 @@ const AuditResultStep: React.FC = ({ } ] = useBoolean(false); + const [ + switchBackupPolicyOpen, + { + setTrue: openSwitchBackupPolicyModal, + setFalse: closeSwitchBackupPolicyModal + } + ] = useBoolean(); + + const [taskID, setTaskID] = useState(); + const internalCreateWorkflow = () => { startCreate(); @@ -39,6 +51,11 @@ const AuditResultStep: React.FC = ({ }); }; + const onBatchSwitchBackupPolicy = (currentTaskID?: string) => { + openSwitchBackupPolicyModal(); + setTaskID(currentTaskID); + }; + return ( <> = ({ = ({ auditAction={auditAction} {...sharedStepDetail} /> + + {/* #if [ee] */} + + {/* #endif */} ); }; From c113f0c36184a6f787f9b0477329dfabb0d32519 Mon Sep 17 00:00:00 2001 From: zzyangh <799463087@qq.com> Date: Tue, 19 Nov 2024 15:22:02 +0800 Subject: [PATCH 04/20] [fix]: Code optimization[skip ci] --- .../sqle/src/locale/zh-CN/execWorkflow.ts | 1 + .../Common/AuditResultList/Table/column.tsx | 4 ++- .../Common/AuditResultList/Table/index.tsx | 9 ++++-- .../components/SqlBackupSwitcher.tsx | 30 +++++++++++-------- .../components/SwitchField.tsx | 7 ++--- .../components/index.type.ts | 6 ++++ 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/packages/sqle/src/locale/zh-CN/execWorkflow.ts b/packages/sqle/src/locale/zh-CN/execWorkflow.ts index d44ceebb5..7825dc4e5 100644 --- a/packages/sqle/src/locale/zh-CN/execWorkflow.ts +++ b/packages/sqle/src/locale/zh-CN/execWorkflow.ts @@ -106,6 +106,7 @@ export default { executeFileMode: '文件模式', selectFileSortMethod: '选择文件排序方式', switchSqlBackup: '是否选择开启备份', + switchSqlBackupTips: '开启后,数据源上创建的工单将默认开启备份能力', cancelSwitchSqlBackupTips: '当前应用的数据源已开启备份需求,是否确认关闭备份?', cancelSwitchSqlBackupTipsWithInstanceName: diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx index 8cb19e2d8..8a25c6bf0 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx @@ -9,6 +9,8 @@ import { AuditResultBackupPolicyColumnStyleWrapper } from './style'; import { EditFilled } from '@actiontech/icons'; import { BackupStrategyDictionary } from './index.data'; +export const BACKUP_STRATEGY_DATA_INDEX = 'backup_strategy'; + export const AuditResultForCreateWorkflowColumn = ( updateSqlDescribe: (sqlNum: number, sqlDescribe: string) => void, onClickAuditResult: (record: IAuditTaskSQLResV2) => void, @@ -55,7 +57,7 @@ export const AuditResultForCreateWorkflowColumn = ( }, // #if [ee] { - dataIndex: 'backup_strategy', + dataIndex: BACKUP_STRATEGY_DATA_INDEX, title: () => ( = ({ ); // #if [ee] if (!allowSwitchBackupPolicy) { - return tableColumns.filter((v) => v.dataIndex !== 'backup_strategy'); + return tableColumns.filter( + (v) => v.dataIndex !== BACKUP_STRATEGY_DATA_INDEX + ); } // #endif return tableColumns; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx index 9608bc0e4..eb33f13c2 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx @@ -1,4 +1,7 @@ -import { FormItemLabel } from '@actiontech/shared/lib/components/FormCom'; +import { + FormItemLabel, + CustomLabelContent +} from '@actiontech/shared/lib/components/FormCom'; import { useTranslation } from 'react-i18next'; import { EmptyBox } from '@actiontech/shared'; import { Form } from 'antd'; @@ -23,7 +26,7 @@ const SqlBackupSwitcher: React.FC = ({ ); const isSameSqlForAll = Form.useWatch('isSameSqlForAll', form); - const getInitValue = () => { + const getInstanceEnableBackup = () => { if (isSameSqlForAll) { return databaseInfo.some((item) => item.enableBackup); } @@ -34,15 +37,10 @@ const SqlBackupSwitcher: React.FC = ({ }; const enableBackupInstanceName = useMemo(() => { - let nameStr = ''; - databaseInfo.forEach((item, index) => { - if (item.enableBackup) { - nameStr += `${item.instanceName}${ - index === databaseInfo.length - 1 ? '' : ',' - }`; - } - }); - return nameStr; + return databaseInfo + .filter((i) => i.enableBackup) + .map((i) => i.instanceName) + .join(','); }, [databaseInfo]); return ( @@ -52,12 +50,18 @@ const SqlBackupSwitcher: React.FC = ({ } > + } labelCol={{ span: 22 }} wrapperCol={{ span: 2 }} name={[fieldPrefixPath, 'backup']} valuePropName="checked" - initialValue={getInitValue()} + initialValue={getInstanceEnableBackup()} > void; - title?: string; -}> = ({ checked, onChange }) => { +const SwitchField: React.FC = ({ checked, onChange }) => { const { t } = useTranslation(); const [ diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts index 166e4d9ec..8ed5b7d6a 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts @@ -27,3 +27,9 @@ export type SqlBackupSwitcherProps = Pick< SqlStatementFormItemProps, 'fieldPrefixPath' | 'databaseInfo' >; + +export type SwitcherField = { + checked?: boolean; + onChange?: (v: boolean) => void; + title?: string; +}; From 55933851a503fec88c34597ec7be7922387125ff Mon Sep 17 00:00:00 2001 From: zzyangh <799463087@qq.com> Date: Tue, 19 Nov 2024 16:31:50 +0800 Subject: [PATCH 05/20] [fix]: Code Optimization --- .../Table/SwitchSqlBackupStrategyModal.tsx | 11 ++++------- .../Common/AuditResultList/Table/column.tsx | 10 +++++----- .../Common/AuditResultList/Table/index.tsx | 18 ++++-------------- .../Common/AuditResultList/Table/index.type.ts | 8 ++++++++ .../components/SwitchField.tsx | 4 ++-- .../components/index.type.ts | 2 +- .../BatchSwitchBackupStrategyModal/index.tsx | 8 ++++++-- 7 files changed, 30 insertions(+), 31 deletions(-) diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/SwitchSqlBackupStrategyModal.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/SwitchSqlBackupStrategyModal.tsx index 4185b71d0..8d63f987f 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/SwitchSqlBackupStrategyModal.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/SwitchSqlBackupStrategyModal.tsx @@ -5,14 +5,11 @@ import workflow from '@actiontech/shared/lib/api/sqle/service/workflow'; import { ResponseCode } from '@actiontech/shared/lib/enum'; import { UpdateSqlBackupStrategyReqStrategyEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum'; import { BackupStrategyOptions } from './index.data'; +import { SwitchSqlBackupStrategyModalProps } from './index.type'; -const SwitchSqlBackupStrategyModal: React.FC<{ - sqlID?: number; - open: boolean; - onCancel: () => void; - taskID?: string; - refresh: () => void; -}> = ({ open, onCancel, taskID, sqlID, refresh }) => { +const SwitchSqlBackupStrategyModal: React.FC< + SwitchSqlBackupStrategyModalProps +> = ({ open, onCancel, taskID, sqlID, refresh }) => { const { t } = useTranslation(); const [messageApi, contextHolder] = message.useMessage(); diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx index 8a25c6bf0..b58c31eb1 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/column.tsx @@ -9,12 +9,11 @@ import { AuditResultBackupPolicyColumnStyleWrapper } from './style'; import { EditFilled } from '@actiontech/icons'; import { BackupStrategyDictionary } from './index.data'; -export const BACKUP_STRATEGY_DATA_INDEX = 'backup_strategy'; - export const AuditResultForCreateWorkflowColumn = ( updateSqlDescribe: (sqlNum: number, sqlDescribe: string) => void, onClickAuditResult: (record: IAuditTaskSQLResV2) => void, - onSwitchSqlBackupPolicy: (sqlID?: number) => void + onSwitchSqlBackupPolicy: (sqlID?: number) => void, + showBackupStrategy?: boolean ): ActiontechTableColumn => { return [ { @@ -57,7 +56,7 @@ export const AuditResultForCreateWorkflowColumn = ( }, // #if [ee] { - dataIndex: BACKUP_STRATEGY_DATA_INDEX, + dataIndex: 'backup_strategy', title: () => ( ); - } + }, + show: showBackupStrategy }, // #endif { diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.tsx index 714ddc45c..aea09a3ca 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.tsx @@ -9,10 +9,7 @@ import { useTableRequestParams } from '@actiontech/shared/lib/components/ActiontechTable'; import { AuditResultTableProps } from './index.type'; -import { - AuditResultForCreateWorkflowColumn, - BACKUP_STRATEGY_DATA_INDEX -} from './column'; +import { AuditResultForCreateWorkflowColumn } from './column'; import AuditResultDrawer from './AuditResultDrawer'; import useWhitelistRedux from '../../../../Whitelist/hooks/useWhitelistRedux'; import AddWhitelistModal from '../../../../Whitelist/Drawer/AddWhitelist'; @@ -165,19 +162,12 @@ const AuditResultTable: React.FC = ({ ); const columns = useMemo(() => { - const tableColumns = AuditResultForCreateWorkflowColumn( + return AuditResultForCreateWorkflowColumn( updateSqlDescribe, onClickAuditResult, - onSwitchSqlBackupPolicy + onSwitchSqlBackupPolicy, + allowSwitchBackupPolicy ); - // #if [ee] - if (!allowSwitchBackupPolicy) { - return tableColumns.filter( - (v) => v.dataIndex !== BACKUP_STRATEGY_DATA_INDEX - ); - } - // #endif - return tableColumns; }, [ onSwitchSqlBackupPolicy, updateSqlDescribe, diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.type.ts index 0be296324..27f7f017a 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/AuditResultList/Table/index.type.ts @@ -18,3 +18,11 @@ export type AuditResultDrawerProps = { dbType?: string; clickAnalyze: (sqlNum?: number) => void; }; + +export type SwitchSqlBackupStrategyModalProps = { + sqlID?: number; + open: boolean; + onCancel: () => void; + taskID?: string; + refresh: () => void; +}; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx index 09561ffd9..fa159e314 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx @@ -2,9 +2,9 @@ import { BasicSwitch } from '@actiontech/shared'; import { Popconfirm } from 'antd'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'ahooks'; -import { SwitcherField } from './index.type'; +import { SwitcherFieldProps } from './index.type'; -const SwitchField: React.FC = ({ checked, onChange }) => { +const SwitchField: React.FC = ({ checked, onChange }) => { const { t } = useTranslation(); const [ diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts index 8ed5b7d6a..959830945 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts @@ -28,7 +28,7 @@ export type SqlBackupSwitcherProps = Pick< 'fieldPrefixPath' | 'databaseInfo' >; -export type SwitcherField = { +export type SwitcherFieldProps = { checked?: boolean; onChange?: (v: boolean) => void; title?: string; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/BatchSwitchBackupStrategyModal/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/BatchSwitchBackupStrategyModal/index.tsx index 13002ba17..d69df1576 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/BatchSwitchBackupStrategyModal/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Create/components/AuditResultStep/BatchSwitchBackupStrategyModal/index.tsx @@ -8,11 +8,15 @@ import { BackupStrategyOptions } from '../../../../Common/AuditResultList/Table/ import EventEmitter from '../../../../../../utils/EventEmitter'; import EmitterKey from '../../../../../../data/EmitterKey'; -const BatchSwitchBackupStrategyModal: React.FC<{ +type BatchSwitchBackupStrategyModalProps = { taskID?: string; open: boolean; onCancel: () => void; -}> = ({ taskID, open, onCancel }) => { +}; + +const BatchSwitchBackupStrategyModal: React.FC< + BatchSwitchBackupStrategyModalProps +> = ({ taskID, open, onCancel }) => { const { t } = useTranslation(); const [messageApi, contextHolder] = message.useMessage(); From 24ff25b3d03943afa1acb3d37b8572a55c76d0a6 Mon Sep 17 00:00:00 2001 From: zzyangh <799463087@qq.com> Date: Tue, 19 Nov 2024 16:33:15 +0800 Subject: [PATCH 06/20] [fix](ActiontechTable): Filter columns by show attribute[skip ci] --- .../lib/components/ActiontechTable/Table.tsx | 4 +- .../__snapshots__/index.test.tsx.snap | 92 +++++++++++++++++++ .../components/ActiontechTable/index.test.tsx | 25 +++++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/packages/shared/lib/components/ActiontechTable/Table.tsx b/packages/shared/lib/components/ActiontechTable/Table.tsx index ad43b3af8..e58b4a22b 100644 --- a/packages/shared/lib/components/ActiontechTable/Table.tsx +++ b/packages/shared/lib/components/ActiontechTable/Table.tsx @@ -37,8 +37,10 @@ const ActiontechTable = < const mergerColumns = useMemo(() => { const operatorColumn = renderActionInTable(props.actions); + const extractedColumns = columns.filter((v) => v.show !== false); + return ( - operatorColumn ? [...columns, operatorColumn] : columns + operatorColumn ? [...extractedColumns, operatorColumn] : extractedColumns ) as ActiontechTableColumn; }, [columns, props.actions, renderActionInTable]); diff --git a/packages/shared/lib/components/ActiontechTable/__snapshots__/index.test.tsx.snap b/packages/shared/lib/components/ActiontechTable/__snapshots__/index.test.tsx.snap index 59f82dd90..59bcdd38b 100644 --- a/packages/shared/lib/components/ActiontechTable/__snapshots__/index.test.tsx.snap +++ b/packages/shared/lib/components/ActiontechTable/__snapshots__/index.test.tsx.snap @@ -1420,6 +1420,98 @@ exports[`lib/ActiontechTable -composite table render table with filter 1`] = ` `; +exports[`lib/ActiontechTable -normal table render filter columns by show attribute 1`] = ` + +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ 名称 +
+
+
+
+
+
+
+
+
+
+
+ +`; + exports[`lib/ActiontechTable -normal table render normal table is empty 1`] = `
diff --git a/packages/shared/lib/components/ActiontechTable/index.test.tsx b/packages/shared/lib/components/ActiontechTable/index.test.tsx index e86ed9d6d..7287b3f49 100644 --- a/packages/shared/lib/components/ActiontechTable/index.test.tsx +++ b/packages/shared/lib/components/ActiontechTable/index.test.tsx @@ -97,6 +97,31 @@ describe('lib/ActiontechTable', () => { expect(onChangeFn).toHaveBeenCalledTimes(1); expect(baseElement).toMatchSnapshot(); }); + + it('render filter columns by show attribute', async () => { + const { baseElement } = customRender({ + pagination: false, + dataSource: [ + { name: 'a', age: 11 }, + { name: 'b', age: 18 }, + { name: 'c', age: 19 } + ], + rowKey: 'name', + columns: [ + { + dataIndex: 'a', + title: '名称' + }, + { + dataIndex: 'b', + title: '年龄', + show: false + } + ] + }); + expect(baseElement).toMatchSnapshot(); + expect(screen.queryByText('年龄')).not.toBeInTheDocument(); + }); }); describe('-composite table', () => { From 1838140d6fdf72fcf9e98448913c67636ebea0f5 Mon Sep 17 00:00:00 2001 From: zzyangh <799463087@qq.com> Date: Wed, 20 Nov 2024 18:20:39 +0800 Subject: [PATCH 07/20] [feature](SqlExecWorkflow): Backup strategy display and rollback workflow[skip ci] --- .../base/src/locale/zh-CN/dmsDataSource.ts | 5 +- .../usePermission/permissionManifest.ts | 10 + .../lib/global/usePermission/permissions.ts | 4 +- .../src/hooks/useStaticStatus/index.data.ts | 4 +- .../sqle/src/locale/zh-CN/execWorkflow.ts | 5 +- .../Common/DownloadRecord/index.tsx | 26 +- .../Common/DownloadRecord/index.type.ts | 1 + .../components/SqlBackupSwitcher.tsx | 9 +- .../components/SwitchField.tsx | 9 +- .../components/index.type.ts | 2 +- .../SqlStatementFormItem/index.tsx | 1 + .../hooks/useRenderDatabaseSelectionItems.tsx | 4 +- .../Create/hooks/useAuditWorkflow.tsx | 6 +- .../Common/ResultCard/SqlMode.tsx | 231 +++++++------ .../ResultCard/components/ExecStatusTag.tsx | 7 +- .../Common/ResultCard/index.data.ts | 7 + .../Common/ResultCard/index.type.ts | 1 + .../TaskResultList/Common/ResultCard/style.ts | 33 ++ .../PaginationList/SqlExecuteMode/index.tsx | 4 +- .../TaskResultList/index.type.ts | 1 + .../components/AuditExecResultPanel/index.tsx | 7 +- .../components/PageHeaderExtra/action.tsx | 34 ++ .../hooks/useWorkflowDetailAction.tsx | 46 ++- .../components/PageHeaderExtra/index.tsx | 11 +- .../components/PageHeaderExtra/index.type.ts | 2 + .../components/SqlRollback/TableTransfer.tsx | 67 ++++ .../Detail/components/SqlRollback/columns.tsx | 124 +++++++ .../components/SqlRollback/index.data.ts | 63 ++++ .../Detail/components/SqlRollback/index.tsx | 327 ++++++++++++++++++ .../components/SqlRollback/index.type.ts | 37 ++ .../Detail/components/SqlRollback/style.ts | 51 +++ .../Detail/hooks/useCloneExecWorkflowInfo.ts | 18 +- .../src/page/SqlExecWorkflow/Detail/index.tsx | 16 +- .../sqle/src/store/sqlExecWorkflow/index.ts | 17 +- 34 files changed, 1052 insertions(+), 138 deletions(-) create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/index.data.ts create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/TableTransfer.tsx create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/columns.tsx create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.data.ts create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.tsx create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.type.ts create mode 100644 packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/style.ts diff --git a/packages/base/src/locale/zh-CN/dmsDataSource.ts b/packages/base/src/locale/zh-CN/dmsDataSource.ts index c23a69ebf..3e45a1c69 100644 --- a/packages/base/src/locale/zh-CN/dmsDataSource.ts +++ b/packages/base/src/locale/zh-CN/dmsDataSource.ts @@ -72,7 +72,10 @@ export default { dataMaskConfig: '数据脱敏配置', dataMaskConfigLabel: 'SQL工作台是否开启脱敏配置', dataMaskConfigTips: '开启后,将对SQL工作台的查询结果进行脱敏', - checkDataMaskButton: '查看脱敏规则' + checkDataMaskButton: '查看脱敏规则', + sqlBackupConfiguration: 'SQL备份配置', + enableDataSourceBackup: '是否开启数据源上的SQL备份能力', + enableDataSourceBackupTips: '是否开启数据源上的SQL备份能力' }, testConnectModal: { diff --git a/packages/shared/lib/global/usePermission/permissionManifest.ts b/packages/shared/lib/global/usePermission/permissionManifest.ts index d7811df62..3c33bcaef 100644 --- a/packages/shared/lib/global/usePermission/permissionManifest.ts +++ b/packages/shared/lib/global/usePermission/permissionManifest.ts @@ -563,6 +563,16 @@ export const PERMISSION_MANIFEST: Record< type: 'action', role: [SystemRole.admin, SystemRole.globalManager] }, + [PERMISSIONS.ACTIONS.SQLE.SQL_EXEC_WORKFLOW.RETRY]: { + id: PERMISSIONS.ACTIONS.SQLE.SQL_EXEC_WORKFLOW.RETRY, + type: 'action', + projectArchived: false + }, + [PERMISSIONS.ACTIONS.SQLE.SQL_EXEC_WORKFLOW.ROLLBACK]: { + id: PERMISSIONS.ACTIONS.SQLE.SQL_EXEC_WORKFLOW.ROLLBACK, + type: 'action', + projectArchived: false + }, // SQL 管控 [PERMISSIONS.ACTIONS.SQLE.SQL_MANAGEMENT.ASSIGNMENT]: { diff --git a/packages/shared/lib/global/usePermission/permissions.ts b/packages/shared/lib/global/usePermission/permissions.ts index 0bb86ccd1..75e5f2507 100644 --- a/packages/shared/lib/global/usePermission/permissions.ts +++ b/packages/shared/lib/global/usePermission/permissions.ts @@ -151,7 +151,9 @@ export const PERMISSIONS = { SCHEDULE_TIME_EXEC_TASK: 'action:schedule_time_exec_task', CANCEL_SCHEDULE_TIME_EXEC_TASK: 'action:cancel_schedule_time_exec_task', CREATE_WHITE_LIST: 'action:workflow_sql_audit_result_create_white_list', - BATCH_CLOSE: 'action:batch_close_workflow' + BATCH_CLOSE: 'action:batch_close_workflow', + RETRY: 'action:retry_workflow', + ROLLBACK: 'action:rollback_workflow' }, SQL_MANAGEMENT: { ASSIGNMENT: 'action:sql_assignment', diff --git a/packages/sqle/src/hooks/useStaticStatus/index.data.ts b/packages/sqle/src/hooks/useStaticStatus/index.data.ts index 5df594a45..08811db6f 100644 --- a/packages/sqle/src/hooks/useStaticStatus/index.data.ts +++ b/packages/sqle/src/hooks/useStaticStatus/index.data.ts @@ -37,7 +37,9 @@ export const execStatusDictionary: StaticEnumDictionary = diff --git a/packages/sqle/src/locale/zh-CN/execWorkflow.ts b/packages/sqle/src/locale/zh-CN/execWorkflow.ts index 7825dc4e5..1dc5ae319 100644 --- a/packages/sqle/src/locale/zh-CN/execWorkflow.ts +++ b/packages/sqle/src/locale/zh-CN/execWorkflow.ts @@ -110,7 +110,7 @@ export default { cancelSwitchSqlBackupTips: '当前应用的数据源已开启备份需求,是否确认关闭备份?', cancelSwitchSqlBackupTipsWithInstanceName: - '{instanceName}已开启备份需求,是否确认关闭备份?' + '{{instanceName}}已开启备份需求,是否确认关闭备份?' }, tour: { modifyName: '修改工单名称', @@ -131,7 +131,8 @@ export default { switchDatabaseBackupPolicy: '切换数据源备份策略', switchDatabaseBackupPolicyTips: '统一变更当前数据源上SQL的备份回滚策略为', editBackupStrategy: '切换SQL备份回滚策略', - editBackupStrategySuccessTips: '切换SQL备份回滚策略成功' + editBackupStrategySuccessTips: '切换SQL备份回滚策略成功', + switchDatabaseBackupPolicySuccessTips: '切换数据源备份策略成功' }, backupStrategy: { reverseSql: '基于反向SQL回滚', diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/DownloadRecord/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/DownloadRecord/index.tsx index 9849f6bf6..fdbb00959 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/DownloadRecord/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/DownloadRecord/index.tsx @@ -13,14 +13,18 @@ import { DownArrowLineOutlined } from '@actiontech/icons'; import { CommonIconStyleWrapper } from '@actiontech/shared/lib/styleWrapper/element'; +import { useCurrentProject } from '@actiontech/shared/lib/global'; const DownloadRecord: React.FC = ({ noDuplicate, - taskId + taskId, + workflowId }) => { const { t } = useTranslation(); const [open, setOpen] = useState(false); + const { projectName } = useCurrentProject(); + const downloadSql = () => { task.downloadAuditTaskSQLFileV1( { @@ -42,6 +46,20 @@ const DownloadRecord: React.FC = ({ setOpen(false); }; + // #if [ee] + const downloadRollbackSql = () => { + task.downloadBackupFileV1( + { + task_id: taskId, + workflow_id: workflowId ?? '', + project_name: projectName + }, + { responseType: 'blob' } + ); + setOpen(false); + }; + // #endif + const renderDownloadDropdown = () => { return ( @@ -57,6 +75,12 @@ const DownloadRecord: React.FC = ({ {t('execWorkflow.audit.downloadSql')}
+ {/* #if [ee] */} +
+ + {t('execWorkflow.audit.downloadRollbackSql')} +
+ {/* #endif */} ); }; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/DownloadRecord/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/DownloadRecord/index.type.ts index f4dc049d1..c1add7071 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/DownloadRecord/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/DownloadRecord/index.type.ts @@ -1,4 +1,5 @@ export type DownloadRecordProps = { noDuplicate: boolean; taskId: string; + workflowId?: string; }; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx index eb33f13c2..42096207a 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SqlBackupSwitcher.tsx @@ -14,7 +14,8 @@ import SwitchField from './SwitchField'; const SqlBackupSwitcher: React.FC = ({ fieldPrefixPath, - databaseInfo + databaseInfo, + isSameSqlForAll }) => { const { t } = useTranslation(); @@ -24,8 +25,6 @@ const SqlBackupSwitcher: React.FC = ({ [fieldPrefixPath, 'exec_mode'], form ); - const isSameSqlForAll = Form.useWatch('isSameSqlForAll', form); - const getInstanceEnableBackup = () => { if (isSameSqlForAll) { return databaseInfo.some((item) => item.enableBackup); @@ -66,13 +65,13 @@ const SqlBackupSwitcher: React.FC = ({
diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx index fa159e314..bbb92923e 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/SwitchField.tsx @@ -4,7 +4,11 @@ import { useTranslation } from 'react-i18next'; import { useBoolean } from 'ahooks'; import { SwitcherFieldProps } from './index.type'; -const SwitchField: React.FC = ({ checked, onChange }) => { +const SwitchField: React.FC = ({ + checked, + onChange, + title +}) => { const { t } = useTranslation(); const [ @@ -14,7 +18,7 @@ const SwitchField: React.FC = ({ checked, onChange }) => { return ( = ({ checked, onChange }) => { > { if (!checked) { onChange?.(true); diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts index 959830945..fd5726e33 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/components/index.type.ts @@ -25,7 +25,7 @@ export type SqlFormatterAndSubmitterProps = { export type SqlBackupSwitcherProps = Pick< SqlStatementFormItemProps, - 'fieldPrefixPath' | 'databaseInfo' + 'fieldPrefixPath' | 'databaseInfo' | 'isSameSqlForAll' >; export type SwitcherFieldProps = { diff --git a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/index.tsx index fa5cee03e..58b471eb3 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Common/SqlStatementFormController/SqlStatementFormItem/index.tsx @@ -88,6 +88,7 @@ const SqlStatementFormItem: React.FC = ({ {/* #endif */} & { instanceList: IInstanceTipResV1[] }) => { +> & { instanceList?: IInstanceTipResV1[] }) => { const { t } = useTranslation(); const { projectName, projectID } = useCurrentProject(); const { sqleTheme } = useThemeStyleData(); @@ -118,7 +118,7 @@ const useRenderDatabaseSelectionItems = ({ testConnectResult: undefined, isSupportFileModeExecuteSql: true, enableBackup: - instanceList.find((i) => i.instance_name === instanceName) + instanceList?.find((i) => i.instance_name === instanceName) ?.enable_backup ?? false }); updateSchemaList(key, instanceName); diff --git a/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useAuditWorkflow.tsx b/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useAuditWorkflow.tsx index ed1f5e06a..4c2e08f3e 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useAuditWorkflow.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Create/hooks/useAuditWorkflow.tsx @@ -140,7 +140,9 @@ const useAuditWorkflow = () => { ) { const auditTaskPrams: IAuditTaskGroupIdV1Params = { task_group_id: taskGroupInfo.data.data?.task_group_id, + // #if [ee] enable_backup: sqlStatementInfo.backup, + // #endif ...getSqlSourceWithUploadType(sqlStatementInfo) }; const res = await task.auditTaskGroupIdV1(auditTaskPrams); @@ -192,9 +194,9 @@ const useAuditWorkflow = () => { ...getSqlSourceWithUploadType(sqlStatementInfo), exec_mode: sqlStatementInfo.exec_mode as unknown as CreateAuditTaskReqV1ExecModeEnum, - enable_backup: sqlStatementInfo.backup, // #if [ee] - file_order_method: sqlStatementInfo.file_sort_method + file_order_method: sqlStatementInfo.file_sort_method, + enable_backup: sqlStatementInfo.backup // #endif }; }); diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/SqlMode.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/SqlMode.tsx index 991b8cb96..6a16ab9f3 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/SqlMode.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/SqlMode.tsx @@ -4,13 +4,14 @@ import { BasicToolTips, Copy, EmptyBox, - SQLRenderer + SQLRenderer, + SegmentedTabs } from '@actiontech/shared'; import task from '@actiontech/shared/lib/api/sqle/service/task'; import { ResponseCode } from '@actiontech/shared/lib/enum'; import { useBoolean } from 'ahooks'; import { Divider, Space, Spin, message } from 'antd'; -import { useMemo } from 'react'; +import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { getAuditTaskSQLsV2FilterExecStatusEnum } from '@actiontech/shared/lib/api/sqle/service/task/index.enum'; import { SqlExecuteResultCardProps } from './index.type'; @@ -18,20 +19,15 @@ import ExecStatusTag from './components/ExecStatusTag'; import AuditResultTag from './components/AuditResultTag'; import AuditResultTree from './components/AuditResultTree'; import ResultDescribe from './components/ResultDescribe'; -import { - TaskResultSqlOptionsStyleWrapper, - TasksResultCardStyleWrapper -} from './style'; -import { TaskAuditResultTreeStyleWrapper } from './components/style'; -import { - ProfileSquareFilled, - DownOutlined, - EnvironmentFilled -} from '@actiontech/icons'; +import { TasksResultCardStyleWrapper } from './style'; +import { ProfileSquareFilled, EnvironmentFilled } from '@actiontech/icons'; import useThemeStyleData from '../../../../../../../../hooks/useThemeStyleData'; -import { CommonIconStyleWrapper } from '@actiontech/shared/lib/styleWrapper/element'; import { parse2ReactRouterPath } from '@actiontech/shared/lib/components/TypedRouter/utils'; import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import { TaskResultContentTypeEnum } from './index.data'; +import { BackupStrategyDictionary } from '../../../../../../Common/AuditResultList/Table/index.data'; +import { UpdateSqlBackupStrategyReqStrategyEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum'; +import { WarningFilled } from '@actiontech/icons'; const SqlMode: React.FC = ({ projectID, @@ -43,11 +39,13 @@ const SqlMode: React.FC = ({ const [messageApi, contextHolder] = message.useMessage(); - const [showExecSql, { setTrue, setFalse }] = useBoolean(true); - const { sqleTheme } = useThemeStyleData(); - const [loading, { set }] = useBoolean(); + const [loading, { setTrue: updateDescPending, setFalse: updateDescDone }] = + useBoolean(); + + const [currentContentKey, setCurrentContentKey] = + useState(TaskResultContentTypeEnum.exec_sql); const onCopyExecSql = () => { Copy.copyTextByTextarea(props.exec_sql ?? ''); @@ -67,7 +65,7 @@ const SqlMode: React.FC = ({ }; const updateSqlDescribe = (sqlDescribe: string) => { - set(true); + updateDescPending(); task .updateAuditTaskSQLsV1({ number: `${props.number}`, @@ -80,15 +78,10 @@ const SqlMode: React.FC = ({ } }) .finally(() => { - set(false); + updateDescDone(); }); }; - const sqlTemplate = useMemo(() => { - const renderSql = (showExecSql ? props.exec_sql : props.rollback_sql) || ''; - return renderSql; - }, [props.exec_sql, props.rollback_sql, showExecSql]); - return ( {contextHolder} @@ -116,91 +109,121 @@ const SqlMode: React.FC = ({
- - - {t('execWorkflow.audit.table.execSql')} - - - {t('execWorkflow.audit.table.rollback')} - - - - - - - - } - > - - {t('execWorkflow.audit.sqlFileSource.source')} - - - - + { + setCurrentContentKey(v as TaskResultContentTypeEnum); + }} + items={[ + { + value: TaskResultContentTypeEnum.exec_sql, + label: t('execWorkflow.audit.table.execSql'), + children: + }, + { + value: TaskResultContentTypeEnum.rollback_sql, + label: t('execWorkflow.audit.table.rollback'), + children: ( + + + + + {props.backup_strategy_tip} + + + + {/* #if [ee] */} + + + { + BackupStrategyDictionary[ + props.backup_strategy as unknown as UpdateSqlBackupStrategyReqStrategyEnum + ] + } + + + } + > + + + {t('execWorkflow.audit.table.backupConflictTips')} + + + + {/* #endif */} + + - + ) + }, + { + value: TaskResultContentTypeEnum.exec_result, + label: t('execWorkflow.audit.table.execResult'), + children: props.exec_result || '-' } - > - - } - > - - {t('execWorkflow.audit.sqlFileSource.source')} - - {props?.sql_source_file} - - - }> - - {t('execWorkflow.audit.sqlFileSource.fileLine')} - - {props?.sql_start_line || '-'} - - + ]} + segmentedRowExtraContent={ + + + + + } + > + + {t('execWorkflow.audit.sqlFileSource.source')} + + - + + + + } + > + + } + > + + {t('execWorkflow.audit.sqlFileSource.source')} + + {props?.sql_source_file} + + + }> + + {t('execWorkflow.audit.sqlFileSource.fileLine')} + + {props?.sql_start_line || '-'} + + + } + />
- - - - - } - />
diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/components/ExecStatusTag.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/components/ExecStatusTag.tsx index e77414a82..9a56c52c4 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/components/ExecStatusTag.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/components/ExecStatusTag.tsx @@ -5,7 +5,9 @@ import { useTranslation } from 'react-i18next'; import { execStatusDictionary } from '../../../../../../../../../hooks/useStaticStatus/index.data'; const execStatusMap: { - [key in getAuditTaskSQLsV2FilterExecStatusEnum]?: BasicTagColor; + [key in + | getAuditTaskSQLsV2FilterExecStatusEnum + | 'execute_rollback']?: BasicTagColor; } = { [getAuditTaskSQLsV2FilterExecStatusEnum.initialized]: 'default', [getAuditTaskSQLsV2FilterExecStatusEnum.failed]: 'red', @@ -14,7 +16,8 @@ const execStatusMap: { [getAuditTaskSQLsV2FilterExecStatusEnum.manually_executed]: 'orange', [getAuditTaskSQLsV2FilterExecStatusEnum.terminate_failed]: 'red', [getAuditTaskSQLsV2FilterExecStatusEnum.terminate_succeeded]: 'green', - [getAuditTaskSQLsV2FilterExecStatusEnum.terminating]: 'geekblue' + [getAuditTaskSQLsV2FilterExecStatusEnum.terminating]: 'geekblue', + [getAuditTaskSQLsV2FilterExecStatusEnum.execute_rollback]: 'orange' }; export interface ExecStatusTagProps { diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/index.data.ts b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/index.data.ts new file mode 100644 index 000000000..26cc59e86 --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/index.data.ts @@ -0,0 +1,7 @@ +export enum TaskResultContentTypeEnum { + exec_sql = 'exec_sql', + rollback_sql = 'rollback_sql', + // 执行预览 暂不处理 + exec_preview = 'exec_preview', + exec_result = 'exec_result' +} diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/index.type.ts index c28011ff3..a1bd3e3d9 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/index.type.ts @@ -12,6 +12,7 @@ export type SqlExecuteResultCardProps = BaseProps & IAuditTaskSQLResV2 & { onUpdateDescription?: () => void; projectID: string; + backupConflict?: boolean; }; export type FileExecuteResultCardProps = BaseProps & diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/style.ts b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/style.ts index 03e6d31f9..915ad4c1a 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/style.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/Common/ResultCard/style.ts @@ -39,6 +39,39 @@ export const TasksResultCardStyleWrapper = styled('div')` .result-card-content-options { display: flex; justify-content: space-between; + margin-bottom: 16px; + + .segmented-tabs-wrapper { + width: 100%; + + .segmented-row-wrapper { + padding: 0; + border: none; + justify-content: space-between; + margin-bottom: 12px; + } + + pre { + margin-bottom: 0; + } + } + + .backup-conflict-tips { + .ant-space-item { + display: flex; + } + } + + .result-card-content-rollback { + display: flex !important; + width: 100%; + align-items: start; + + .ant-space-item:last-of-type { + flex: 1; + overflow: hidden; + } + } } & .ant-collapse.result-record-collapse .ant-collapse-header { diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/PaginationList/SqlExecuteMode/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/PaginationList/SqlExecuteMode/index.tsx index a9b49ecd6..06c42e90a 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/PaginationList/SqlExecuteMode/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/PaginationList/SqlExecuteMode/index.tsx @@ -18,7 +18,8 @@ const SqlExecuteMode: React.FC = ({ noDuplicate, currentListLayout, workflowStatus, - auditResultActiveKey + auditResultActiveKey, + backupConflict }) => { const { t } = useTranslation(); @@ -79,6 +80,7 @@ const SqlExecuteMode: React.FC = ({ taskId={auditResultActiveKey} onUpdateDescription={refresh} executeMode={WorkflowResV2ExecModeEnum.sqls} + backupConflict={backupConflict} /> ); diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/index.type.ts index 083479c59..0b5d1c592 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/TaskResultList/index.type.ts @@ -16,4 +16,5 @@ export type TasksResultListBaseProps = { workflowStatus?: WorkflowRecordResV2StatusEnum; assigneeUserNames: string[]; executeMode: WorkflowResV2ExecModeEnum; + backupConflict?: boolean; }; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/index.tsx index 8f20fb19c..86802b39a 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/AuditExecResultPanel/index.tsx @@ -130,7 +130,11 @@ const AuditExecResultPanel: React.FC = ({ > {t('execWorkflow.create.auditResult.clearDuplicate')} - + @@ -196,6 +200,7 @@ const AuditExecResultPanel: React.FC = ({ (currentTask?.exec_mode as WorkflowResV2ExecModeEnum) ?? WorkflowResV2ExecModeEnum.sqls } + backupConflict={currentTask?.backup_conflict_with_instance} /> diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/action.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/action.tsx index 68630d696..262daa6d3 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/action.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/action.tsx @@ -171,3 +171,37 @@ export const RefreshWorkflowAction = (refreshWorkflow: () => void) => { /> ); }; + +export const RollbackWorkflowAction = ( + rollbackWorkflowButtonMeta: WorkflowDetailActionMeta +) => { + return ( + + + ); +}; + +export const RetryWorkflowAction = ( + retryWorkflowButtonMeta: WorkflowDetailActionMeta +) => { + return ( + + + ); +}; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/hooks/useWorkflowDetailAction.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/hooks/useWorkflowDetailAction.tsx index 770a97be1..61f48d6cc 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/hooks/useWorkflowDetailAction.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/hooks/useWorkflowDetailAction.tsx @@ -27,7 +27,9 @@ const useWorkflowDetailAction = ({ terminateAction, completeAction, maintenanceTimeInfo, - executeInOtherInstanceAction + executeInOtherInstanceAction, + startRollback, + showModifySqlStatementStep }: WorkflowDetailPageHeaderExtraProps & { projectName: string; }): { @@ -39,6 +41,8 @@ const useWorkflowDetailAction = ({ manualExecuteWorkflowButtonMeta: WorkflowDetailActionMeta; terminateWorkflowButtonMeta: WorkflowDetailActionMeta; executeInOtherInstanceMeta: WorkflowDetailActionMeta; + rollbackWorkflowButtonMeta: WorkflowDetailActionMeta; + retryWorkflowButtonMeta: WorkflowDetailActionMeta; executable?: boolean; executable_reason?: string; } => { @@ -263,6 +267,36 @@ const useWorkflowDetailAction = ({ return executeInOtherInstanceAction().finally(executeInOtherInstanceFinish); }; + const rollbackButtonVisibility = useMemo(() => { + if (!workflowInfo?.record?.status) { + return false; + } + return [ + WorkflowRecordResV2StatusEnum.finished, + WorkflowRecordResV2StatusEnum.exec_failed, + WorkflowRecordResV2StatusEnum.canceled + ].includes(workflowInfo.record.status); + }, [workflowInfo?.record?.status]); + + const rollbackWorkflow = () => { + startRollback(); + return undefined; + }; + + const retryButtonVisibility = useMemo(() => { + if (!workflowInfo?.record?.status) { + return false; + } + return ( + workflowInfo.record.status === WorkflowRecordResV2StatusEnum.exec_failed + ); + }, [workflowInfo?.record?.status]); + + const retryWorkflow = () => { + showModifySqlStatementStep(); + return undefined; + }; + return { messageContextHolder, @@ -301,6 +335,16 @@ const useWorkflowDetailAction = ({ loading: executeInOtherInstanceLoading, hidden: false }, + rollbackWorkflowButtonMeta: { + action: rollbackWorkflow, + loading: false, + hidden: !rollbackButtonVisibility + }, + retryWorkflowButtonMeta: { + action: retryWorkflow, + loading: false, + hidden: !retryButtonVisibility + }, executable: workflowInfo?.record?.executable, executable_reason: workflowInfo?.record?.executable_reason diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/index.tsx index f8d4817de..f7fca62e5 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/index.tsx @@ -15,7 +15,9 @@ import { CloseWorkflowAction, MarkManuallyExecWorkflowAction, RefreshWorkflowAction, - TerminateWorkflowAction + TerminateWorkflowAction, + RollbackWorkflowAction, + RetryWorkflowAction } from './action'; const WorkflowDetailPageHeaderExtra: React.FC< @@ -38,6 +40,8 @@ const WorkflowDetailPageHeaderExtra: React.FC< manualExecuteWorkflowButtonMeta, terminateWorkflowButtonMeta, executeInOtherInstanceMeta, + rollbackWorkflowButtonMeta, + retryWorkflowButtonMeta, executable, executable_reason } = useWorkflowDetailAction({ projectName, ...props }); @@ -54,7 +58,10 @@ const WorkflowDetailPageHeaderExtra: React.FC< className="workflow-detail-page-header-divider" />
- + {RetryWorkflowAction(retryWorkflowButtonMeta)} + {/* #if [ee] */} + {RollbackWorkflowAction(rollbackWorkflowButtonMeta)} + {/* #endif */} {CloneWorkflowAction(executeInOtherInstanceMeta)} {BatchRejectWorkflowAction(rejectWorkflowButtonMeta, openRejectModal)} {ApproveWorkflowAction(auditPassWorkflowButtonMeta)} diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/index.type.ts index 86aa7fbb2..17abdd7fe 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/index.type.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/PageHeaderExtra/index.type.ts @@ -21,6 +21,8 @@ export type WorkflowDetailPageHeaderExtraProps = { showWorkflowSteps: () => void; workflowStepsVisibility: boolean; executeInOtherInstanceAction: () => Promise; + startRollback: () => void; + showModifySqlStatementStep: () => void; }; export type WorkflowDetailActionMeta = { diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/TableTransfer.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/TableTransfer.tsx new file mode 100644 index 000000000..8c85d5bbb --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/TableTransfer.tsx @@ -0,0 +1,67 @@ +import { BasicTable } from '@actiontech/shared'; +import { Transfer } from 'antd'; +import { + TableTransferProps, + TableRowSelection, + BackupSqlType +} from './index.type'; + +const TableTransfer: React.FC = (props) => { + const { + leftColumns, + rightColumns, + loading, + leftDataSource, + rightDataSource, + leftPagination, + onTableChange, + ...restProps + } = props; + return ( + + {({ + direction, + onItemSelect, + onItemSelectAll, + selectedKeys: listSelectedKeys + }) => { + const isLeftTable = direction === 'left'; + const columns = isLeftTable ? leftColumns : rightColumns; + const rowSelection: TableRowSelection = { + getCheckboxProps: isLeftTable + ? (item) => ({ disabled: item.disabled }) + : undefined, + onChange(selectedRowKeys) { + onItemSelectAll(selectedRowKeys as string[], 'replace'); + }, + selectedRowKeys: listSelectedKeys, + columnWidth: 60 + }; + + return ( + record.id ?? ''} + columns={columns} + dataSource={isLeftTable ? leftDataSource : rightDataSource} + size="small" + loading={loading} + onRow={({ id = '', disabled: itemDisabled }) => ({ + onClick: () => { + if (itemDisabled) { + return; + } + onItemSelect(id, !listSelectedKeys.includes(id)); + } + })} + pagination={isLeftTable ? leftPagination : undefined} + onChange={isLeftTable ? onTableChange : undefined} + scroll={{ y: '700px' }} + /> + ); + }} + + ); +}; + +export default TableTransfer; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/columns.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/columns.tsx new file mode 100644 index 000000000..098cdf315 --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/columns.tsx @@ -0,0 +1,124 @@ +import { t } from '../../../../../locale'; +import { + ActiontechTableColumn, + PageInfoWithoutIndexAndSize +} from '@actiontech/shared/lib/components/ActiontechTable'; +import { SQLRenderer, EditText, BasicTag } from '@actiontech/shared'; +import { BackupSqlType } from './index.type'; +import { IGetBackupSqlListV1Params } from '@actiontech/shared/lib/api/sqle/service/workflow/index.d'; +import ExecStatusTag from '../AuditExecResultPanel/TaskResultList/Common/ResultCard/components/ExecStatusTag'; +import { tooltipsCommonProps } from '@actiontech/shared/lib/components/BasicToolTips'; +import { getAuditTaskSQLsV2FilterExecStatusEnum } from '@actiontech/shared/lib/api/sqle/service/task/index.enum'; +import { BackupStrategyDictionary } from '../../../Common/AuditResultList/Table/index.data'; +import { UpdateSqlBackupStrategyReqStrategyEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum'; + +export type WorkflowRollbackSqlTableFilterParamType = + PageInfoWithoutIndexAndSize< + IGetBackupSqlListV1Params & { + page_index: number; + page_size: number; + }, + 'project_name' | 'workflow_id' + >; + +export const WorkflowRollbackSqlTableColumn: () => ActiontechTableColumn< + BackupSqlType, + WorkflowRollbackSqlTableFilterParamType +> = () => { + return [ + { + dataIndex: 'origin_sql', + title: 'SQL', + className: 'ellipsis-column-width', + width: 350, + render: (sql_fingerprint, record) => { + if (!sql_fingerprint) return null; + return ( + + ); + } + }, + { + dataIndex: 'backup_strategy', + title: t('execWorkflow.detail.rollback.backupStrategy'), + width: 150, + render: (strategy) => { + return strategy ? ( + + { + BackupStrategyDictionary[ + strategy as unknown as UpdateSqlBackupStrategyReqStrategyEnum + ] + } + + ) : ( + '-' + ); + } + }, + { + dataIndex: 'instance_name', + title: t('execWorkflow.detail.rollback.instance'), + filterCustomType: 'select', + filterKey: 'filter_instance_id' + }, + { + dataIndex: 'exec_status', + title: t('execWorkflow.detail.rollback.execStatus'), + filterCustomType: 'select', + filterKey: 'filter_exec_status', + render: (status) => { + return ( + + ); + } + } + ]; +}; + +export const WorkflowRollbackSelectedSqlTableColumn: ( + onUpdateSqlRemake: (id: string, remake?: string) => void +) => ActiontechTableColumn = (onUpdateSqlRemake) => { + const baseColumns = WorkflowRollbackSqlTableColumn(); + return [ + ...baseColumns, + { + dataIndex: 'remark', + title: t('execWorkflow.detail.rollback.remark'), + width: 150, + render: (remark, record) => { + return ( + { + onUpdateSqlRemake(record.id ?? '', val); + } + }} + ellipsis={{ + expandable: false, + tooltip: { + arrow: false, + ...tooltipsCommonProps(remark, 500) + }, + rows: 1 + }} + value={remark ?? ''} + /> + ); + } + } + ]; +}; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.data.ts b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.data.ts new file mode 100644 index 000000000..516189526 --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.data.ts @@ -0,0 +1,63 @@ +import { execStatusDictionary } from '../../../../../hooks/useStaticStatus/index.data'; +import { getAuditTaskSQLsV2FilterExecStatusEnum } from '@actiontech/shared/lib/api/sqle/service/task/index.enum'; +import { t } from '../../../../../locale'; + +export const SqlExecStatusOptions: Array<{ + label: string; + value: getAuditTaskSQLsV2FilterExecStatusEnum; +}> = [ + { + label: t( + execStatusDictionary[getAuditTaskSQLsV2FilterExecStatusEnum.doing] + ), + value: getAuditTaskSQLsV2FilterExecStatusEnum.doing + }, + { + label: t( + execStatusDictionary[getAuditTaskSQLsV2FilterExecStatusEnum.failed] + ), + value: getAuditTaskSQLsV2FilterExecStatusEnum.failed + }, + { + label: t( + execStatusDictionary[getAuditTaskSQLsV2FilterExecStatusEnum.initialized] + ), + value: getAuditTaskSQLsV2FilterExecStatusEnum.initialized + }, + { + label: t( + execStatusDictionary[ + getAuditTaskSQLsV2FilterExecStatusEnum.manually_executed + ] + ), + value: getAuditTaskSQLsV2FilterExecStatusEnum.manually_executed + }, + { + label: t( + execStatusDictionary[getAuditTaskSQLsV2FilterExecStatusEnum.succeeded] + ), + value: getAuditTaskSQLsV2FilterExecStatusEnum.succeeded + }, + { + label: t( + execStatusDictionary[ + getAuditTaskSQLsV2FilterExecStatusEnum.terminate_failed + ] + ), + value: getAuditTaskSQLsV2FilterExecStatusEnum.terminate_failed + }, + { + label: t( + execStatusDictionary[ + getAuditTaskSQLsV2FilterExecStatusEnum.terminate_succeeded + ] + ), + value: getAuditTaskSQLsV2FilterExecStatusEnum.terminate_succeeded + }, + { + label: t( + execStatusDictionary[getAuditTaskSQLsV2FilterExecStatusEnum.terminating] + ), + value: getAuditTaskSQLsV2FilterExecStatusEnum.terminating + } +]; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.tsx new file mode 100644 index 000000000..18750057d --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.tsx @@ -0,0 +1,327 @@ +import { SqlRollbackProps } from './index.type'; +import { + EmptyBox, + PageHeader, + BasicButton, + useTypedNavigate +} from '@actiontech/shared'; +import { LeftArrowOutlined } from '@actiontech/icons'; +import { useTranslation } from 'react-i18next'; +import { useEffect, useState, useMemo } from 'react'; +import { + WorkflowRollbackSqlTableColumn, + WorkflowRollbackSelectedSqlTableColumn, + WorkflowRollbackSqlTableFilterParamType +} from './columns'; +import { useRequest } from 'ahooks'; +import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { SqlRollbackTableStyleWrapper } from './style'; +import { TransferDirection } from 'antd/es/transfer'; +import { cloneDeep } from 'lodash'; +import { + TableFilterContainer, + useTableFilterContainer, + useTableRequestParams, + FilterCustomProps +} from '@actiontech/shared/lib/components/ActiontechTable'; +import TableTransfer from './TableTransfer'; +import { BackupSqlType, TableTransferProps } from './index.type'; +import workflow from '@actiontech/shared/lib/api/sqle/service/workflow'; +import { useCurrentProject } from '@actiontech/shared/lib/global'; +import { useParams } from 'react-router-dom'; +import { SqlExecStatusOptions } from './index.data'; +import useInstance from '../../../../../hooks/useInstance'; +import { getInstanceTipListV1FunctionalModuleEnum } from '@actiontech/shared/lib/api/sqle/service/instance/index.enum'; +import { groupBy } from 'lodash'; +import { SqlStatementFields } from '../../../Create/index.type'; +import { AuditTaskResV1SqlSourceEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum'; +import { useDispatch } from 'react-redux'; +import { + updateClonedExecWorkflowSqlAuditInfo, + updateClonedExecWorkflowBaseInfo, + updateWorkflowRollbackSqlIds +} from '../../../../../store/sqlExecWorkflow'; +import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import { Space, SelectProps } from 'antd'; + +const SqlRollback: React.FC = ({ + isAtRollbackStep, + backToWorkflowDetail, + taskInfos, + workflowInfo +}) => { + const { t } = useTranslation(); + + const dispatch = useDispatch(); + + const navigate = useTypedNavigate(); + + const [targetKeys, setTargetKeys] = useState([]); + + const [selectedList, setSelectedList] = useState([]); + + const { pagination, tableChange, updateTableFilterInfo, tableFilterInfo } = + useTableRequestParams< + BackupSqlType, + WorkflowRollbackSqlTableFilterParamType + >(); + + const { updateAllSelectedFilterItem, filterContainerMeta } = + useTableFilterContainer( + WorkflowRollbackSqlTableColumn(), + updateTableFilterInfo + ); + + const { projectName, projectID } = useCurrentProject(); + + const { updateInstanceList, instanceIDOptions, instanceList } = useInstance(); + + const urlParams = useParams<{ workflowId: string }>(); + + const { data, loading, mutate } = useRequest( + () => { + return workflow + .GetBackupSqlListV1({ + ...tableFilterInfo, + page_index: pagination.page_index.toString(), + page_size: pagination.page_size.toString(), + project_name: projectName, + workflow_id: urlParams.workflowId ?? '' + }) + .then((res) => { + if (res.data.code === ResponseCode.SUCCESS) { + return { + list: + res.data.data?.map((item) => ({ + ...item, + id: item.exec_sql_id?.toString(), + disabled: selectedList.some( + (i) => i.id === item.exec_sql_id?.toString() + ) + })) || [], + total: res.data.total_nums || 0 + }; + } + }); + }, + { + refreshDeps: [pagination, tableFilterInfo], + ready: isAtRollbackStep + } + ); + + const onChange: TableTransferProps['onChange'] = ( + nextTargetKeys: string[], + direction: TransferDirection, + moveKeys: string[] + ) => { + if (direction === 'left') { + const selected = selectedList.filter((i) => { + return !moveKeys.includes(i.id ?? ''); + }); + const clonedData = cloneDeep(data?.list ?? []); + clonedData.forEach((i) => { + if (moveKeys.includes(i.id ?? '')) { + i.disabled = false; + } + }); + setSelectedList(selected); + mutate({ + list: clonedData, + total: data?.total ?? 0 + }); + } else { + const selected: BackupSqlType[] = []; + const clonedData = cloneDeep(data?.list ?? []); + moveKeys.forEach((key) => { + const dataSource = clonedData.find((i) => { + if (i.id === key) { + i.disabled = true; + return true; + } + return false; + }); + if (dataSource) { + selected.push(dataSource); + } + }); + setSelectedList(selectedList.concat(selected)); + mutate({ + list: clonedData, + total: data?.total ?? 0 + }); + } + setTargetKeys(nextTargetKeys); + }; + + const taskInstanceIdOptions = useMemo(() => { + const instanceNames = taskInfos?.map((i) => i.instance_name); + const instanceIds = instanceNames?.map( + (name) => instanceList.find((i) => i.instance_name === name)?.instance_id + ); + const instanceOptions: SelectProps['options'] = []; + instanceIDOptions.forEach((instance) => { + if (instance.options.some((i) => instanceIds?.includes(i.value))) { + instanceOptions.push({ + ...instance, + options: instance.options.filter((i) => + instanceIds?.includes(i.value) + ) + }); + } + }); + return instanceOptions; + }, [taskInfos, instanceIDOptions, instanceList]); + + const filterCustomProps = useMemo(() => { + return new Map([ + ['instance_name', { options: taskInstanceIdOptions }], + ['exec_status', { options: SqlExecStatusOptions }] + ]); + }, [taskInstanceIdOptions]); + + const onUpdateSqlRemake = (id: string, remark?: string) => { + const clonedSelectedList = cloneDeep(selectedList); + const editItemIndex = clonedSelectedList.findIndex((i) => i.id === id) ?? 0; + clonedSelectedList[editItemIndex].remark = remark; + setSelectedList(clonedSelectedList); + }; + + const onCreateWorkflow = () => { + const sqlStatement: { [key: string]: SqlStatementFields } = {}; + let description = ''; + selectedList.forEach((i) => { + if (i.remark) { + description += `${i.remark};`; + } + }); + const sqlIds = selectedList.map((i) => i.exec_sql_id ?? 0); + const taskSqlGroup = groupBy(selectedList, 'origin_task_id'); + const taskIds = Object.keys(taskSqlGroup); + const databaseInfo = taskIds?.map((id) => { + const taskInfo = taskInfos?.find((i) => `${i.task_id}` === id) ?? {}; + return { + instanceName: taskInfo.instance_name, + instanceSchema: taskInfo.instance_schema + }; + }); + + taskIds.forEach((id, index) => { + let sqlFormData = ''; + const sortedBackupSqlList = taskSqlGroup[id].sort( + (a, b) => (a.exec_order ?? 0) - (b.exec_order ?? 0) + ); + sortedBackupSqlList.forEach((item) => { + let backupSqlStatement = ''; + backupSqlStatement += `-- ${t( + 'execWorkflow.detail.rollback.originSql' + )}: ${item.origin_sql} \n`; + item.backup_sqls?.forEach((i) => (backupSqlStatement += `${i}\n`)); + sqlFormData += backupSqlStatement; + }); + sqlStatement[`${index}`] = { + currentUploadType: AuditTaskResV1SqlSourceEnum.form_data, + form_data: sqlFormData + } as SqlStatementFields; + }); + dispatch( + updateClonedExecWorkflowBaseInfo({ + workflow_subject: `${workflowInfo?.workflow_name}_Rollback`, + desc: description + }) + ); + + dispatch( + updateClonedExecWorkflowSqlAuditInfo({ + isSameSqlForAll: false, + databaseInfo, + ...sqlStatement + }) + ); + dispatch( + updateWorkflowRollbackSqlIds({ + workflowRollbackSqlIds: sqlIds + }) + ); + + navigate(ROUTE_PATHS.SQLE.SQL_EXEC_WORKFLOW.create, { + params: { projectID }, + queries: { + rollbackWorkflowId: workflowInfo?.workflow_id + } + }); + }; + + const onBack = () => { + setSelectedList([]); + backToWorkflowDetail(); + }; + + useEffect(() => { + updateInstanceList({ + project_name: projectName, + functional_module: + getInstanceTipListV1FunctionalModuleEnum.create_workflow + }); + }, [updateInstanceList, projectName]); + + useEffect(() => { + updateAllSelectedFilterItem(true); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + } onClick={onBack}> + {t('execWorkflow.detail.operator.backToDetail')} + + } + extra={ + + {t('execWorkflow.list.createButtonText')} + + } + /> + + + + {t('execWorkflow.detail.rollback.allSql')} + +
, + t('execWorkflow.detail.rollback.selectedRollbackSql') + ]} + loading={loading} + leftDataSource={data?.list ?? []} + rightDataSource={selectedList} + leftPagination={{ + total: data?.total || 0, + current: pagination.page_index + }} + onTableChange={tableChange} + /> + + + ); +}; + +export default SqlRollback; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.type.ts b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.type.ts new file mode 100644 index 000000000..0e7466ad0 --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/index.type.ts @@ -0,0 +1,37 @@ +import { + IBackupSqlData, + IWorkflowResV2, + IAuditTaskResV1 +} from '@actiontech/shared/lib/api/sqle/service/common'; +import type { + TableColumnsType, + TableProps, + TransferProps, + TablePaginationConfig +} from 'antd'; + +export type SqlRollbackProps = { + isAtRollbackStep: boolean; + backToWorkflowDetail: () => void; + workflowInfo?: IWorkflowResV2; + taskInfos?: IAuditTaskResV1[]; +}; + +export type BackupSqlType = IBackupSqlData & { + id?: string; + disabled?: boolean; + remark?: string; +}; + +export type TableRowSelection = TableProps['rowSelection']; + +export interface TableTransferProps extends TransferProps { + dataSource: BackupSqlType[]; + leftColumns: TableColumnsType; + rightColumns: TableColumnsType; + loading: boolean; + leftDataSource?: BackupSqlType[]; + rightDataSource?: BackupSqlType[]; + leftPagination: TablePaginationConfig; + onTableChange: TableProps['onChange']; +} diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/style.ts b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/style.ts new file mode 100644 index 000000000..8e96185a3 --- /dev/null +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/components/SqlRollback/style.ts @@ -0,0 +1,51 @@ +import { styled } from '@mui/material'; + +export const SqlRollbackTableStyleWrapper = styled('section')` + & .ant-transfer.ant-transfer-customize-list .ant-transfer-list { + border: none; + + &:first-of-type { + border: 1px solid + ${({ theme }) => theme.sharedTheme.uiToken.colorBorderSecondary}; + border-top: none; + border-left: none; + } + + &:last-of-type { + border: 1px solid + ${({ theme }) => theme.sharedTheme.uiToken.colorBorderSecondary}; + border-top: none; + border-right: none; + } + + .ant-transfer-list-header-selected { + display: none; + } + + .ant-transfer-list-header-title { + text-align: start; + padding: 0 28px; + } + + & .ant-table-wrapper { + padding-bottom: 0px; + } + + & .ant-table-container .ant-table-body { + max-height: calc(100vh - 250px) !important; + } + + .ant-tag { + width: max-content; + } + + .audit-result-describe-column { + max-width: 600px; + } + + .actiontech-table-filter-container-namespace { + padding: 0 !important; + border: none !important; + } + } +`; diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/hooks/useCloneExecWorkflowInfo.ts b/packages/sqle/src/page/SqlExecWorkflow/Detail/hooks/useCloneExecWorkflowInfo.ts index 91f383bb2..117033d91 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/hooks/useCloneExecWorkflowInfo.ts +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/hooks/useCloneExecWorkflowInfo.ts @@ -95,7 +95,8 @@ const useCloneExecWorkflowInfo = ( await getTaskAllSql(defaultTask.task_id).then((res) => { sqlStatement['0'] = { currentUploadType: AuditTaskResV1SqlSourceEnum.form_data, - form_data: res + form_data: res, + backup: defaultTask.enable_backup } as SqlStatementFields; }); } else if (isSqlFileUploadType) { @@ -103,7 +104,8 @@ const useCloneExecWorkflowInfo = ( sqlStatement['0'] = { currentUploadType: AuditTaskResV1SqlSourceEnum.sql_file, sql_file: res ? [new File([res], fileName)] : undefined, - exec_mode: defaultTask.exec_mode + exec_mode: defaultTask.exec_mode, + backup: defaultTask.enable_backup } as SqlStatementFields; }); } else if (isZipFileUploadType) { @@ -112,7 +114,8 @@ const useCloneExecWorkflowInfo = ( currentUploadType: AuditTaskResV1SqlSourceEnum.zip_file, zip_file: res ? [new File([res], fileName)] : undefined, exec_mode: defaultTask.exec_mode, - file_sort_method: defaultTask.file_order_method + file_sort_method: defaultTask.file_order_method, + backup: defaultTask.enable_backup } as SqlStatementFields; }); } @@ -131,7 +134,8 @@ const useCloneExecWorkflowInfo = ( return getTaskAllSql(taskInfo.task_id).then((res) => { return { currentUploadType: AuditTaskResV1SqlSourceEnum.form_data, - form_data: res + form_data: res, + backup: taskInfo.enable_backup } as SqlStatementFields; }); } else if (isSqlFileUploadType) { @@ -139,7 +143,8 @@ const useCloneExecWorkflowInfo = ( return { currentUploadType: AuditTaskResV1SqlSourceEnum.sql_file, sql_file: res ? [new File([res], fileName)] : undefined, - exec_mode: taskInfo.exec_mode + exec_mode: taskInfo.exec_mode, + backup: taskInfo.enable_backup } as SqlStatementFields; }); } else if (isZipFileUploadType) { @@ -148,7 +153,8 @@ const useCloneExecWorkflowInfo = ( currentUploadType: AuditTaskResV1SqlSourceEnum.zip_file, zip_file: res ? [new File([res], fileName)] : undefined, exec_mode: taskInfo.exec_mode, - file_sort_method: taskInfo.file_order_method + file_sort_method: taskInfo.file_order_method, + backup: taskInfo.enable_backup } as SqlStatementFields; }); } diff --git a/packages/sqle/src/page/SqlExecWorkflow/Detail/index.tsx b/packages/sqle/src/page/SqlExecWorkflow/Detail/index.tsx index 164e61591..0ceb96c6d 100644 --- a/packages/sqle/src/page/SqlExecWorkflow/Detail/index.tsx +++ b/packages/sqle/src/page/SqlExecWorkflow/Detail/index.tsx @@ -20,6 +20,7 @@ import WorkflowRecordInfo from './components/RecordInfo'; import ModifySqlStatement from './components/ModifySqlStatement'; import useAuditExecResultPanelSetup from './hooks/useAuditExecResultPanelSetup'; import AuditExecResultPanel from './components/AuditExecResultPanel'; +import SqlRollback from './components/SqlRollback'; const SqlWorkflowDetail: React.FC = () => { const { username } = useCurrentUser(); @@ -29,6 +30,9 @@ const SqlWorkflowDetail: React.FC = () => { { setFalse: closeWorkflowSteps, setTrue: showWorkflowSteps } ] = useBoolean(false); + const [isAtRollbackStep, { setTrue: startRollback, setFalse: stopRollback }] = + useBoolean(); + const { taskInfos, workflowInfo, refreshWorkflowInfo, initLoading } = useInitDataWithRequest(); @@ -81,7 +85,7 @@ const SqlWorkflowDetail: React.FC = () => { {messageContextHolder}