mirror of
https://github.com/apache/superset.git
synced 2026-06-01 05:39:17 +00:00
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:
@@ -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>
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -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`
|
||||
|
||||
Reference in New Issue
Block a user