Skip to content

Commit

Permalink
feat: add databricks form (#21573)
Browse files Browse the repository at this point in the history
  • Loading branch information
eschutho committed Dec 2, 2022
1 parent df91664 commit 5c77f1a
Show file tree
Hide file tree
Showing 10 changed files with 685 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,29 @@ export const portField = ({
/>
</>
);
export const httpPath = ({
required,
changeMethods,
getValidation,
validationErrors,
db,
}: FieldPropTypes) => {
const extraJson = JSON.parse(db?.extra || '{}');
return (
<ValidatedInput
id="http_path"
name="http_path"
required={required}
value={extraJson.engine_params?.connect_args?.http_path}
validationMethods={{ onBlur: getValidation }}
errorMessage={validationErrors?.http_path}
placeholder={t('e.g. sql/protocolv1/o/12345')}
label="HTTP Path"
onChange={changeMethods.onExtraInputChange}
helpText={t('Copy the name of the HTTP Path of your cluster.')}
/>
);
};
export const databaseField = ({
required,
changeMethods,
Expand Down Expand Up @@ -132,6 +155,27 @@ export const passwordField = ({
onChange={changeMethods.onParametersChange}
/>
);
export const accessTokenField = ({
required,
changeMethods,
getValidation,
validationErrors,
db,
isEditMode,
}: FieldPropTypes) => (
<ValidatedInput
id="access_token"
name="access_token"
required={required}
visibilityToggle={!isEditMode}
value={db?.parameters?.access_token}
validationMethods={{ onBlur: getValidation }}
errorMessage={validationErrors?.access_token}
placeholder={t('e.g. ********')}
label={t('Access token')}
onChange={changeMethods.onParametersChange}
/>
);
export const displayField = ({
changeMethods,
getValidation,
Expand All @@ -150,7 +194,7 @@ export const displayField = ({
label={t('Display Name')}
onChange={changeMethods.onChange}
helpText={t(
'Pick a nickname for this database to display as in Superset.',
'Pick a nickname for how the database will display in Superset.',
)}
/>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
import React, { FormEvent } from 'react';
import React, { FormEvent, useEffect } from 'react';
import { SupersetTheme, JsonObject } from '@superset-ui/core';
import { InputProps } from 'antd/lib/input';
import { Form } from 'src/components/Form';
import {
hostField,
portField,
accessTokenField,
databaseField,
usernameField,
passwordField,
displayField,
queryField,
forceSSLField,
hostField,
httpPath,
passwordField,
portField,
queryField,
usernameField,
} from './CommonParameters';
import { validatedInputField } from './ValidatedInputField';
import { EncryptedField } from './EncryptedField';
Expand All @@ -42,6 +44,8 @@ export const FormFieldOrder = [
'database',
'username',
'password',
'access_token',
'http_path',
'database_name',
'credentials_info',
'service_account_info',
Expand All @@ -67,6 +71,8 @@ export interface FieldPropTypes {
} & { onParametersUploadFileChange: (value: any) => string } & {
onAddTableCatalog: () => void;
onRemoveTableCatalog: (idx: number) => void;
} & {
onExtraInputChange: (value: any) => void;
};
validationErrors: JsonObject | null;
getValidation: () => void;
Expand All @@ -80,10 +86,12 @@ export interface FieldPropTypes {

const FORM_FIELD_MAP = {
host: hostField,
http_path: httpPath,
port: portField,
database: databaseField,
username: usernameField,
password: passwordField,
access_token: accessTokenField,
database_name: displayField,
query: queryField,
encryption: forceSSLField,
Expand All @@ -96,20 +104,22 @@ const FORM_FIELD_MAP = {
};

const DatabaseConnectionForm = ({
dbModel: { parameters },
onParametersChange,
dbModel: { parameters, default_driver },
db,
editNewDb,
getPlaceholder,
getValidation,
isEditMode = false,
onAddTableCatalog,
onChange,
onQueryChange,
onExtraInputChange,
onParametersChange,
onParametersUploadFileChange,
onAddTableCatalog,
onQueryChange,
onRemoveTableCatalog,
validationErrors,
getValidation,
db,
isEditMode = false,
setDatabaseDriver,
sslForced,
editNewDb,
getPlaceholder,
validationErrors,
}: {
isEditMode?: boolean;
sslForced: boolean;
Expand All @@ -128,50 +138,60 @@ const DatabaseConnectionForm = ({
onParametersUploadFileChange?: (
event: FormEvent<InputProps> | { target: HTMLInputElement },
) => void;
onExtraInputChange: (
event: FormEvent<InputProps> | { target: HTMLInputElement },
) => void;
onAddTableCatalog: () => void;
onRemoveTableCatalog: (idx: number) => void;
validationErrors: JsonObject | null;
getValidation: () => void;
getPlaceholder?: (field: string) => string | undefined;
}) => (
<Form>
<div
// @ts-ignore
css={(theme: SupersetTheme) => [
formScrollableStyles,
validatedFormStyles(theme),
]}
>
{parameters &&
FormFieldOrder.filter(
(key: string) =>
Object.keys(parameters.properties).includes(key) ||
key === 'database_name',
).map(field =>
FORM_FIELD_MAP[field]({
required: parameters.required?.includes(field),
changeMethods: {
onParametersChange,
onChange,
onQueryChange,
onParametersUploadFileChange,
onAddTableCatalog,
onRemoveTableCatalog,
},
validationErrors,
getValidation,
db,
key: field,
field,
isEditMode,
sslForced,
editNewDb,
placeholder: getPlaceholder ? getPlaceholder(field) : undefined,
}),
)}
</div>
</Form>
);
setDatabaseDriver: (driver: string) => void;
}) => {
useEffect(() => {
setDatabaseDriver(default_driver);
}, [default_driver]);
return (
<Form>
<div
// @ts-ignore
css={(theme: SupersetTheme) => [
formScrollableStyles,
validatedFormStyles(theme),
]}
>
{parameters &&
FormFieldOrder.filter(
(key: string) =>
Object.keys(parameters.properties).includes(key) ||
key === 'database_name',
).map(field =>
FORM_FIELD_MAP[field]({
required: parameters.required?.includes(field),
changeMethods: {
onParametersChange,
onChange,
onQueryChange,
onParametersUploadFileChange,
onAddTableCatalog,
onRemoveTableCatalog,
onExtraInputChange,
},
validationErrors,
getValidation,
db,
key: field,
field,
isEditMode,
sslForced,
editNewDb,
placeholder: getPlaceholder ? getPlaceholder(field) : undefined,
}),
)}
</div>
</Form>
);
};
export const FormFieldMap = FORM_FIELD_MAP;

export default DatabaseConnectionForm;
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ const SqlAlchemyTab = ({
</StyledInputContainer>
<Button
onClick={testConnection}
disabled={testInProgress}
loading={testInProgress}
cta
buttonStyle="link"
css={(theme: SupersetTheme) => wideButton(theme)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,37 @@ fetchMock.mock(AVAILABLE_DB_ENDPOINT, {
supports_file_upload: false,
},
},
{
available_drivers: ['connector'],
default_driver: 'connector',
engine: 'databricks',
name: 'Databricks',
parameters: {
properties: {
access_token: {
type: 'string',
},
database: {
type: 'string',
},
host: {
type: 'string',
},
http_path: {
type: 'string',
},
port: {
format: 'int32',
type: 'integer',
},
},
required: ['access_token', 'database', 'host', 'http_path', 'port'],
type: 'object',
},
preferred: true,
sqlalchemy_uri_placeholder:
'databricks+connector://token:{access_token}@{host}:{port}/{database_name}',
},
],
});
fetchMock.post(VALIDATE_PARAMS_ENDPOINT, {
Expand All @@ -238,6 +269,7 @@ const databaseFixture: DatabaseObject = {
database_name: 'Postgres',
name: 'PostgresDB',
is_managed_externally: false,
driver: 'psycopg2',
};

describe('DatabaseModal', () => {
Expand Down Expand Up @@ -355,8 +387,9 @@ describe('DatabaseModal', () => {
});
// there should be a footer but it should not have any buttons in it
expect(footer[0]).toBeEmptyDOMElement();

// This is how many preferred databases are rendered
expect(preferredDbIcon).toHaveLength(4);
expect(preferredDbIcon).toHaveLength(5);
});

test('renders the "Basic" tab of SQL Alchemy form (step 2 of 2) correctly', async () => {
Expand Down
Loading

0 comments on commit 5c77f1a

Please sign in to comment.