From 08886ab52aad250b82e532073b12eaf27e07ae83 Mon Sep 17 00:00:00 2001 From: Arash Date: Tue, 7 Sep 2021 20:11:45 -0400 Subject: [PATCH 1/9] first pass private gsheets --- .../DatabaseModal/DatabaseConnectionForm.tsx | 171 +++++++++++------- .../data/database/DatabaseModal/index.tsx | 7 +- .../data/database/DatabaseModal/styles.ts | 12 +- superset/databases/api.py | 2 - 4 files changed, 117 insertions(+), 75 deletions(-) diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm.tsx index e2a3f0338daae..6a2079d49df20 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm.tsx @@ -32,6 +32,7 @@ import { infoTooltip, StyledFooterButton, StyledCatalogTable, + labelMarginBotton, } from './styles'; import { CatalogObject, DatabaseForm, DatabaseObject } from '../types'; @@ -40,6 +41,13 @@ enum CredentialInfoOptions { copyPaste, } +const setStringToBoolean = (optionValue: string) => { + if (optionValue === 'true') { + return true; + } + return false; +}; + export const FormFieldOrder = [ 'host', 'port', @@ -56,7 +64,7 @@ export const FormFieldOrder = [ interface FieldPropTypes { required: boolean; hasTooltip?: boolean; - tooltipText?: (valuse: any) => string; + tooltipText?: (value: any) => string; onParametersChange: (value: any) => string; onParametersUploadFileChange: (value: any) => string; changeMethods: { onParametersChange: (value: any) => string } & { @@ -88,9 +96,35 @@ const CredentialsInfo = ({ const [fileToUpload, setFileToUpload] = useState( null, ); + const [isPublic, setIsPublic] = useState(true); + const showCredentialsInfo = + db?.engine === 'gsheets' ? !isEditMode && !isPublic : !isEditMode; + return ( - {!isEditMode && ( + {db?.engine === 'gsheets' && ( +
+ labelMarginBotton(theme)} + required + > + {t('Type of Google Sheets Allowed')} + + +
+ )} + {showCredentialsInfo && ( <> {t('How do you want to enter service account credentials?')} @@ -127,69 +161,73 @@ const CredentialsInfo = ({ ) : ( -
infoTooltip(theme)} - > -
- {t('Upload Credentials')} - -
- - {!fileToUpload && ( - - )} - {fileToUpload && ( -
- {fileToUpload} - { - setFileToUpload(null); - changeMethods.onParametersChange({ - target: { - name: 'credentials_info', - value: '', - }, - }); - }} + showCredentialsInfo && ( +
infoTooltip(theme)} + > +
+ {t('Upload Credentials')} +
- )} - { - let file; - if (event.target.files) { - file = event.target.files[0]; - } - setFileToUpload(file?.name); - changeMethods.onParametersChange({ - target: { - type: null, - name: 'credentials_info', - value: await file?.text(), - checked: false, - }, - }); - (document.getElementById( - 'selectedFile', - ) as HTMLInputElement).value = null as any; - }} - /> -
+ {!fileToUpload && ( + + )} + {fileToUpload && ( +
+ {fileToUpload} + { + setFileToUpload(null); + changeMethods.onParametersChange({ + target: { + name: 'credentials_info', + value: '', + }, + }); + }} + /> +
+ )} + + { + let file; + if (event.target.files) { + file = event.target.files[0]; + } + setFileToUpload(file?.name); + changeMethods.onParametersChange({ + target: { + type: null, + name: 'credentials_info', + value: await file?.text(), + checked: false, + }, + }); + (document.getElementById( + 'selectedFile', + ) as HTMLInputElement).value = null as any; + }} + /> +
+ ) )} ); @@ -204,16 +242,9 @@ const TableCatalog = ({ }: FieldPropTypes) => { const tableCatalog = db?.catalog || []; const catalogError = validationErrors || {}; + return ( -
- {t('Type of Google Sheets Allowed')} - -

{t('Connect Google Sheets as tables to this database')}

diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx index 1cb3082680537..fa41e73293991 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx @@ -180,6 +180,7 @@ type DBReducerActionType = database_name?: string; engine?: string; configuration_method: CONFIGURATION_METHOD; + parameters?: Record; }; } | { @@ -513,7 +514,6 @@ const DatabaseModal: FunctionComponent = ({ encrypted_extra: db?.encrypted_extra || '', server_cert: db?.server_cert || undefined, }; - testDatabaseConnection(connection, addDangerToast, addSuccessToast); }; @@ -541,6 +541,7 @@ const DatabaseModal: FunctionComponent = ({ } const engine = dbToUpdate.backend || dbToUpdate.engine; + console.log('this is', dbModel); if (engine === 'bigquery' && dbToUpdate.parameters?.credentials_info) { // wrap encrypted_extra in credentials_info only for BigQuery if ( @@ -654,6 +655,7 @@ const DatabaseModal: FunctionComponent = ({ const selectedDbModel = availableDbs?.databases.filter( (db: DatabaseObject) => db.name === database_name, )[0]; + console.log(selectedDbModel); const { engine, parameters } = selectedDbModel; const isDynamic = parameters !== undefined; setDB({ @@ -664,6 +666,7 @@ const DatabaseModal: FunctionComponent = ({ ? CONFIGURATION_METHOD.DYNAMIC_FORM : CONFIGURATION_METHOD.SQLALCHEMY_URI, engine, + parameters, }, }); } @@ -738,6 +741,8 @@ const DatabaseModal: FunctionComponent = ({
); + console.log(db); + const renderPreferredSelector = () => (
{availableDbs?.databases diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts index 364ee971e12dc..af66ba24b15bc 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts @@ -31,6 +31,10 @@ export const no_margin_bottom = css` margin-bottom: 0; `; +export const labelMarginBotton = (theme: SupersetTheme) => css` + margin-bottom: ${theme.gridUnit * 2}px; +`; + export const marginBottom = (theme: SupersetTheme) => css` margin-bottom: ${theme.gridUnit * 4}px; `; @@ -442,6 +446,10 @@ export const EditHeaderSubtitle = styled.div` `; export const CredentialInfoForm = styled.div` + .catalog-type-select { + margin: 0 0 20px; + } + .label-select { text-transform: uppercase; color: ${({ theme }) => theme.colors.grayscale.dark1}; @@ -542,13 +550,13 @@ export const StyledCatalogTable = styled.div` margin-bottom: 16px; .catalog-type-select { - margin: 0 0 40px; + margin: 0 0 20px; } .gsheet-title { font-size: ${({ theme }) => theme.typography.sizes.l * 1.1}px; font-weight: bold; - margin: ${({ theme }) => theme.gridUnit * 6}px 0 16px; + margin: ${({ theme }) => theme.gridUnit * 10}px 0 16px; } .catalog-label { diff --git a/superset/databases/api.py b/superset/databases/api.py index 8ed2d073545b8..b2729ea6e8ef3 100644 --- a/superset/databases/api.py +++ b/superset/databases/api.py @@ -920,7 +920,6 @@ def available(self) -> Response: for engine_spec, drivers in get_available_engine_specs().items(): if not drivers: continue - payload: Dict[str, Any] = { "name": engine_spec.engine_name, "engine": engine_spec.engine, @@ -943,7 +942,6 @@ def available(self) -> Response: payload[ "sqlalchemy_uri_placeholder" ] = engine_spec.sqlalchemy_uri_placeholder # type: ignore - available_databases.append(payload) # sort preferred first From ae0c4debe566d867389135f20cb6caa9d6762b5d Mon Sep 17 00:00:00 2001 From: Arash Date: Wed, 15 Sep 2021 16:46:55 -0400 Subject: [PATCH 2/9] made encrypted extra into string, refactored onParametersChanged --- .../DatabaseModal/DatabaseConnectionForm.tsx | 27 ++++- .../data/database/DatabaseModal/index.tsx | 107 ++++++++---------- .../src/views/CRUD/data/database/types.ts | 9 +- superset/databases/schemas.py | 14 ++- superset/db_engine_specs/bigquery.py | 18 +-- superset/db_engine_specs/gsheets.py | 20 +++- superset/models/core.py | 7 +- 7 files changed, 119 insertions(+), 83 deletions(-) diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm.tsx index 6a2079d49df20..2b78fb13a54c1 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm.tsx @@ -36,6 +36,14 @@ import { } from './styles'; import { CatalogObject, DatabaseForm, DatabaseObject } from '../types'; +// These are the columns that are going to be added to encrypted extra, they differ in name based +// on the engine, however we want to use the same component for each of them. Make sure to add the +// the engine specific name here. +export const encryptedCredentialsMap = { + gsheets: 'service_account_info', + bigquery: 'credentials_info', +}; + enum CredentialInfoOptions { jsonUpload, copyPaste, @@ -56,6 +64,7 @@ export const FormFieldOrder = [ 'password', 'database_name', 'credentials_info', + 'service_account_info', 'catalog', 'query', 'encryption', @@ -99,7 +108,12 @@ const CredentialsInfo = ({ const [isPublic, setIsPublic] = useState(true); const showCredentialsInfo = db?.engine === 'gsheets' ? !isEditMode && !isPublic : !isEditMode; - + const isEncrypted = db?.encrypted_extra?.length; + const encryptedField = db?.engine && encryptedCredentialsMap[db.engine]; + const encryptedValue = + typeof db?.parameters?.[encryptedField] === 'object' + ? JSON.stringify(db?.parameters?.[encryptedField]) + : db?.parameters?.[encryptedField]; return ( {db?.engine === 'gsheets' && ( @@ -112,7 +126,7 @@ const CredentialsInfo = ({