Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Private Google Sheets to dynamic form #16628

Merged
merged 9 commits into from
Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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