feat: database extension registry (#23174)

Co-authored-by: Elizabeth Thompson <eschutho@gmail.com>
Co-authored-by: Lily Kuang <lily@preset.io>
This commit is contained in:
Beto Dealmeida
2023-05-18 17:00:06 -07:00
committed by GitHub
parent e856e35c53
commit 6b5459121f
7 changed files with 185 additions and 18 deletions

View File

@@ -18,7 +18,11 @@
*/
import React, { ChangeEvent, EventHandler } from 'react';
import cx from 'classnames';
import { t, SupersetTheme } from '@superset-ui/core';
import {
t,
SupersetTheme,
DatabaseConnectionExtension,
} from '@superset-ui/core';
import InfoTooltip from 'src/components/InfoTooltip';
import IndeterminateCheckbox from 'src/components/IndeterminateCheckbox';
import Collapse from 'src/components/Collapse';
@@ -38,6 +42,7 @@ const ExtraOptions = ({
onEditorChange,
onExtraInputChange,
onExtraEditorChange,
extraExtension,
}: {
db: DatabaseObject | null;
onInputChange: EventHandler<ChangeEvent<HTMLInputElement>>;
@@ -45,6 +50,7 @@ const ExtraOptions = ({
onEditorChange: Function;
onExtraInputChange: EventHandler<ChangeEvent<HTMLInputElement>>;
onExtraEditorChange: Function;
extraExtension: DatabaseConnectionExtension | undefined;
}) => {
const expandableModalIsOpen = !!db?.expose_in_sqllab;
const createAsOpen = !!(db?.allow_ctas || db?.allow_cvas);
@@ -61,6 +67,10 @@ const ExtraOptions = ({
return value;
});
const ExtraExtensionComponent = extraExtension?.component;
const ExtraExtensionLogo = extraExtension?.logo;
const ExtensionDescription = extraExtension?.description;
return (
<Collapse
expandIconPosition="right"
@@ -437,6 +447,32 @@ const ExtraOptions = ({
</StyledInputContainer>
)}
</Collapse.Panel>
{extraExtension && ExtraExtensionComponent && ExtensionDescription && (
<Collapse.Panel
header={
<div>
{ExtraExtensionLogo && <ExtraExtensionLogo />}
<span
css={(theme: SupersetTheme) => ({
fontSize: theme.typography.sizes.l,
fontWeight: theme.typography.weights.bold,
})}
>
{extraExtension?.title}
</span>
<p className="helper">
<ExtensionDescription />
</p>
</div>
}
key={extraExtension?.title}
collapsible={extraExtension.enabled?.() ? 'header' : 'disabled'}
>
<StyledInputContainer css={no_margin_bottom}>
<ExtraExtensionComponent db={db} onEdit={extraExtension.onEdit} />
</StyledInputContainer>
</Collapse.Panel>
)}
<Collapse.Panel
header={
<div>

View File

@@ -578,12 +578,31 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
sshTunnelPrivateKeyPasswordFields,
setSSHTunnelPrivateKeyPasswordFields,
] = useState<string[]>([]);
const [extraExtensionComponentState, setExtraExtensionComponentState] =
useState<object>({});
const SSHTunnelSwitchComponent =
extensionsRegistry.get('ssh_tunnel.form.switch') ?? SSHTunnelSwitch;
const [useSSHTunneling, setUseSSHTunneling] = useState<boolean>(false);
let dbConfigExtraExtension = extensionsRegistry.get(
'databaseconnection.extraOption',
);
if (dbConfigExtraExtension) {
// add method for db modal to store data
dbConfigExtraExtension = {
...dbConfigExtraExtension,
onEdit: componentState => {
setExtraExtensionComponentState({
...extraExtensionComponentState,
...componentState,
});
},
};
}
const conf = useCommonConf();
const dbImages = getDatabaseImages();
const connectionAlert = getConnectionAlert();
@@ -715,6 +734,19 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
};
const onSave = async () => {
let dbConfigExtraExtensionOnSaveError;
dbConfigExtraExtension
?.onSave(extraExtensionComponentState, db)
.then(({ error }: { error: any }) => {
if (error) {
dbConfigExtraExtensionOnSaveError = error;
addDangerToast(error);
}
});
if (dbConfigExtraExtensionOnSaveError) {
setLoading(false);
return;
}
// Clone DB object
const dbToUpdate = { ...(db || {}) };
@@ -803,6 +835,18 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
);
if (result) {
if (onDatabaseAdd) onDatabaseAdd();
dbConfigExtraExtension
?.onSave(extraExtensionComponentState, db)
.then(({ error }: { error: any }) => {
if (error) {
dbConfigExtraExtensionOnSaveError = error;
addDangerToast(error);
}
});
if (dbConfigExtraExtensionOnSaveError) {
setLoading(false);
return;
}
if (!editNewDb) {
onClose();
addSuccessToast(t('Database settings updated'));
@@ -817,6 +861,19 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
if (dbId) {
setHasConnectedDb(true);
if (onDatabaseAdd) onDatabaseAdd();
dbConfigExtraExtension
?.onSave(extraExtensionComponentState, db)
.then(({ error }: { error: any }) => {
if (error) {
dbConfigExtraExtensionOnSaveError = error;
addDangerToast(error);
}
});
if (dbConfigExtraExtensionOnSaveError) {
setLoading(false);
return;
}
if (useTabLayout) {
// tab layout only has one step
// so it should close immediately on save
@@ -1596,6 +1653,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
if (!editNewDb) {
return (
<ExtraOptions
extraExtension={dbConfigExtraExtension}
db={db as DatabaseObject}
onInputChange={({ target }: { target: HTMLInputElement }) =>
onChange(ActionType.inputChange, {
@@ -1807,6 +1865,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
</Tabs.TabPane>
<Tabs.TabPane tab={<span>{t('Advanced')}</span>} key="2">
<ExtraOptions
extraExtension={dbConfigExtraExtension}
db={db as DatabaseObject}
onInputChange={({ target }: { target: HTMLInputElement }) =>
onChange(ActionType.inputChange, {

View File

@@ -573,6 +573,7 @@ export const StyledStickyHeader = styled.div`
top: 0;
z-index: ${({ theme }) => theme.zIndex.max};
background: ${({ theme }) => theme.colors.grayscale.light5};
height: auto;
`;
export const StyledCatalogTable = styled.div`