From 2820627f2ddae4d67c2f5ce79531f805fce45ed1 Mon Sep 17 00:00:00 2001
From: lyndsiWilliams
Date: Tue, 22 Mar 2022 12:57:01 -0500
Subject: [PATCH 01/35] rebase
---
.../CRUD/data/database/DatabaseList.test.jsx | 45 --------
.../views/CRUD/data/database/DatabaseList.tsx | 57 ----------
.../database/DatabaseModal/ModalHeader.tsx | 37 ++++--
.../data/database/DatabaseModal/index.tsx | 105 +++++++++++++++++-
4 files changed, 129 insertions(+), 115 deletions(-)
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx b/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx
index 12580d8ee73fa..47f4907f48527 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx
@@ -23,10 +23,6 @@ import configureStore from 'redux-mock-store';
import fetchMock from 'fetch-mock';
import { Provider } from 'react-redux';
import { styledMount as mount } from 'spec/helpers/theming';
-import { render, screen, cleanup } from 'spec/helpers/testing-library';
-import userEvent from '@testing-library/user-event';
-import { QueryParamProvider } from 'use-query-params';
-import * as featureFlags from 'src/featureFlags';
import DatabaseList from 'src/views/CRUD/data/database/DatabaseList';
import DatabaseModal from 'src/views/CRUD/data/database/DatabaseModal';
@@ -208,44 +204,3 @@ describe('DatabaseList', () => {
);
});
});
-
-describe('RTL', () => {
- async function renderAndWait() {
- const mounted = act(async () => {
- render(
-
-
- ,
- { useRedux: true },
- mockAppState,
- );
- });
-
- return mounted;
- }
-
- let isFeatureEnabledMock;
- beforeEach(async () => {
- isFeatureEnabledMock = jest
- .spyOn(featureFlags, 'isFeatureEnabled')
- .mockImplementation(() => true);
- await renderAndWait();
- });
-
- afterEach(() => {
- cleanup();
- isFeatureEnabledMock.mockRestore();
- });
-
- it('renders an "Import Database" tooltip under import button', async () => {
- const importButton = await screen.findByTestId('import-button');
- userEvent.hover(importButton);
-
- await screen.findByRole('tooltip');
- const importTooltip = screen.getByRole('tooltip', {
- name: 'Import databases',
- });
-
- expect(importTooltip).toBeInTheDocument();
- });
-});
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx
index 10149bc9e8a16..f980295cc2035 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx
@@ -30,7 +30,6 @@ import { Tooltip } from 'src/components/Tooltip';
import Icons from 'src/components/Icons';
import ListView, { FilterOperator, Filters } from 'src/components/ListView';
import { commonMenuData } from 'src/views/CRUD/data/common';
-import ImportModelsModal from 'src/components/ImportModal/index';
import handleResourceExport from 'src/utils/export';
import { ExtentionConfigs } from 'src/views/components/types';
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
@@ -39,17 +38,6 @@ import DatabaseModal from './DatabaseModal';
import { DatabaseObject } from './types';
const PAGE_SIZE = 25;
-const PASSWORDS_NEEDED_MESSAGE = t(
- 'The passwords for the databases below are needed in order to ' +
- 'import them. Please note that the "Secure Extra" and "Certificate" ' +
- 'sections of the database configuration are not present in export ' +
- 'files, and should be added manually after the import if they are needed.',
-);
-const CONFIRM_OVERWRITE_MESSAGE = t(
- 'You are importing one or more databases that already exist. ' +
- 'Overwriting might cause you to lose some of your work. Are you ' +
- 'sure you want to overwrite?',
-);
interface DatabaseDeleteObject extends DatabaseObject {
chart_count: number;
@@ -103,8 +91,6 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
const [currentDatabase, setCurrentDatabase] = useState(
null,
);
- const [importingDatabase, showImportModal] = useState(false);
- const [passwordFields, setPasswordFields] = useState([]);
const [preparingExport, setPreparingExport] = useState(false);
const { roles } = useSelector(
state => state.user,
@@ -116,20 +102,6 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
ALLOWED_EXTENSIONS,
} = useSelector(state => state.common.conf);
- const openDatabaseImportModal = () => {
- showImportModal(true);
- };
-
- const closeDatabaseImportModal = () => {
- showImportModal(false);
- };
-
- const handleDatabaseImport = () => {
- showImportModal(false);
- refreshData();
- addSuccessToast(t('Database imported'));
- };
-
const openDatabaseDeleteModal = (database: DatabaseObject) =>
SupersetClient.get({
endpoint: `/api/v1/database/${database.id}/related_objects/`,
@@ -245,22 +217,6 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
},
},
];
-
- if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) {
- menuData.buttons.push({
- name: (
-
-
-
- ),
- buttonStyle: 'link',
- onClick: openDatabaseImportModal,
- });
- }
}
function handleDatabaseExport(database: DatabaseObject) {
@@ -526,19 +482,6 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
pageSize={PAGE_SIZE}
/>
-
{preparingExport && }
>
);
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
index 992aa76e36060..c923f425aa9e3 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
@@ -19,6 +19,7 @@
import React from 'react';
import { getDatabaseDocumentationLinks } from 'src/views/CRUD/hooks';
+import { UploadFile } from 'antd/lib/upload/interface';
import {
EditHeaderTitle,
EditHeaderSubtitle,
@@ -61,6 +62,7 @@ const ModalHeader = ({
dbName,
dbModel,
editNewDb,
+ fileName,
}: {
isLoading: boolean;
isEditMode: boolean;
@@ -70,6 +72,9 @@ const ModalHeader = ({
dbName: string;
dbModel: DatabaseForm;
editNewDb?: boolean;
+ fileName?: UploadFile[];
+ passwordFields?: string[];
+ needsOverwriteConfirm?: boolean;
}) => {
const isEditHeader = (
@@ -115,6 +120,10 @@ const ModalHeader = ({
);
+ console.log(
+ 'findme modalHeader - fileName',
+ fileName ? fileName[0].name : '',
+ );
const hasDbHeader = (
@@ -142,19 +151,23 @@ const ModalHeader = ({
);
+ const newHeader = (
+
+
+ STEP 2 OF 3
+ Enter the required {dbModel.name} credentials
+ {fileName ? fileName[0].name : ''}
+
+
+ );
+
+ if (fileName) return newHeader;
if (isLoading) return <>>;
- if (isEditMode) {
- return isEditHeader;
- }
- if (useSqlAlchemyForm) {
- return useSqlAlchemyFormHeader;
- }
- if (hasConnectedDb && !editNewDb) {
- return hasConnectedDbHeader;
- }
- if (db || editNewDb) {
- return hasDbHeader;
- }
+ if (isEditMode) return isEditHeader;
+ if (useSqlAlchemyForm) return useSqlAlchemyFormHeader;
+ if (hasConnectedDb && !editNewDb) return hasConnectedDbHeader;
+ if (db || editNewDb) return hasDbHeader;
+
return noDbHeader;
};
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
index 783516231b629..ad337a97e6c83 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
@@ -29,8 +29,9 @@ import React, {
useReducer,
Reducer,
} from 'react';
+import { UploadChangeParam, UploadFile } from 'antd/lib/upload/interface';
import Tabs from 'src/components/Tabs';
-import { AntdSelect } from 'src/components';
+import { AntdSelect, Upload } from 'src/components';
import Alert from 'src/components/Alert';
import Modal from 'src/components/Modal';
import Button from 'src/components/Button';
@@ -44,6 +45,7 @@ import {
useDatabaseValidation,
getDatabaseImages,
getConnectionAlert,
+ useImportResource,
} from 'src/views/CRUD/hooks';
import { useCommonConf } from 'src/views/CRUD/data/database/state';
import {
@@ -520,6 +522,7 @@ const DatabaseModal: FunctionComponent = ({
setEditNewDb(false);
onHide();
};
+
const onSave = async () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { id, ...update } = db || {};
@@ -861,6 +864,49 @@ const DatabaseModal: FunctionComponent = ({
}
}, [availableDbs]);
+ // ------------------------------ FINDME START 🚧
+
+ const [passwordFields, setPasswordFields] = useState([]);
+ const [needsOverwriteConfirm, setNeedsOverwriteConfirm] =
+ useState(false);
+ const [passwords, setPasswords] = useState>({});
+ const [confirmedOverwrite, setConfirmedOverwrite] = useState(false);
+
+ // isImporting ? render modal
+
+ const [fileName, setFileName] = useState([]);
+
+ console.log('findme databasemodal - fileName', fileName);
+
+ const {
+ state: { alreadyExists, passwordsNeeded },
+ importResource,
+ } = useImportResource('database', t('database'), msg => addDangerToast(msg));
+
+ useEffect(() => {
+ setPasswordFields(passwordsNeeded);
+ }, [passwordsNeeded, setPasswordFields]);
+
+ useEffect(() => {
+ setNeedsOverwriteConfirm(alreadyExists.length > 0);
+ }, [alreadyExists, setNeedsOverwriteConfirm]);
+
+ const onDbImport = (info: UploadChangeParam) => {
+ setFileName([
+ {
+ ...info.file,
+ status: 'done',
+ },
+ ]);
+ if (!(fileName[0]?.originFileObj instanceof File)) {
+ return;
+ }
+
+ importResource(fileName[0].originFileObj, passwords, confirmedOverwrite);
+ };
+
+ // ------------------------------ FINDME END 🚧
+
const tabChange = (key: string) => {
setTabKey(key);
};
@@ -1013,6 +1059,41 @@ const DatabaseModal: FunctionComponent = ({
);
};
+ if (fileName.length > 0) {
+ console.log('findme made it');
+ return (
+ [
+ antDModalNoPaddingStyles,
+ antDModalStyles(theme),
+ formHelperStyles(theme),
+ formStyles(theme),
+ ]}
+ name="database"
+ onHandledPrimaryAction={onSave}
+ onHide={onClose}
+ primaryButtonName={t('Connect')}
+ width="500px"
+ centered
+ show={show}
+ title={{t('Connect a database')}
}
+ footer={renderModalFooter()}
+ >
+
+ Test
+
+ );
+ }
+
return useTabLayout ? (
[
@@ -1252,8 +1333,30 @@ const DatabaseModal: FunctionComponent = ({
/>
{renderPreferredSelector()}
{renderAvailableSelector()}
+ {/* // ------------------------------ FINDME START 🚧 */}
+ {}}
+ onChange={info => {
+ onDbImport(info);
+ }}
+ >
+
+
) : (
+ // ------------------------------ FINDME END 🚧
<>
Date: Tue, 22 Mar 2022 12:46:20 -0500
Subject: [PATCH 02/35] more progress
---
.../data/database/DatabaseModal/index.tsx | 100 ++++++++++++++++--
.../data/database/DatabaseModal/styles.ts | 23 ++++
2 files changed, 114 insertions(+), 9 deletions(-)
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
index ad337a97e6c83..47dc06c2e377a 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
@@ -38,6 +38,7 @@ import Button from 'src/components/Button';
import IconButton from 'src/components/IconButton';
import InfoTooltip from 'src/components/InfoTooltip';
import withToasts from 'src/components/MessageToasts/withToasts';
+import ValidatedInput from 'src/components/Form/LabeledErrorBoundInput';
import {
testDatabaseConnection,
useSingleViewResource,
@@ -61,6 +62,7 @@ import DatabaseConnectionForm from './DatabaseConnectionForm';
import {
antDErrorAlertStyles,
antDAlertStyles,
+ antdWarningAlertStyles,
StyledAlertMargin,
antDModalNoPaddingStyles,
antDModalStyles,
@@ -75,6 +77,7 @@ import {
infoTooltip,
StyledFooterButton,
StyledStickyHeader,
+ formScrollableStyles,
} from './styles';
import ModalHeader, { DOCUMENTATION_LINK } from './ModalHeader';
@@ -437,6 +440,7 @@ const DatabaseModal: FunctionComponent = ({
const [db, setDB] = useReducer<
Reducer | null, DBReducerActionType>
>(dbReducer, null);
+ console.log('findme db root', db);
const [tabKey, setTabKey] = useState(DEFAULT_TAB_KEY);
const [availableDbs, getAvailableDbs] = useAvailableDatabases();
const [validationErrors, getValidation, setValidationErrors] =
@@ -884,27 +888,105 @@ const DatabaseModal: FunctionComponent = ({
} = useImportResource('database', t('database'), msg => addDangerToast(msg));
useEffect(() => {
+ // console.log('findme UE - pw', passwordsNeeded, 'pwfields', passwordFields);
setPasswordFields(passwordsNeeded);
}, [passwordsNeeded, setPasswordFields]);
useEffect(() => {
+ // console.log(
+ // 'findme UE - ow',
+ // alreadyExists,
+ // 'confirm',
+ // needsOverwriteConfirm,
+ // );
setNeedsOverwriteConfirm(alreadyExists.length > 0);
}, [alreadyExists, setNeedsOverwriteConfirm]);
const onDbImport = (info: UploadChangeParam) => {
+ console.log('findme odi entrance');
setFileName([
{
...info.file,
status: 'done',
},
]);
- if (!(fileName[0]?.originFileObj instanceof File)) {
- return;
- }
+ if (!(fileName[0]?.originFileObj instanceof File)) return;
+ console.log(
+ 'findme odi filecheck',
+ fileName[0].originFileObj,
+ passwords,
+ confirmedOverwrite,
+ );
+
+ console.log(
+ 'findme onDbImport',
+ fileName[0].originFileObj,
+ passwords,
+ confirmedOverwrite,
+ );
importResource(fileName[0].originFileObj, passwords, confirmedOverwrite);
};
+ const passwordNeededField = () => (
+ // passwordFields.map(password => (
+ // passwordsNeeded.length > 0 && (
+ <>
+
+ antDAlertStyles(theme)}
+ type="info"
+ showIcon
+ message="Database passwords"
+ description={t(
+ `The passwords for the databases below are needed in order to import them. Please not that the "Secure Extra" and "Certificate" sections of the database configuration are not present in explore files and should be added manually after the import if they are needed.`,
+ )}
+ />
+
+ {} }}
+ errorMessage={validationErrors?.password_needed}
+ label={t(`${db?.database_name} PASSWORD`)}
+ css={formScrollableStyles}
+ />
+ >
+ // ));
+ );
+
+ const confirmOverwriteField = () => (
+ // alreadyExists.length > 0 && (
+ <>
+
+ antdWarningAlertStyles(theme)}
+ type="warning"
+ showIcon
+ message=""
+ description={t(
+ 'You are importing one or more databases that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?',
+ )}
+ />
+
+ {} }}
+ errorMessage={validationErrors?.confirm_overwrite}
+ label={t(`TYPE "OVERWRITE" TO CONFIRM`)}
+ css={formScrollableStyles}
+ />
+ >
+ );
+
// ------------------------------ FINDME END 🚧
const tabChange = (key: string) => {
@@ -1059,8 +1141,10 @@ const DatabaseModal: FunctionComponent = ({
);
};
+ // console.log('findme pwneed exists', passwordsNeeded, alreadyExists);
+
if (fileName.length > 0) {
- console.log('findme made it');
+ console.log('findme made it', db, db?.database_name);
return (
[
@@ -1089,7 +1173,8 @@ const DatabaseModal: FunctionComponent = ({
dbModel={dbModel}
fileName={fileName}
/>
- Test
+ {passwordNeededField()}
+ {confirmOverwriteField()}
);
}
@@ -1341,15 +1426,12 @@ const DatabaseModal: FunctionComponent = ({
accept=".yaml,.json,.yml,.zip"
// upload is handled by hook
customRequest={() => {}}
- onChange={info => {
- onDbImport(info);
- }}
+ onChange={info => onDbImport(info)}
>
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts
index c0e65b97774cc..e479c793e8789 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts
@@ -218,6 +218,29 @@ export const antDErrorAlertStyles = (theme: SupersetTheme) => css`
}
`;
+export const antdWarningAlertStyles = (theme: SupersetTheme) => css`
+ border: 1px solid ${theme.colors.warning.light1};
+ padding: ${theme.gridUnit * 4}px;
+ margin: ${theme.gridUnit * 4}px 0;
+ color: ${theme.colors.warning.dark2};
+
+ .ant-alert-message {
+ margin: 0;
+ }
+
+ .ant-alert-description {
+ font-size: ${theme.typography.sizes.s + 1}px;
+ line-height: ${theme.gridUnit * 4}px;
+
+ .ant-alert-icon {
+ margin-right: ${theme.gridUnit * 2.5}px;
+ font-size: ${theme.typography.sizes.l + 1}px;
+ position: relative;
+ top: ${theme.gridUnit / 4}px;
+ }
+ }
+`;
+
export const formHelperStyles = (theme: SupersetTheme) => css`
.required {
margin-left: ${theme.gridUnit / 2}px;
From bc7ef74f7ec699b7c5701e10fcde78c8a7071e7f Mon Sep 17 00:00:00 2001
From: lyndsiWilliams
Date: Tue, 22 Mar 2022 13:02:21 -0500
Subject: [PATCH 03/35] Fix unintended changes
---
.../CRUD/data/database/DatabaseList.test.jsx | 45 +++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx b/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx
index 47f4907f48527..12580d8ee73fa 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx
@@ -23,6 +23,10 @@ import configureStore from 'redux-mock-store';
import fetchMock from 'fetch-mock';
import { Provider } from 'react-redux';
import { styledMount as mount } from 'spec/helpers/theming';
+import { render, screen, cleanup } from 'spec/helpers/testing-library';
+import userEvent from '@testing-library/user-event';
+import { QueryParamProvider } from 'use-query-params';
+import * as featureFlags from 'src/featureFlags';
import DatabaseList from 'src/views/CRUD/data/database/DatabaseList';
import DatabaseModal from 'src/views/CRUD/data/database/DatabaseModal';
@@ -204,3 +208,44 @@ describe('DatabaseList', () => {
);
});
});
+
+describe('RTL', () => {
+ async function renderAndWait() {
+ const mounted = act(async () => {
+ render(
+
+
+ ,
+ { useRedux: true },
+ mockAppState,
+ );
+ });
+
+ return mounted;
+ }
+
+ let isFeatureEnabledMock;
+ beforeEach(async () => {
+ isFeatureEnabledMock = jest
+ .spyOn(featureFlags, 'isFeatureEnabled')
+ .mockImplementation(() => true);
+ await renderAndWait();
+ });
+
+ afterEach(() => {
+ cleanup();
+ isFeatureEnabledMock.mockRestore();
+ });
+
+ it('renders an "Import Database" tooltip under import button', async () => {
+ const importButton = await screen.findByTestId('import-button');
+ userEvent.hover(importButton);
+
+ await screen.findByRole('tooltip');
+ const importTooltip = screen.getByRole('tooltip', {
+ name: 'Import databases',
+ });
+
+ expect(importTooltip).toBeInTheDocument();
+ });
+});
From 1a53bdb35a3d24b4fe90a3fab14e21dd9fd8c974 Mon Sep 17 00:00:00 2001
From: lyndsiWilliams
Date: Wed, 23 Mar 2022 22:43:33 -0500
Subject: [PATCH 04/35] DB import goes to step 3
---
.../database/DatabaseModal/ModalHeader.tsx | 19 +-
.../data/database/DatabaseModal/index.tsx | 276 ++++++++++--------
superset-frontend/src/views/CRUD/hooks.ts | 2 +
3 files changed, 169 insertions(+), 128 deletions(-)
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
index c923f425aa9e3..ba669eb630a50 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
@@ -53,6 +53,7 @@ const documentationLink = (engine: string | undefined) => {
}
return irregularDocumentationLinks[engine];
};
+
const ModalHeader = ({
isLoading,
isEditMode,
@@ -62,7 +63,7 @@ const ModalHeader = ({
dbName,
dbModel,
editNewDb,
- fileName,
+ file,
}: {
isLoading: boolean;
isEditMode: boolean;
@@ -72,7 +73,7 @@ const ModalHeader = ({
dbName: string;
dbModel: DatabaseForm;
editNewDb?: boolean;
- fileName?: UploadFile[];
+ file?: UploadFile[];
passwordFields?: string[];
needsOverwriteConfirm?: boolean;
}) => {
@@ -82,6 +83,7 @@ const ModalHeader = ({
{dbName}
);
+
const useSqlAlchemyFormHeader = (
STEP 2 OF 2
@@ -99,6 +101,7 @@ const ModalHeader = ({
);
+
const hasConnectedDbHeader = (
@@ -120,10 +123,7 @@ const ModalHeader = ({
);
- console.log(
- 'findme modalHeader - fileName',
- fileName ? fileName[0].name : '',
- );
+
const hasDbHeader = (
@@ -142,6 +142,7 @@ const ModalHeader = ({
);
+
const noDbHeader = (
@@ -151,17 +152,17 @@ const ModalHeader = ({
);
- const newHeader = (
+ const importDbHeader = (
STEP 2 OF 3
Enter the required {dbModel.name} credentials
- {fileName ? fileName[0].name : ''}
+ {file ? file[0].name : ''}
);
- if (fileName) return newHeader;
+ if (file && !hasConnectedDb) return importDbHeader;
if (isLoading) return <>>;
if (isEditMode) return isEditHeader;
if (useSqlAlchemyForm) return useSqlAlchemyFormHeader;
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
index 47dc06c2e377a..cde2c277478f7 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
@@ -404,10 +404,15 @@ function dbReducer(
return {
...action.payload,
};
+
case ActionType.configMethodChange:
return {
...action.payload,
};
+
+ // case ActionType.importDatabase:
+ // return {};
+
case ActionType.reset:
default:
return null;
@@ -440,7 +445,6 @@ const DatabaseModal: FunctionComponent
= ({
const [db, setDB] = useReducer<
Reducer | null, DBReducerActionType>
>(dbReducer, null);
- console.log('findme db root', db);
const [tabKey, setTabKey] = useState(DEFAULT_TAB_KEY);
const [availableDbs, getAvailableDbs] = useAvailableDatabases();
const [validationErrors, getValidation, setValidationErrors] =
@@ -518,15 +522,39 @@ const DatabaseModal: FunctionComponent = ({
);
};
+ const [passwordFields, setPasswordFields] = useState([]); // set in useEffect
+ const [needsOverwriteConfirm, setNeedsOverwriteConfirm] =
+ useState(false); // set in useEffect
+ const [passwords, setPasswords] = useState>({}); // set by user input
+ const [confirmedOverwrite, setConfirmedOverwrite] = useState(false); // set by user input
+ const [file, setFile] = useState([]);
+ const [importingModel, setImportingModel] = useState(false);
+ console.log('findme importing', importingModel);
+
+ const {
+ state: { alreadyExists, passwordsNeeded },
+ importResource,
+ } = useImportResource('database', t('database'), msg => addDangerToast(msg));
+
const onClose = () => {
setDB({ type: ActionType.reset });
setHasConnectedDb(false);
setValidationErrors(null); // reset validation errors on close
clearError();
setEditNewDb(false);
+ setFile(file.filter(currentFile => currentFile.uid !== file[0].uid));
+ setPasswordFields([]);
+ setNeedsOverwriteConfirm(false);
+ setImportingModel(false);
onHide();
};
+ const onChange = (type: any, payload: any) => {
+ setDB({ type, payload } as DBReducerActionType);
+ };
+
+ console.log('findme DB', db);
+
const onSave = async () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { id, ...update } = db || {};
@@ -602,9 +630,7 @@ const DatabaseModal: FunctionComponent = ({
dbToUpdate.configuration_method === CONFIGURATION_METHOD.DYNAMIC_FORM, // onShow toast on SQLA Forms
);
if (result) {
- if (onDatabaseAdd) {
- onDatabaseAdd();
- }
+ if (onDatabaseAdd) onDatabaseAdd();
if (!editNewDb) {
onClose();
addSuccessToast(t('Database settings updated'));
@@ -619,9 +645,35 @@ const DatabaseModal: FunctionComponent = ({
);
if (dbId) {
setHasConnectedDb(true);
- if (onDatabaseAdd) {
- onDatabaseAdd();
+ if (onDatabaseAdd) onDatabaseAdd();
+ if (useTabLayout) {
+ // tab layout only has one step
+ // so it should close immediately on save
+ onClose();
+ addSuccessToast(t('Database connected'));
}
+ }
+ }
+
+ // Import - doesn't use db state
+ if (!db) {
+ setLoading(true);
+ setImportingModel(true);
+ onChange(ActionType.textChange, {
+ name: 'database_name',
+ value: 'TEST database name',
+ });
+
+ if (!(file[0].originFileObj instanceof File)) return;
+ const dbId = await importResource(
+ file[0].originFileObj,
+ passwords,
+ confirmedOverwrite,
+ );
+
+ if (dbId) {
+ setHasConnectedDb(true);
+ if (onDatabaseAdd) onDatabaseAdd();
if (useTabLayout) {
// tab layout only has one step
// so it should close immediately on save
@@ -630,14 +682,11 @@ const DatabaseModal: FunctionComponent = ({
}
}
}
+
setEditNewDb(false);
setLoading(false);
};
- const onChange = (type: any, payload: any) => {
- setDB({ type, payload } as DBReducerActionType);
- };
-
// Initialize
const fetchDB = () => {
if (isEditMode && databaseId) {
@@ -788,7 +837,7 @@ const DatabaseModal: FunctionComponent = ({
const renderModalFooter = () => {
if (db) {
// if db show back + connenct
- if (!hasConnectedDb || editNewDb) {
+ if (!hasConnectedDb || editNewDb || !importingModel) {
return (
<>
@@ -821,6 +870,7 @@ const DatabaseModal: FunctionComponent = ({
>
);
}
+
return [];
};
@@ -834,6 +884,7 @@ const DatabaseModal: FunctionComponent = ({
>
);
+
useEffect(() => {
if (show) {
setTabKey(DEFAULT_TAB_KEY);
@@ -870,128 +921,103 @@ const DatabaseModal: FunctionComponent = ({
// ------------------------------ FINDME START 🚧
- const [passwordFields, setPasswordFields] = useState([]);
- const [needsOverwriteConfirm, setNeedsOverwriteConfirm] =
- useState(false);
- const [passwords, setPasswords] = useState>({});
- const [confirmedOverwrite, setConfirmedOverwrite] = useState(false);
-
- // isImporting ? render modal
-
- const [fileName, setFileName] = useState([]);
-
- console.log('findme databasemodal - fileName', fileName);
-
- const {
- state: { alreadyExists, passwordsNeeded },
- importResource,
- } = useImportResource('database', t('database'), msg => addDangerToast(msg));
-
useEffect(() => {
- // console.log('findme UE - pw', passwordsNeeded, 'pwfields', passwordFields);
setPasswordFields(passwordsNeeded);
+ if (passwordsNeeded.length > 0) {
+ setImportingModel(false);
+ }
}, [passwordsNeeded, setPasswordFields]);
useEffect(() => {
- // console.log(
- // 'findme UE - ow',
- // alreadyExists,
- // 'confirm',
- // needsOverwriteConfirm,
- // );
setNeedsOverwriteConfirm(alreadyExists.length > 0);
+ if (alreadyExists.length > 0) {
+ setImportingModel(false);
+ }
}, [alreadyExists, setNeedsOverwriteConfirm]);
const onDbImport = (info: UploadChangeParam) => {
- console.log('findme odi entrance');
- setFileName([
+ setImportingModel(true);
+ setFile([
{
...info.file,
status: 'done',
},
]);
- if (!(fileName[0]?.originFileObj instanceof File)) return;
- console.log(
- 'findme odi filecheck',
- fileName[0].originFileObj,
- passwords,
- confirmedOverwrite,
- );
+ if (!(info.file.originFileObj instanceof File)) return;
+ importResource(info.file.originFileObj, passwords, confirmedOverwrite);
+ };
- console.log(
- 'findme onDbImport',
- fileName[0].originFileObj,
- passwords,
- confirmedOverwrite,
+ const passwordNeededField = () =>
+ passwordFields.map(
+ password =>
+ passwordsNeeded.length > 0 && (
+ <>
+
+ antDAlertStyles(theme)}
+ type="info"
+ showIcon
+ message="Database passwords"
+ description={t(
+ `The passwords for the databases below are needed in order to import them. Please not that the "Secure Extra" and "Certificate" sections of the database configuration are not present in explore files and should be added manually after the import if they are needed.`,
+ )}
+ />
+
+ {} }}
+ errorMessage={validationErrors?.password_needed}
+ label={t(`${db?.database_name} PASSWORD`)}
+ css={formScrollableStyles}
+ />
+ >
+ ),
);
- importResource(fileName[0].originFileObj, passwords, confirmedOverwrite);
+
+ const confirmOverwrite = (event: React.ChangeEvent) => {
+ const targetValue = (event.currentTarget?.value as string) ?? '';
+ setConfirmedOverwrite(targetValue.toUpperCase() === t('OVERWRITE'));
};
- const passwordNeededField = () => (
- // passwordFields.map(password => (
- // passwordsNeeded.length > 0 && (
- <>
-
- antDAlertStyles(theme)}
- type="info"
- showIcon
- message="Database passwords"
- description={t(
- `The passwords for the databases below are needed in order to import them. Please not that the "Secure Extra" and "Certificate" sections of the database configuration are not present in explore files and should be added manually after the import if they are needed.`,
- )}
- />
-
- {} }}
- errorMessage={validationErrors?.password_needed}
- label={t(`${db?.database_name} PASSWORD`)}
- css={formScrollableStyles}
- />
- >
- // ));
- );
+ const confirmOverwriteField = () => {
+ if (!needsOverwriteConfirm) return null;
- const confirmOverwriteField = () => (
- // alreadyExists.length > 0 && (
- <>
-
- antdWarningAlertStyles(theme)}
- type="warning"
- showIcon
- message=""
- description={t(
- 'You are importing one or more databases that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?',
- )}
+ return (
+ <>
+
+ antdWarningAlertStyles(theme)}
+ type="warning"
+ showIcon
+ message=""
+ description={t(
+ 'You are importing one or more databases that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?',
+ )}
+ />
+
+ {} }}
+ errorMessage={validationErrors?.confirm_overwrite}
+ label={t(`TYPE "OVERWRITE" TO CONFIRM`)}
+ onChange={confirmOverwrite}
+ css={formScrollableStyles}
/>
-
- {} }}
- errorMessage={validationErrors?.confirm_overwrite}
- label={t(`TYPE "OVERWRITE" TO CONFIRM`)}
- css={formScrollableStyles}
- />
- >
- );
-
+ >
+ );
+ };
// ------------------------------ FINDME END 🚧
- const tabChange = (key: string) => {
- setTabKey(key);
- };
+ const tabChange = (key: string) => setTabKey(key);
const renderStepTwoAlert = () => {
const { hostname } = window.location;
@@ -999,9 +1025,7 @@ const DatabaseModal: FunctionComponent = ({
const regionalIPs = connectionAlert?.REGIONAL_IPS || {};
Object.entries(regionalIPs).forEach(([ipRegion, ipRange]) => {
const regex = new RegExp(ipRegion);
- if (hostname.match(regex)) {
- ipAlert = ipRange;
- }
+ if (hostname.match(regex)) ipAlert = ipRange;
});
return (
db?.engine && (
@@ -1141,10 +1165,10 @@ const DatabaseModal: FunctionComponent = ({
);
};
- // console.log('findme pwneed exists', passwordsNeeded, alreadyExists);
-
- if (fileName.length > 0) {
- console.log('findme made it', db, db?.database_name);
+ if (
+ (passwordsNeeded.length > 0 || alreadyExists.length > 0) &&
+ !hasConnectedDb
+ ) {
return (
[
@@ -1161,7 +1185,21 @@ const DatabaseModal: FunctionComponent = ({
centered
show={show}
title={{t('Connect a database')}
}
- footer={renderModalFooter()}
+ footer={
+ <>
+
+ {t('Back')}
+
+
+ {t('Connect')}
+
+ >
+ // renderModalFooter()
+ }
>
= ({
db={db}
dbName={dbName}
dbModel={dbModel}
- fileName={fileName}
+ file={file}
/>
{passwordNeededField()}
{confirmOverwriteField()}
diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts
index ae58aef0d9e0f..83c90c2597a3e 100644
--- a/superset-frontend/src/views/CRUD/hooks.ts
+++ b/superset-frontend/src/views/CRUD/hooks.ts
@@ -425,6 +425,8 @@ export function useImportResource(
formData.append('overwrite', 'true');
}
+ console.log('FINDME formdata', formData);
+
return SupersetClient.post({
endpoint: `/api/v1/${resourceName}/import/`,
body: formData,
From 84dd7f5b72a6178217755cc22a7ed839a92412ad Mon Sep 17 00:00:00 2001
From: lyndsiWilliams
Date: Thu, 24 Mar 2022 15:45:28 -0500
Subject: [PATCH 05/35] debugging
---
.../data/database/DatabaseModal/index.tsx | 90 ++++++++++---------
1 file changed, 50 insertions(+), 40 deletions(-)
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
index cde2c277478f7..28b61bddc2fb4 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
@@ -536,13 +536,15 @@ const DatabaseModal: FunctionComponent = ({
importResource,
} = useImportResource('database', t('database'), msg => addDangerToast(msg));
+ console.log('findme STATE', alreadyExists, passwordsNeeded);
+
const onClose = () => {
setDB({ type: ActionType.reset });
setHasConnectedDb(false);
setValidationErrors(null); // reset validation errors on close
clearError();
setEditNewDb(false);
- setFile(file.filter(currentFile => currentFile.uid !== file[0].uid));
+ // setFile(file.filter(currentFile => currentFile.uid !== file[0].uid));
setPasswordFields([]);
setNeedsOverwriteConfirm(false);
setImportingModel(false);
@@ -672,14 +674,17 @@ const DatabaseModal: FunctionComponent = ({
);
if (dbId) {
- setHasConnectedDb(true);
- if (onDatabaseAdd) onDatabaseAdd();
- if (useTabLayout) {
- // tab layout only has one step
- // so it should close immediately on save
- onClose();
- addSuccessToast(t('Database connected'));
- }
+ // setHasConnectedDb(true);
+ // if (onDatabaseAdd) onDatabaseAdd();
+ // if (useTabLayout) {
+ // // tab layout only has one step
+ // // so it should close immediately on save
+ // onClose();
+ // addSuccessToast(t('Database connected'));
+ // }
+
+ onClose();
+ addSuccessToast(t('Database connected'));
}
}
@@ -948,37 +953,42 @@ const DatabaseModal: FunctionComponent = ({
importResource(info.file.originFileObj, passwords, confirmedOverwrite);
};
- const passwordNeededField = () =>
- passwordFields.map(
- password =>
- passwordsNeeded.length > 0 && (
- <>
-
- antDAlertStyles(theme)}
- type="info"
- showIcon
- message="Database passwords"
- description={t(
- `The passwords for the databases below are needed in order to import them. Please not that the "Secure Extra" and "Certificate" sections of the database configuration are not present in explore files and should be added manually after the import if they are needed.`,
- )}
- />
-
- {} }}
- errorMessage={validationErrors?.password_needed}
- label={t(`${db?.database_name} PASSWORD`)}
- css={formScrollableStyles}
- />
- >
- ),
- );
+ console.log('findme PASSWORDS', passwords);
+ console.log('findme PASSWORDFIELDS', passwordFields);
+
+ const passwordNeededField = () => {
+ // if (passwordFields.length === 0) return null;
+
+ passwordFields.map(database => (
+ <>
+
+ antDAlertStyles(theme)}
+ type="info"
+ showIcon
+ message="Database passwords"
+ description={t(
+ `The passwords for the databases below are needed in order to import them. Please not that the "Secure Extra" and "Certificate" sections of the database configuration are not present in explore files and should be added manually after the import if they are needed.`,
+ )}
+ />
+
+ ) =>
+ setPasswords({ ...passwords, [database]: event.target.value })
+ }
+ validationMethods={{ onBlur: () => {} }}
+ errorMessage={validationErrors?.password_needed}
+ label={t(`${database.slice(10)} PASSWORD`)}
+ css={formScrollableStyles}
+ />
+ >
+ ));
+ };
const confirmOverwrite = (event: React.ChangeEvent) => {
const targetValue = (event.currentTarget?.value as string) ?? '';
From 3a86dea84f4c70e7d0e5bad78379a368dc77af80 Mon Sep 17 00:00:00 2001
From: lyndsiWilliams
Date: Mon, 28 Mar 2022 15:57:00 -0500
Subject: [PATCH 06/35] DB list refreshing properly
---
.../database/DatabaseModal/ModalHeader.tsx | 2 +-
.../data/database/DatabaseModal/index.tsx | 47 ++++++++++---------
2 files changed, 27 insertions(+), 22 deletions(-)
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
index ba669eb630a50..f13e1b734d130 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
@@ -155,7 +155,7 @@ const ModalHeader = ({
const importDbHeader = (
- STEP 2 OF 3
+ STEP 2 OF 2
Enter the required {dbModel.name} credentials
{file ? file[0].name : ''}
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
index 28b61bddc2fb4..3bc18a28f5d9a 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
@@ -538,19 +538,34 @@ const DatabaseModal: FunctionComponent = ({
console.log('findme STATE', alreadyExists, passwordsNeeded);
+ const blankFile = {
+ lastModified: 0,
+ lastModifiedDate: undefined,
+ name: '',
+ originFileObj: undefined,
+ percent: 0,
+ size: 0,
+ status: undefined,
+ type: '',
+ uid: '',
+ };
+
const onClose = () => {
setDB({ type: ActionType.reset });
setHasConnectedDb(false);
setValidationErrors(null); // reset validation errors on close
clearError();
setEditNewDb(false);
- // setFile(file.filter(currentFile => currentFile.uid !== file[0].uid));
+ setFile([blankFile]);
setPasswordFields([]);
setNeedsOverwriteConfirm(false);
setImportingModel(false);
+ if (onDatabaseAdd) onDatabaseAdd();
onHide();
};
+ console.log('findme file', file);
+
const onChange = (type: any, payload: any) => {
setDB({ type, payload } as DBReducerActionType);
};
@@ -661,10 +676,10 @@ const DatabaseModal: FunctionComponent = ({
if (!db) {
setLoading(true);
setImportingModel(true);
- onChange(ActionType.textChange, {
- name: 'database_name',
- value: 'TEST database name',
- });
+ // onChange(ActionType.textChange, {
+ // name: 'database_name',
+ // value: 'TEST database name',
+ // });
if (!(file[0].originFileObj instanceof File)) return;
const dbId = await importResource(
@@ -674,14 +689,8 @@ const DatabaseModal: FunctionComponent = ({
);
if (dbId) {
- // setHasConnectedDb(true);
- // if (onDatabaseAdd) onDatabaseAdd();
- // if (useTabLayout) {
- // // tab layout only has one step
- // // so it should close immediately on save
- // onClose();
- // addSuccessToast(t('Database connected'));
- // }
+ console.log('findme onsave !db && dbId');
+ setHasConnectedDb(true);
onClose();
addSuccessToast(t('Database connected'));
@@ -928,16 +937,10 @@ const DatabaseModal: FunctionComponent = ({
useEffect(() => {
setPasswordFields(passwordsNeeded);
- if (passwordsNeeded.length > 0) {
- setImportingModel(false);
- }
}, [passwordsNeeded, setPasswordFields]);
useEffect(() => {
setNeedsOverwriteConfirm(alreadyExists.length > 0);
- if (alreadyExists.length > 0) {
- setImportingModel(false);
- }
}, [alreadyExists, setNeedsOverwriteConfirm]);
const onDbImport = (info: UploadChangeParam) => {
@@ -1175,9 +1178,11 @@ const DatabaseModal: FunctionComponent = ({
);
};
+ console.log('findme importing', importingModel);
+
if (
- (passwordsNeeded.length > 0 || alreadyExists.length > 0) &&
- !hasConnectedDb
+ importingModel &&
+ (passwordsNeeded.length > 0 || alreadyExists.length > 0)
) {
return (
Date: Mon, 28 Mar 2022 16:26:58 -0500
Subject: [PATCH 07/35] import screens flowing properly
---
.../database/DatabaseModal/ModalHeader.tsx | 10 ++++---
.../data/database/DatabaseModal/index.tsx | 26 +++++++------------
2 files changed, 17 insertions(+), 19 deletions(-)
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
index f13e1b734d130..2537d2fcc6548 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx
@@ -64,7 +64,8 @@ const ModalHeader = ({
dbModel,
editNewDb,
file,
-}: {
+}: // importingModel,
+{
isLoading: boolean;
isEditMode: boolean;
useSqlAlchemyForm: boolean;
@@ -76,6 +77,7 @@ const ModalHeader = ({
file?: UploadFile[];
passwordFields?: string[];
needsOverwriteConfirm?: boolean;
+ // importingModel?: boolean;
}) => {
const isEditHeader = (
@@ -152,17 +154,19 @@ const ModalHeader = ({
);
+ const fileCheck = file && file?.length > 0;
+
const importDbHeader = (
STEP 2 OF 2
Enter the required {dbModel.name} credentials
- {file ? file[0].name : ''}
+ {fileCheck ? file[0].name : ''}
);
- if (file && !hasConnectedDb) return importDbHeader;
+ if (fileCheck) return importDbHeader;
if (isLoading) return <>>;
if (isEditMode) return isEditHeader;
if (useSqlAlchemyForm) return useSqlAlchemyFormHeader;
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
index 3bc18a28f5d9a..c9b2dc4670593 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
@@ -538,16 +538,9 @@ const DatabaseModal: FunctionComponent = ({
console.log('findme STATE', alreadyExists, passwordsNeeded);
- const blankFile = {
- lastModified: 0,
- lastModifiedDate: undefined,
- name: '',
- originFileObj: undefined,
- percent: 0,
- size: 0,
- status: undefined,
- type: '',
- uid: '',
+ const removeFile = (removedFile: UploadFile) => {
+ setFile(file.filter(file => file.uid !== removedFile.uid));
+ return false;
};
const onClose = () => {
@@ -556,7 +549,7 @@ const DatabaseModal: FunctionComponent = ({
setValidationErrors(null); // reset validation errors on close
clearError();
setEditNewDb(false);
- setFile([blankFile]);
+ setFile([]);
setPasswordFields([]);
setNeedsOverwriteConfirm(false);
setImportingModel(false);
@@ -940,6 +933,7 @@ const DatabaseModal: FunctionComponent = ({
}, [passwordsNeeded, setPasswordFields]);
useEffect(() => {
+ console.log('findme UE', needsOverwriteConfirm, alreadyExists);
setNeedsOverwriteConfirm(alreadyExists.length > 0);
}, [alreadyExists, setNeedsOverwriteConfirm]);
@@ -999,7 +993,8 @@ const DatabaseModal: FunctionComponent = ({
};
const confirmOverwriteField = () => {
- if (!needsOverwriteConfirm) return null;
+ console.log('findme AE', alreadyExists);
+ if (alreadyExists.length === 0) return null;
return (
<>
@@ -1180,10 +1175,7 @@ const DatabaseModal: FunctionComponent = ({
console.log('findme importing', importingModel);
- if (
- importingModel &&
- (passwordsNeeded.length > 0 || alreadyExists.length > 0)
- ) {
+ if (file.length > 0 && importingModel) {
return (
[
@@ -1225,6 +1217,7 @@ const DatabaseModal: FunctionComponent = ({
dbName={dbName}
dbModel={dbModel}
file={file}
+ // importingModal={importingModel}
/>
{passwordNeededField()}
{confirmOverwriteField()}
@@ -1480,6 +1473,7 @@ const DatabaseModal: FunctionComponent = ({
// upload is handled by hook
customRequest={() => {}}
onChange={info => onDbImport(info)}
+ onRemove={removeFile}
>