From 2c21181bcfcd1fbd6b31c0ba6c1de40abe4cf316 Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Tue, 27 May 2025 14:54:33 +0500 Subject: [PATCH 1/4] Add deploy credential param in the deployment endpoint --- .../setting/environments/config/apps.config.tsx | 7 +++++++ .../environments/config/data-sources.config.tsx | 9 ++++++++- .../setting/environments/config/workspace.config.tsx | 12 ++++++++++-- .../setting/environments/services/apps.service.ts | 4 +++- .../environments/services/datasources.service.ts | 3 ++- .../environments/services/workspace.service.ts | 4 +++- 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/client/packages/lowcoder/src/pages/setting/environments/config/apps.config.tsx b/client/packages/lowcoder/src/pages/setting/environments/config/apps.config.tsx index b2459abb7..197b2a826 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/config/apps.config.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/config/apps.config.tsx @@ -39,6 +39,12 @@ export const appsConfig: DeployableItemConfig = { label: 'Public To Marketplace', type: 'checkbox', defaultValue: false + }, + { + name: 'deployCredential', + label: 'Overwrite Credentials', + type: 'checkbox', + defaultValue: false } ], prepareParams: (item: App, values: any, sourceEnv: Environment, targetEnv: Environment) => { @@ -51,6 +57,7 @@ export const appsConfig: DeployableItemConfig = { publicToAll: values.publicToAll, publicToMarketplace: values.publicToMarketplace, applicationGid: item.applicationGid, + deployCredential: values.deployCredential ?? false }; }, execute: (params: any) => deployApp(params) diff --git a/client/packages/lowcoder/src/pages/setting/environments/config/data-sources.config.tsx b/client/packages/lowcoder/src/pages/setting/environments/config/data-sources.config.tsx index 3ae507dd8..591621862 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/config/data-sources.config.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/config/data-sources.config.tsx @@ -16,6 +16,12 @@ export const dataSourcesConfig: DeployableItemConfig = { label: 'Update Dependencies If Needed', type: 'checkbox', defaultValue: false + }, + { + name: 'deployCredential', + label: 'Overwrite Credentials', + type: 'checkbox', + defaultValue: false } ], prepareParams: (item: DataSource, values: any, sourceEnv: Environment, targetEnv: Environment) => { @@ -24,7 +30,8 @@ export const dataSourcesConfig: DeployableItemConfig = { targetEnvId: targetEnv.environmentId, datasourceId: item.id, updateDependenciesIfNeeded: values.updateDependenciesIfNeeded, - datasourceGid: item.gid + datasourceGid: item.gid, + deployCredential: values.deployCredential ?? false }; }, execute: (params: any) => deployDataSource(params) diff --git a/client/packages/lowcoder/src/pages/setting/environments/config/workspace.config.tsx b/client/packages/lowcoder/src/pages/setting/environments/config/workspace.config.tsx index 4b55b4257..6689931f9 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/config/workspace.config.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/config/workspace.config.tsx @@ -12,7 +12,14 @@ export const workspaceConfig: DeployableItemConfig = { // Deploy configuration deploy: { singularLabel: 'Workspace', - fields: [], + fields: [ + { + name: 'deployCredential', + label: 'Overwrite Credentials', + type: 'checkbox', + defaultValue: false + } + ], prepareParams: (item: Workspace, values: any, sourceEnv: Environment, targetEnv: Environment) => { if (!item.gid) { console.error('Missing workspace.gid when deploying workspace:', item); @@ -22,7 +29,8 @@ export const workspaceConfig: DeployableItemConfig = { return { envId: sourceEnv.environmentId, targetEnvId: targetEnv.environmentId, - workspaceId: item.gid + workspaceId: item.gid, + deployCredential: values.deployCredential ?? false }; }, execute: (params: any) => deployWorkspace(params) diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/apps.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/apps.service.ts index 6d9d40eaf..db7f21dff 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/apps.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/apps.service.ts @@ -23,6 +23,7 @@ export interface DeployAppParams { publishOnTarget?: boolean; publicToAll?: boolean; publicToMarketplace?: boolean; + deployCredential: boolean; } @@ -119,7 +120,8 @@ export const deployApp = async (params: DeployAppParams): Promise => { updateDependenciesIfNeeded: params.updateDependenciesIfNeeded ?? false, publishOnTarget: params.publishOnTarget ?? false, publicToAll: params.publicToAll ?? false, - publicToMarketplace: params.publicToMarketplace ?? false + publicToMarketplace: params.publicToMarketplace ?? false, + deployCredential: params.deployCredential } } ); diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/datasources.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/datasources.service.ts index 0e181a6da..e743179b0 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/datasources.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/datasources.service.ts @@ -22,7 +22,7 @@ export interface DeployDataSourceParams { datasourceId: string; datasourceGid: string; updateDependenciesIfNeeded?: boolean; - + deployCredential: boolean; } // Get data sources for a workspace - using your correct implementation export async function getWorkspaceDataSources( @@ -159,6 +159,7 @@ export async function deployDataSource(params: DeployDataSourceParams): Promise< targetEnvId: params.targetEnvId, datasourceId: params.datasourceId, updateDependenciesIfNeeded: params.updateDependenciesIfNeeded ?? false, + deployCredential: params.deployCredential } }); if (response.status === 200) { diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/workspace.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/workspace.service.ts index 3683b97d7..dec7c7cf7 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/workspace.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/workspace.service.ts @@ -84,6 +84,7 @@ export async function deployWorkspace(params: { envId: string; targetEnvId: string; workspaceId: string; + deployCredential: boolean; // Mandatory parameter }): Promise { try { // Use the new endpoint format with only essential parameters @@ -91,7 +92,8 @@ export async function deployWorkspace(params: { params: { orgGid: params.workspaceId, // Using workspaceId as orgGid envId: params.envId, - targetEnvId: params.targetEnvId + targetEnvId: params.targetEnvId, + deployCredential: params.deployCredential } }); From 288ce772cf5c7d00c3dcdabb0dbe7aa99151ab3b Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Tue, 27 May 2025 15:09:40 +0500 Subject: [PATCH 2/4] Add overwrite credential in the Deploy Modal --- .../components/DeployItemModal.tsx | 101 +++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) 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..60688f83c 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,12 @@ // 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'; interface DeployItemModalProps { visible: boolean; @@ -27,10 +28,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 +42,76 @@ 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) { + Modal.confirm({ + title: 'Overwrite Credentials Warning', + icon: , + content: ( +
+ +
+ ), + okText: 'Continue', + cancelText: 'Cancel', + onOk: () => { + setCredentialConfirmationStep(1); + // Show second confirmation immediately + showSecondConfirmation(fieldName); + }, + onCancel: () => { + setCredentialConfirmationStep(0); + form.setFieldsValue({ [fieldName]: false }); + } + }); + } + }; + + const showSecondConfirmation = (fieldName: string) => { + Modal.confirm({ + title: 'Final Confirmation Required', + icon: , + content: ( +
+ +

Are you absolutely certain you want to overwrite the credentials?

+
+ ), + okText: 'Yes, Overwrite Credentials', + okType: 'danger', + cancelText: 'Cancel', + onOk: () => { + setCredentialConfirmationStep(2); + form.setFieldsValue({ [fieldName]: true }); + }, + onCancel: () => { + setCredentialConfirmationStep(0); + form.setFieldsValue({ [fieldName]: false }); + } + }); + }; + const handleDeploy = async () => { if (!config.deploy || !item) return; @@ -50,6 +123,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 +203,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': From 97b0aab9ded2a83c1ed5b69478eb0028b0e571ce Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Tue, 27 May 2025 15:51:08 +0500 Subject: [PATCH 3/4] improve UI confirmation for the deployment --- .../components/DeployItemModal.tsx | 107 +++++++++++++++--- 1 file changed, 94 insertions(+), 13 deletions(-) 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 60688f83c..4b3c9f583 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx @@ -6,7 +6,7 @@ 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 { ExclamationCircleOutlined, WarningOutlined } from '@ant-design/icons'; interface DeployItemModalProps { visible: boolean; @@ -54,21 +54,53 @@ function DeployItemModal({ // First confirmation if (credentialConfirmationStep === 0) { Modal.confirm({ - title: 'Overwrite Credentials Warning', - icon: , + title: ( +
+ + Overwrite Credentials Warning +
+ ), + icon: null, content: ( -
+
+

+ This is a serious operation that may affect other applications and users. +

+

+ Are you sure you want to proceed? +

+
+ } type="warning" showIcon - style={{ marginBottom: 16 }} + style={{ + marginBottom: 0, + border: '1px solid #fff2e8', + borderRadius: '8px' + }} />
), okText: 'Continue', cancelText: 'Cancel', + okButtonProps: { + style: { + backgroundColor: '#ff7a00', + borderColor: '#ff7a00', + fontWeight: '500' + } + }, + cancelButtonProps: { + style: { + fontWeight: '500' + } + }, + width: 520, + centered: false, onOk: () => { setCredentialConfirmationStep(1); // Show second confirmation immediately @@ -84,23 +116,68 @@ function DeployItemModal({ const showSecondConfirmation = (fieldName: string) => { Modal.confirm({ - title: 'Final Confirmation Required', - icon: , + title: ( +
+ + Final Confirmation Required +
+ ), + icon: null, content: ( -
+
+

+ You are about to overwrite credentials in the target environment. + This action cannot be undone and may break existing integrations. +

+

+ Please confirm one more time. +

+
+ } type="error" showIcon - style={{ marginBottom: 16 }} + style={{ + marginBottom: 16, + border: '1px solid #ffebee', + borderRadius: '8px' + }} /> -

