Skip to content

Commit

Permalink
feat: Add Private Google Sheets to dynamic form (#16628)
Browse files Browse the repository at this point in the history
* first pass private gsheets

* made encrypted extra into string, refactored onParametersChanged

* private sheets working, credential_info errors

* all but test connection working

* first pass private gsheets

* made encrypted extra into string, refactored onParametersChanged

* private sheets working, credential_info errors

* all but test connection working

* Regenerate package-lock.json

Co-authored-by: Beto Dealmeida <roberto@dealmeida.net>
  • Loading branch information
AAfghahi and betodealmeida authored Sep 29, 2021
1 parent b35645c commit aa74721
Show file tree
Hide file tree
Showing 12 changed files with 4,123 additions and 42,863 deletions.
46,606 changes: 3,888 additions & 42,718 deletions superset-frontend/package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,25 @@ import {
infoTooltip,
StyledFooterButton,
StyledCatalogTable,
labelMarginBotton,
} 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,
}

const castStringToBoolean = (optionValue: string) => optionValue === 'true';

export const FormFieldOrder = [
'host',
'port',
Expand All @@ -48,6 +59,7 @@ export const FormFieldOrder = [
'password',
'database_name',
'credentials_info',
'service_account_info',
'catalog',
'query',
'encryption',
Expand All @@ -56,7 +68,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 } & {
Expand Down Expand Up @@ -88,12 +100,46 @@ const CredentialsInfo = ({
const [fileToUpload, setFileToUpload] = useState<string | null | undefined>(
null,
);
const [isPublic, setIsPublic] = useState<boolean>(true);
const showCredentialsInfo =
db?.engine === 'gsheets' ? !isEditMode && !isPublic : !isEditMode;
// a database that has an optional encrypted field has an encrypted_extra that is an empty object, this checks for that.
const isEncrypted = isEditMode && db?.encrypted_extra !== '{}';
const encryptedField = db?.engine && encryptedCredentialsMap[db.engine];
const encryptedValue =
typeof db?.parameters?.[encryptedField] === 'object'
? JSON.stringify(db?.parameters?.[encryptedField])
: db?.parameters?.[encryptedField];
return (
<CredentialInfoForm>
{!isEditMode && (
{db?.engine === 'gsheets' && (
<div className="catalog-type-select">
<FormLabel
css={(theme: SupersetTheme) => labelMarginBotton(theme)}
required
>
{t('Type of Google Sheets allowed')}
</FormLabel>
<Select
style={{ width: '100%' }}
defaultValue={isEncrypted ? 'false' : 'true'}
onChange={(value: string) =>
setIsPublic(castStringToBoolean(value))
}
>
<Select.Option value="true" key={1}>
{t('Publicly shared sheets only')}
</Select.Option>
<Select.Option value="false" key={2}>
{t('Public and privately shared sheets')}
</Select.Option>
</Select>
</div>
)}
{showCredentialsInfo && (
<>
<FormLabel required>
{t('How do you want to enter service account credentials?')}
{t('How do you want to enter service account credentials?')}
</FormLabel>
<Select
defaultValue={uploadOption}
Expand All @@ -117,8 +163,8 @@ const CredentialsInfo = ({
<FormLabel required>{t('Service Account')}</FormLabel>
<textarea
className="input-form"
name="credentials_info"
value={db?.parameters?.credentials_info}
name={encryptedField}
value={encryptedValue}
onChange={changeMethods.onParametersChange}
placeholder="Paste content of service credentials JSON file here"
/>
Expand All @@ -127,69 +173,73 @@ const CredentialsInfo = ({
</span>
</div>
) : (
<div
className="input-container"
css={(theme: SupersetTheme) => infoTooltip(theme)}
>
<div css={{ display: 'flex', alignItems: 'center' }}>
<FormLabel required>{t('Upload Credentials')}</FormLabel>
<InfoTooltip
tooltip={t(
'Use the JSON file you automatically downloaded when creating your service account in Google BigQuery.',
)}
viewBox="0 0 24 24"
/>
</div>

{!fileToUpload && (
<Button
className="input-upload-btn"
onClick={() => document?.getElementById('selectedFile')?.click()}
>
{t('Choose File')}
</Button>
)}
{fileToUpload && (
<div className="input-upload-current">
{fileToUpload}
<DeleteFilled
onClick={() => {
setFileToUpload(null);
changeMethods.onParametersChange({
target: {
name: 'credentials_info',
value: '',
},
});
}}
showCredentialsInfo && (
<div
className="input-container"
css={(theme: SupersetTheme) => infoTooltip(theme)}
>
<div css={{ display: 'flex', alignItems: 'center' }}>
<FormLabel required>{t('Upload Credentials')}</FormLabel>
<InfoTooltip
tooltip={t(
'Use the JSON file you automatically downloaded when creating your service account.',
)}
viewBox="0 0 24 24"
/>
</div>
)}

<input
id="selectedFile"
className="input-upload"
type="file"
onChange={async event => {
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;
}}
/>
</div>
{!fileToUpload && (
<Button
className="input-upload-btn"
onClick={() =>
document?.getElementById('selectedFile')?.click()
}
>
{t('Choose File')}
</Button>
)}
{fileToUpload && (
<div className="input-upload-current">
{fileToUpload}
<DeleteFilled
onClick={() => {
setFileToUpload(null);
changeMethods.onParametersChange({
target: {
name: encryptedField,
value: '',
},
});
}}
/>
</div>
)}

<input
id="selectedFile"
className="input-upload"
type="file"
onChange={async event => {
let file;
if (event.target.files) {
file = event.target.files[0];
}
setFileToUpload(file?.name);
changeMethods.onParametersChange({
target: {
type: null,
name: encryptedField,
value: await file?.text(),
checked: false,
},
});
(document.getElementById(
'selectedFile',
) as HTMLInputElement).value = null as any;
}}
/>
</div>
)
)}
</CredentialInfoForm>
);
Expand All @@ -204,16 +254,9 @@ const TableCatalog = ({
}: FieldPropTypes) => {
const tableCatalog = db?.catalog || [];
const catalogError = validationErrors || {};

return (
<StyledCatalogTable>
<div className="catalog-type-select">
<FormLabel required>{t('Type of Google Sheets Allowed')}</FormLabel>
<Select style={{ width: '100%' }} defaultValue="true" disabled>
<Select.Option value="true" key={1}>
{t('Publicly shared sheets only')}
</Select.Option>
</Select>
</div>
<h4 className="gsheet-title">
{t('Connect Google Sheets as tables to this database')}
</h4>
Expand Down Expand Up @@ -472,6 +515,7 @@ const FORM_FIELD_MAP = {
query: queryField,
encryption: forceSSLField,
credentials_info: CredentialsInfo,
service_account_info: CredentialsInfo,
catalog: TableCatalog,
};

Expand Down
Loading

0 comments on commit aa74721

Please sign in to comment.