From 97b436bb4e18520ffac230fc00bec52ebc0571f6 Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Tue, 23 May 2023 01:29:45 +0000 Subject: [PATCH 01/15] save for now --- .../CommonParameters.tsx | 33 +++++++++++++++++++ .../DatabaseConnectionForm/index.tsx | 3 ++ .../databases/DatabaseModal/index.tsx | 13 +------- superset-frontend/src/views/CRUD/hooks.ts | 3 ++ superset/db_engine_specs/base.py | 4 +++ 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx index 99a414012b779..d853b3a5d94bc 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx @@ -250,3 +250,36 @@ export const forceSSLField = ({ /> ); + +export const SSHTunnelSwitch = ({ + isEditMode, + changeMethods, + db, + setDB, + useSSHTunneling, +}: FieldPropTypes) => + true ? ( +
infoTooltip(theme)}> + { + changeMethods.onParametersChange({ + target: { + type: 'toggle', + name: 'ssh', + checked: true, + value: changed, + }, + }); + }} + data-test="ssh-tunnel-switch" + /> + {t('SSH Tunnel')} + +
+ ) : null; diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/index.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/index.tsx index f6284ae67d9a7..5dce73206f151 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/index.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/index.tsx @@ -31,6 +31,7 @@ import { portField, queryField, usernameField, + SSHTunnelSwitch, } from './CommonParameters'; import { validatedInputField } from './ValidatedInputField'; import { EncryptedField } from './EncryptedField'; @@ -55,6 +56,7 @@ export const FormFieldOrder = [ 'account', 'warehouse', 'role', + 'ssh', ]; export interface FieldPropTypes { @@ -102,6 +104,7 @@ const FORM_FIELD_MAP = { warehouse: validatedInputField, role: validatedInputField, account: validatedInputField, + ssh: SSHTunnelSwitch, }; interface DatabaseConnectionFormProps { diff --git a/superset-frontend/src/features/databases/DatabaseModal/index.tsx b/superset-frontend/src/features/databases/DatabaseModal/index.tsx index 25fbadd3e1487..b857f43f7a78e 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/index.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/index.tsx @@ -1633,18 +1633,7 @@ const DatabaseModal: FunctionComponent = ({ validationErrors={validationErrors} getPlaceholder={getPlaceholder} /> - - - - {useSSHTunneling && ( + {db?.parameters?.ssh && ( {renderSSHTunnelForm()} )} diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index 7947494f315bd..0363b8d07c2a8 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -753,6 +753,9 @@ export function useDatabaseValidation() { .catch(e => { if (typeof e.json === 'function') { return e.json().then(({ errors = [] }: JsonObject) => { + if (database?.parameters?.ssh) { + return []; + } const parsedErrors = errors .filter((error: { error_type: string }) => { const skipValidationError = ![ diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py index a7ff8622722c1..c2df4b96376a0 100644 --- a/superset/db_engine_specs/base.py +++ b/superset/db_engine_specs/base.py @@ -1888,6 +1888,10 @@ class BasicParametersSchema(Schema): required=False, metadata={"description": __("Use an encrypted connection to the database")}, ) + ssh = fields.Boolean( + required=False, + metadata={"description": __("Use an ssh tunnel connection to the database")}, + ) class BasicParametersType(TypedDict, total=False): From 1afb7cde1dca529161b64dc5744c6cd3ef01c73e Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Tue, 23 May 2023 21:16:57 +0000 Subject: [PATCH 02/15] this works --- .../features/databases/DatabaseModal/index.tsx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/superset-frontend/src/features/databases/DatabaseModal/index.tsx b/superset-frontend/src/features/databases/DatabaseModal/index.tsx index b857f43f7a78e..82b2421de30be 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/index.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/index.tsx @@ -763,15 +763,19 @@ const DatabaseModal: FunctionComponent = ({ }); } - // make sure that button spinner animates - setLoading(true); - const errors = await getValidation(dbToUpdate, true); - if ((validationErrors && !isEmpty(validationErrors)) || errors) { + // only do validation for non ssh tunnel connections + console.log(dbToUpdate); + if (!dbToUpdate?.ssh_tunnel) { + // make sure that button spinner animates + setLoading(true); + const errors = await getValidation(dbToUpdate, true); + if ((validationErrors && !isEmpty(validationErrors)) || errors) { + setLoading(false); + return; + } + // end spinner animation setLoading(false); - return; } - setLoading(false); - // end spinner animation const parameters_schema = isEditMode ? dbToUpdate.parameters_schema?.properties From 79af985a51d997438dc0f30a4d1baa40c5e8d6b7 Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Wed, 24 May 2023 19:05:11 +0000 Subject: [PATCH 03/15] w --- .../DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx index d853b3a5d94bc..d76458f9be9b7 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx @@ -255,7 +255,6 @@ export const SSHTunnelSwitch = ({ isEditMode, changeMethods, db, - setDB, useSSHTunneling, }: FieldPropTypes) => true ? ( From eb7683ab4c12fd0748258acbbb50207c04d3804f Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Wed, 24 May 2023 21:23:05 +0000 Subject: [PATCH 04/15] ok --- .../DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx | 4 ++-- superset-frontend/src/features/databases/types.ts | 1 + superset-frontend/src/types/Database.ts | 1 + superset-frontend/src/views/CRUD/hooks.ts | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx index d76458f9be9b7..7774abcfb5253 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx @@ -17,6 +17,7 @@ * under the License. */ import React from 'react'; +import { isEmpty } from 'lodash'; import { SupersetTheme, t } from '@superset-ui/core'; import { AntdSwitch } from 'src/components'; import InfoTooltip from 'src/components/InfoTooltip'; @@ -255,13 +256,12 @@ export const SSHTunnelSwitch = ({ isEditMode, changeMethods, db, - useSSHTunneling, }: FieldPropTypes) => true ? (
infoTooltip(theme)}> { changeMethods.onParametersChange({ target: { diff --git a/superset-frontend/src/features/databases/types.ts b/superset-frontend/src/features/databases/types.ts index 7b92819fdb77e..a7e4f59b581b9 100644 --- a/superset-frontend/src/features/databases/types.ts +++ b/superset-frontend/src/features/databases/types.ts @@ -69,6 +69,7 @@ export type DatabaseObject = { warehouse?: string; role?: string; account?: string; + ssh?: boolean; }; // Performance diff --git a/superset-frontend/src/types/Database.ts b/superset-frontend/src/types/Database.ts index c4491dbb9943d..0262a2a26834e 100644 --- a/superset-frontend/src/types/Database.ts +++ b/superset-frontend/src/types/Database.ts @@ -27,4 +27,5 @@ export default interface Database { server_cert: string; sqlalchemy_uri: string; catalog: object; + ssh_tunnel: object; } diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index 0363b8d07c2a8..8893499123dbc 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -753,7 +753,7 @@ export function useDatabaseValidation() { .catch(e => { if (typeof e.json === 'function') { return e.json().then(({ errors = [] }: JsonObject) => { - if (database?.parameters?.ssh) { + if (database?.ssh_tunnel) { return []; } const parsedErrors = errors From 9b99dd24a6b99e2ef94740b188db10ae45c33d2b Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Thu, 25 May 2023 03:55:46 +0000 Subject: [PATCH 05/15] fix test --- tests/integration_tests/databases/api_tests.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/integration_tests/databases/api_tests.py b/tests/integration_tests/databases/api_tests.py index a30a951884497..671e6c13eaeb9 100644 --- a/tests/integration_tests/databases/api_tests.py +++ b/tests/integration_tests/databases/api_tests.py @@ -2885,6 +2885,10 @@ def test_available(self, app, get_available_engine_specs): "description": "Additional parameters", "type": "object", }, + "ssh": { + "description": "Use an ssh tunnel connection to the database", + "type": "boolean", + }, "username": { "description": "Username", "nullable": True, From eff48f97a2f55dc9c14e39233c36e76f24807dab Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Thu, 25 May 2023 21:28:21 +0000 Subject: [PATCH 06/15] fix test --- tests/integration_tests/databases/api_tests.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/integration_tests/databases/api_tests.py b/tests/integration_tests/databases/api_tests.py index 671e6c13eaeb9..080fc6ef7ff14 100644 --- a/tests/integration_tests/databases/api_tests.py +++ b/tests/integration_tests/databases/api_tests.py @@ -2964,6 +2964,10 @@ def test_available(self, app, get_available_engine_specs): "description": "Additional parameters", "type": "object", }, + "ssh": { + "description": "Use an ssh tunnel connection to the database", + "type": "boolean", + }, "username": { "description": "Username", "nullable": True, @@ -3039,6 +3043,10 @@ def test_available(self, app, get_available_engine_specs): "description": "Additional parameters", "type": "object", }, + "ssh": { + "description": "Use an ssh tunnel connection to the database", + "type": "boolean", + }, "username": { "description": "Username", "nullable": True, From b4bab39832216be59fce68993981b13338c9071e Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Thu, 25 May 2023 22:10:32 +0000 Subject: [PATCH 07/15] add ssh --- tests/integration_tests/db_engine_specs/postgres_tests.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/integration_tests/db_engine_specs/postgres_tests.py b/tests/integration_tests/db_engine_specs/postgres_tests.py index 44fb1c047402d..c014d7f160e2c 100644 --- a/tests/integration_tests/db_engine_specs/postgres_tests.py +++ b/tests/integration_tests/db_engine_specs/postgres_tests.py @@ -513,6 +513,10 @@ def test_base_parameters_mixin(): "description": "Additional parameters", "additionalProperties": {}, }, + "ssh": { + "description": "Use an ssh tunnel connection to the database", + "type": "boolean", + }, }, "required": ["database", "host", "port", "username"], } From c1ccff2fb18ef4c346ceb8a65eac0ec755400d05 Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Fri, 26 May 2023 19:24:37 +0000 Subject: [PATCH 08/15] update test --- .../src/features/databases/DatabaseModal/index.test.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/superset-frontend/src/features/databases/DatabaseModal/index.test.tsx b/superset-frontend/src/features/databases/DatabaseModal/index.test.tsx index bcff047be345e..385b771efe5e7 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/index.test.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/index.test.tsx @@ -124,6 +124,10 @@ fetchMock.mock(AVAILABLE_DB_ENDPOINT, { description: 'Additional parameters', type: 'object', }, + ssh: { + description: 'Create SSH Tunnel', + type: 'boolean', + }, username: { description: 'Username', nullable: true, From f4fb07b0a75314ab408eaaf3d5537001badfbe88 Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Wed, 21 Jun 2023 15:48:35 +0000 Subject: [PATCH 09/15] remove console log --- .../src/features/databases/DatabaseModal/index.tsx | 1 - superset-frontend/src/types/Database.ts | 1 - superset-frontend/src/views/CRUD/hooks.ts | 7 +++++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/superset-frontend/src/features/databases/DatabaseModal/index.tsx b/superset-frontend/src/features/databases/DatabaseModal/index.tsx index 82b2421de30be..1861cc46ed609 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/index.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/index.tsx @@ -764,7 +764,6 @@ const DatabaseModal: FunctionComponent = ({ } // only do validation for non ssh tunnel connections - console.log(dbToUpdate); if (!dbToUpdate?.ssh_tunnel) { // make sure that button spinner animates setLoading(true); diff --git a/superset-frontend/src/types/Database.ts b/superset-frontend/src/types/Database.ts index 0262a2a26834e..c4491dbb9943d 100644 --- a/superset-frontend/src/types/Database.ts +++ b/superset-frontend/src/types/Database.ts @@ -27,5 +27,4 @@ export default interface Database { server_cert: string; sqlalchemy_uri: string; catalog: object; - ssh_tunnel: object; } diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index 8893499123dbc..9a7c2a478e6f8 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -35,7 +35,8 @@ import Chart, { Slice } from 'src/types/Chart'; import copyTextToClipboard from 'src/utils/copy'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; import SupersetText from 'src/utils/textUtils'; -import { FavoriteStatus, ImportResourceName, DatabaseObject } from './types'; +import { DatabaseObject } from 'src/features/databases/types'; +import { FavoriteStatus, ImportResourceName } from './types'; interface ListViewResourceState { loading: boolean; @@ -753,7 +754,9 @@ export function useDatabaseValidation() { .catch(e => { if (typeof e.json === 'function') { return e.json().then(({ errors = [] }: JsonObject) => { - if (database?.ssh_tunnel) { + if (database?.parameters?.ssh) { + // when ssh tunnel is enabled we don't want to render any validation errors + setValidationErrors([]); return []; } const parsedErrors = errors From 3fc9269eb5cdc4a8d06981a44ecf45c9140d325e Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Wed, 21 Jun 2023 19:24:02 +0000 Subject: [PATCH 10/15] fix cypress --- .../cypress-base/cypress/e2e/database/modal.test.ts | 8 ++++---- superset-frontend/src/views/CRUD/hooks.ts | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/superset-frontend/cypress-base/cypress/e2e/database/modal.test.ts b/superset-frontend/cypress-base/cypress/e2e/database/modal.test.ts index a3260250aa47f..3cc34cb64fb99 100644 --- a/superset-frontend/cypress-base/cypress/e2e/database/modal.test.ts +++ b/superset-frontend/cypress-base/cypress/e2e/database/modal.test.ts @@ -62,8 +62,8 @@ describe('Add database', () => { it('show error alerts on dynamic form for bad host', () => { // click postgres dynamic form cy.get('.preferred > :nth-child(1)').click(); - cy.get('input[name="host"]').focus().type('badhost'); - cy.get('input[name="port"]').focus().type('5432'); + cy.get('input[name="host"]').focus().type('badhost', { force: true }); + cy.get('input[name="port"]').focus().type('5432', { force: true }); cy.get('.ant-form-item-explain-error').contains( "The hostname provided can't be resolved", ); @@ -72,8 +72,8 @@ describe('Add database', () => { it('show error alerts on dynamic form for bad port', () => { // click postgres dynamic form cy.get('.preferred > :nth-child(1)').click(); - cy.get('input[name="host"]').focus().type('localhost'); - cy.get('input[name="port"]').focus().type('123'); + cy.get('input[name="host"]').focus().type('localhost', { force: true }); + cy.get('input[name="port"]').focus().type('123', { force: true }); cy.get('input[name="database"]').focus(); cy.get('.ant-form-item-explain-error').contains('The port is closed'); }); diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index 9a7c2a478e6f8..d142b5eb6d640 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -35,8 +35,7 @@ import Chart, { Slice } from 'src/types/Chart'; import copyTextToClipboard from 'src/utils/copy'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; import SupersetText from 'src/utils/textUtils'; -import { DatabaseObject } from 'src/features/databases/types'; -import { FavoriteStatus, ImportResourceName } from './types'; +import { FavoriteStatus, ImportResourceName, DatabaseObject } from './types'; interface ListViewResourceState { loading: boolean; From 75f6ddf6c2d997f4e0ac171b05ff736a4806ef69 Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Thu, 22 Jun 2023 00:41:11 +0000 Subject: [PATCH 11/15] cleanup --- .../features/databases/DatabaseModal/index.tsx | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/superset-frontend/src/features/databases/DatabaseModal/index.tsx b/superset-frontend/src/features/databases/DatabaseModal/index.tsx index 1861cc46ed609..9196b20dbb952 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/index.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/index.tsx @@ -585,8 +585,6 @@ const DatabaseModal: FunctionComponent = ({ const SSHTunnelSwitchComponent = extensionsRegistry.get('ssh_tunnel.form.switch') ?? SSHTunnelSwitch; - const [useSSHTunneling, setUseSSHTunneling] = useState(false); - let dbConfigExtraExtension = extensionsRegistry.get( 'databaseconnection.extraOption', ); @@ -608,15 +606,6 @@ const DatabaseModal: FunctionComponent = ({ const dbImages = getDatabaseImages(); const connectionAlert = getConnectionAlert(); const isEditMode = !!databaseId; - const disableSSHTunnelingForEngine = ( - availableDbs?.databases?.find( - (DB: DatabaseObject) => - DB.backend === db?.engine || DB.engine === db?.engine, - ) as DatabaseObject - )?.engine_information?.disable_ssh_tunneling; - const isSSHTunneling = - isFeatureEnabled(FeatureFlag.SSH_TUNNELING) && - !disableSSHTunnelingForEngine; const hasAlert = connectionAlert || !!(db?.engine && engineSpecificAlertMapping[db.engine]); const useSqlAlchemyForm = @@ -1277,7 +1266,7 @@ const DatabaseModal: FunctionComponent = ({ }, [sshPrivateKeyPasswordNeeded]); useEffect(() => { - if (db && isSSHTunneling) { + if (db && canSSHTunnel) { setUseSSHTunneling(!isEmpty(db?.ssh_tunnel)); } }, [db, isSSHTunneling]); @@ -1636,7 +1625,7 @@ const DatabaseModal: FunctionComponent = ({ validationErrors={validationErrors} getPlaceholder={getPlaceholder} /> - {db?.parameters?.ssh && ( + {db?.parameters?.ssh && isFeatureEnabled(FeatureFlag.SSH_TUNNELING) && ( {renderSSHTunnelForm()} )} From 66f60242f59747c1a5e98204f2791edb14bbe353 Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Thu, 22 Jun 2023 16:14:00 +0000 Subject: [PATCH 12/15] Revert "cleanup" This reverts commit 75f6ddf6c2d997f4e0ac171b05ff736a4806ef69. --- .../features/databases/DatabaseModal/index.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/superset-frontend/src/features/databases/DatabaseModal/index.tsx b/superset-frontend/src/features/databases/DatabaseModal/index.tsx index 9196b20dbb952..1861cc46ed609 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/index.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/index.tsx @@ -585,6 +585,8 @@ const DatabaseModal: FunctionComponent = ({ const SSHTunnelSwitchComponent = extensionsRegistry.get('ssh_tunnel.form.switch') ?? SSHTunnelSwitch; + const [useSSHTunneling, setUseSSHTunneling] = useState(false); + let dbConfigExtraExtension = extensionsRegistry.get( 'databaseconnection.extraOption', ); @@ -606,6 +608,15 @@ const DatabaseModal: FunctionComponent = ({ const dbImages = getDatabaseImages(); const connectionAlert = getConnectionAlert(); const isEditMode = !!databaseId; + const disableSSHTunnelingForEngine = ( + availableDbs?.databases?.find( + (DB: DatabaseObject) => + DB.backend === db?.engine || DB.engine === db?.engine, + ) as DatabaseObject + )?.engine_information?.disable_ssh_tunneling; + const isSSHTunneling = + isFeatureEnabled(FeatureFlag.SSH_TUNNELING) && + !disableSSHTunnelingForEngine; const hasAlert = connectionAlert || !!(db?.engine && engineSpecificAlertMapping[db.engine]); const useSqlAlchemyForm = @@ -1266,7 +1277,7 @@ const DatabaseModal: FunctionComponent = ({ }, [sshPrivateKeyPasswordNeeded]); useEffect(() => { - if (db && canSSHTunnel) { + if (db && isSSHTunneling) { setUseSSHTunneling(!isEmpty(db?.ssh_tunnel)); } }, [db, isSSHTunneling]); @@ -1625,7 +1636,7 @@ const DatabaseModal: FunctionComponent = ({ validationErrors={validationErrors} getPlaceholder={getPlaceholder} /> - {db?.parameters?.ssh && isFeatureEnabled(FeatureFlag.SSH_TUNNELING) && ( + {db?.parameters?.ssh && ( {renderSSHTunnelForm()} )} From 9e3760a78e632b612a0f47647c2059770e1a3672 Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Thu, 22 Jun 2023 16:29:54 +0000 Subject: [PATCH 13/15] update types for now --- superset-frontend/src/types/Database.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/superset-frontend/src/types/Database.ts b/superset-frontend/src/types/Database.ts index c4491dbb9943d..575d69e2f2be0 100644 --- a/superset-frontend/src/types/Database.ts +++ b/superset-frontend/src/types/Database.ts @@ -27,4 +27,5 @@ export default interface Database { server_cert: string; sqlalchemy_uri: string; catalog: object; + parameters: any; } From 5e843f98ed7197eee7e332612e09d16875cc750d Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Wed, 28 Jun 2023 22:34:27 +0000 Subject: [PATCH 14/15] remove unneeded code --- .../CommonParameters.tsx | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx index 7774abcfb5253..7078b49cbc8d5 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx @@ -256,29 +256,28 @@ export const SSHTunnelSwitch = ({ isEditMode, changeMethods, db, -}: FieldPropTypes) => - true ? ( -
infoTooltip(theme)}> - { - changeMethods.onParametersChange({ - target: { - type: 'toggle', - name: 'ssh', - checked: true, - value: changed, - }, - }); - }} - data-test="ssh-tunnel-switch" - /> - {t('SSH Tunnel')} - -
- ) : null; +}: FieldPropTypes) => ( +
infoTooltip(theme)}> + { + changeMethods.onParametersChange({ + target: { + type: 'toggle', + name: 'ssh', + checked: true, + value: changed, + }, + }); + }} + data-test="ssh-tunnel-switch" + /> + {t('SSH Tunnel')} + +
+); From 5fb76e7357e8a0109f78d6917fa4404a18438f33 Mon Sep 17 00:00:00 2001 From: "Hugh A. Miles II" Date: Thu, 29 Jun 2023 16:13:43 +0000 Subject: [PATCH 15/15] dnt make network calls with ssh enabled --- superset-frontend/src/views/CRUD/hooks.ts | 214 +++++++++++----------- 1 file changed, 109 insertions(+), 105 deletions(-) diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index d142b5eb6d640..b53731754f1fb 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -740,128 +740,132 @@ export function useDatabaseValidation() { null, ); const getValidation = useCallback( - (database: Partial | null, onCreate = false) => - SupersetClient.post({ - endpoint: '/api/v1/database/validate_parameters/', - body: JSON.stringify(transformDB(database)), - headers: { 'Content-Type': 'application/json' }, - }) - .then(() => { - setValidationErrors(null); + (database: Partial | null, onCreate = false) => { + if (database?.parameters?.ssh) { + // when ssh tunnel is enabled we don't want to render any validation errors + setValidationErrors(null); + return []; + } + + return ( + SupersetClient.post({ + endpoint: '/api/v1/database/validate_parameters/', + body: JSON.stringify(transformDB(database)), + headers: { 'Content-Type': 'application/json' }, }) - // eslint-disable-next-line consistent-return - .catch(e => { - if (typeof e.json === 'function') { - return e.json().then(({ errors = [] }: JsonObject) => { - if (database?.parameters?.ssh) { - // when ssh tunnel is enabled we don't want to render any validation errors - setValidationErrors([]); - return []; - } - const parsedErrors = errors - .filter((error: { error_type: string }) => { - const skipValidationError = ![ - 'CONNECTION_MISSING_PARAMETERS_ERROR', - 'CONNECTION_ACCESS_DENIED_ERROR', - ].includes(error.error_type); - return skipValidationError || onCreate; - }) - .reduce( - ( - obj: {}, - { - error_type, - extra, - message, - }: { - error_type: string; - extra: { - invalid?: string[]; - missing?: string[]; - name: string; - catalog: { + .then(() => { + setValidationErrors(null); + }) + // eslint-disable-next-line consistent-return + .catch(e => { + if (typeof e.json === 'function') { + return e.json().then(({ errors = [] }: JsonObject) => { + const parsedErrors = errors + .filter((error: { error_type: string }) => { + const skipValidationError = ![ + 'CONNECTION_MISSING_PARAMETERS_ERROR', + 'CONNECTION_ACCESS_DENIED_ERROR', + ].includes(error.error_type); + return skipValidationError || onCreate; + }) + .reduce( + ( + obj: {}, + { + error_type, + extra, + message, + }: { + error_type: string; + extra: { + invalid?: string[]; + missing?: string[]; name: string; - url: string; - idx: number; + catalog: { + name: string; + url: string; + idx: number; + }; + issue_codes?: { + code?: number; + message?: string; + }[]; }; - issue_codes?: { - code?: number; - message?: string; - }[]; - }; - message: string; - }, - ) => { - if (extra.catalog) { - if (extra.catalog.name) { + message: string; + }, + ) => { + if (extra.catalog) { + if (extra.catalog.name) { + return { + ...obj, + error_type, + [extra.catalog.idx]: { + name: message, + }, + }; + } + if (extra.catalog.url) { + return { + ...obj, + error_type, + [extra.catalog.idx]: { + url: message, + }, + }; + } + return { ...obj, error_type, [extra.catalog.idx]: { name: message, + url: message, }, }; } - if (extra.catalog.url) { + // if extra.invalid doesn't exist then the + // error can't be mapped to a parameter + // so leave it alone + if (extra.invalid) { return { ...obj, + [extra.invalid[0]]: message, error_type, - [extra.catalog.idx]: { - url: message, - }, + }; + } + if (extra.missing) { + return { + ...obj, + error_type, + ...Object.assign( + {}, + ...extra.missing.map(field => ({ + [field]: 'This is a required field', + })), + ), + }; + } + if (extra.issue_codes?.length) { + return { + ...obj, + error_type, + description: message || extra.issue_codes[0]?.message, }; } - return { - ...obj, - error_type, - [extra.catalog.idx]: { - name: message, - url: message, - }, - }; - } - // if extra.invalid doesn't exist then the - // error can't be mapped to a parameter - // so leave it alone - if (extra.invalid) { - return { - ...obj, - [extra.invalid[0]]: message, - error_type, - }; - } - if (extra.missing) { - return { - ...obj, - error_type, - ...Object.assign( - {}, - ...extra.missing.map(field => ({ - [field]: 'This is a required field', - })), - ), - }; - } - if (extra.issue_codes?.length) { - return { - ...obj, - error_type, - description: message || extra.issue_codes[0]?.message, - }; - } - - return obj; - }, - {}, - ); - setValidationErrors(parsedErrors); - return parsedErrors; - }); - } - // eslint-disable-next-line no-console - console.error(e); - }), + return obj; + }, + {}, + ); + setValidationErrors(parsedErrors); + return parsedErrors; + }); + } + // eslint-disable-next-line no-console + console.error(e); + }) + ); + }, [setValidationErrors], );