Are you absolutely certain you want to overwrite the credentials?

+
+

+ Are you absolutely certain you want to overwrite the credentials? +

+
), okText: 'Yes, Overwrite Credentials', okType: 'danger', cancelText: 'Cancel', + okButtonProps: { + style: { + fontWeight: '500' + } + }, + cancelButtonProps: { + style: { + fontWeight: '500' + } + }, + width: 520, + centered: false, onOk: () => { setCredentialConfirmationStep(2); form.setFieldsValue({ [fieldName]: true }); @@ -224,7 +301,11 @@ function DeployItemModal({ > {field.label} {isCredentialField && credentialConfirmationStep === 2 && ( - + } + > Confirmed )} From 38cd16b305393a06229d2a8e0c72087633f7951e Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Tue, 27 May 2025 16:24:24 +0500 Subject: [PATCH 4/4] refactor deploy modal --- .../components/DeployItemModal.tsx | 140 ++---------------- .../components/credentialConfirmations.tsx | 111 ++++++++++++++ 2 files changed, 125 insertions(+), 126 deletions(-) create mode 100644 client/packages/lowcoder/src/pages/setting/environments/components/credentialConfirmations.tsx 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 4b3c9f583..ecef655af 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx @@ -6,7 +6,8 @@ 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, WarningOutlined } from '@ant-design/icons'; +import { ExclamationCircleOutlined } from '@ant-design/icons'; +import { showFirstCredentialOverwriteConfirm, showSecondCredentialOverwriteConfirm } from './credentialConfirmations'; interface DeployItemModalProps { visible: boolean; @@ -53,58 +54,20 @@ function DeployItemModal({ // First confirmation if (credentialConfirmationStep === 0) { - Modal.confirm({ - title: ( -
- - Overwrite Credentials Warning -
- ), - icon: null, - content: ( -
- -

- This is a serious operation that may affect other applications and users. -

-

- Are you sure you want to proceed? -

-
- } - type="warning" - showIcon - style={{ - marginBottom: 0, - border: '1px solid #fff2e8', - borderRadius: '8px' - }} - /> - - ), - okText: 'Continue', - cancelText: 'Cancel', - okButtonProps: { - style: { - backgroundColor: '#ff7a00', - borderColor: '#ff7a00', - fontWeight: '500' - } - }, - cancelButtonProps: { - style: { - fontWeight: '500' - } - }, - width: 520, - centered: false, + showFirstCredentialOverwriteConfirm({ onOk: () => { setCredentialConfirmationStep(1); // Show second confirmation immediately - showSecondConfirmation(fieldName); + showSecondCredentialOverwriteConfirm({ + onOk: () => { + setCredentialConfirmationStep(2); + form.setFieldsValue({ [fieldName]: true }); + }, + onCancel: () => { + setCredentialConfirmationStep(0); + form.setFieldsValue({ [fieldName]: false }); + } + }); }, onCancel: () => { setCredentialConfirmationStep(0); @@ -114,81 +77,6 @@ function DeployItemModal({ } }; - const showSecondConfirmation = (fieldName: string) => { - Modal.confirm({ - title: ( -
- - Final Confirmation Required -
- ), - icon: null, - content: ( -
- -

- You are about to overwrite credentials in the target environment. - This action cannot be undone and may break existing integrations. -

-

- Please confirm one more time. -

-
- } - type="error" - showIcon - style={{ - marginBottom: 16, - border: '1px solid #ffebee', - borderRadius: '8px' - }} - /> -
-

- Are you absolutely certain you want to overwrite the credentials? -

-
- - ), - okText: 'Yes, Overwrite Credentials', - okType: 'danger', - cancelText: 'Cancel', - okButtonProps: { - style: { - fontWeight: '500' - } - }, - cancelButtonProps: { - style: { - fontWeight: '500' - } - }, - width: 520, - centered: false, - onOk: () => { - setCredentialConfirmationStep(2); - form.setFieldsValue({ [fieldName]: true }); - }, - onCancel: () => { - setCredentialConfirmationStep(0); - form.setFieldsValue({ [fieldName]: false }); - } - }); - }; - const handleDeploy = async () => { if (!config.deploy || !item) return; @@ -346,7 +234,7 @@ function DeployItemModal({ return null; } })} - +