diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx index 256589ac0..ecef655af 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx @@ -1,11 +1,13 @@ // components/DeployItemModal.tsx import React, { useState, useEffect } from 'react'; -import { Modal, Form, Select, Checkbox, Button, Spin, Input, Tag, Space } from 'antd'; +import { Modal, Form, Select, Checkbox, Button, Spin, Input, Tag, Space, Alert } from 'antd'; import { messageInstance } from 'lowcoder-design/src/components/GlobalInstances'; import { Environment } from '../types/environment.types'; import { DeployableItemConfig } from '../types/deployable-item.types'; import { useEnvironmentContext } from '../context/EnvironmentContext'; import { getEnvironmentTagColor, formatEnvironmentType } from '../utils/environmentUtils'; +import { ExclamationCircleOutlined } from '@ant-design/icons'; +import { showFirstCredentialOverwriteConfirm, showSecondCredentialOverwriteConfirm } from './credentialConfirmations'; interface DeployItemModalProps { visible: boolean; @@ -27,10 +29,12 @@ function DeployItemModal({ const [form] = Form.useForm(); const { environments, isLoading } = useEnvironmentContext(); const [deploying, setDeploying] = useState(false); + const [credentialConfirmationStep, setCredentialConfirmationStep] = useState(0); // 0: not started, 1: first confirmation, 2: confirmed useEffect(() => { if (visible) { form.resetFields(); + setCredentialConfirmationStep(0); } }, [visible, form]); @@ -39,6 +43,40 @@ function DeployItemModal({ (env: Environment) => env.environmentId !== sourceEnvironment.environmentId && env.isLicensed !== false ); + // Handle credential checkbox change with double confirmation + const handleCredentialCheckboxChange = (checked: boolean, fieldName: string) => { + if (!checked) { + // If unchecking, reset confirmation and update form + setCredentialConfirmationStep(0); + form.setFieldsValue({ [fieldName]: false }); + return; + } + + // First confirmation + if (credentialConfirmationStep === 0) { + showFirstCredentialOverwriteConfirm({ + onOk: () => { + setCredentialConfirmationStep(1); + // Show second confirmation immediately + showSecondCredentialOverwriteConfirm({ + onOk: () => { + setCredentialConfirmationStep(2); + form.setFieldsValue({ [fieldName]: true }); + }, + onCancel: () => { + setCredentialConfirmationStep(0); + form.setFieldsValue({ [fieldName]: false }); + } + }); + }, + onCancel: () => { + setCredentialConfirmationStep(0); + form.setFieldsValue({ [fieldName]: false }); + } + }); + } + }; + const handleDeploy = async () => { if (!config.deploy || !item) return; @@ -50,6 +88,12 @@ function DeployItemModal({ messageInstance.error('Target environment not found'); return; } + + // Additional check for credential overwrite + if (values.deployCredential && credentialConfirmationStep !== 2) { + messageInstance.error('Please confirm credential overwrite before deploying'); + return; + } setDeploying(true); @@ -124,6 +168,8 @@ function DeployItemModal({ {config.deploy?.fields.map(field => { switch (field.type) { case 'checkbox': + // Special handling for credential-related checkboxes + const isCredentialField = field.name === 'deployCredential'; return ( - {field.label} + { + if (isCredentialField) { + handleCredentialCheckboxChange(e.target.checked, field.name); + } else { + // For non-credential checkboxes, handle normally + form.setFieldsValue({ [field.name]: e.target.checked }); + } + }} + > + {field.label} + {isCredentialField && credentialConfirmationStep === 2 && ( + } + > + Confirmed + + )} + ); case 'select': @@ -168,7 +234,7 @@ function DeployItemModal({ return null; } })} - +