You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ly...@apache.org on 2023/01/18 02:05:50 UTC
[superset] branch master updated: feat: Enable new dataset creation flow (#22610)
This is an automated email from the ASF dual-hosted git repository.
lyndsi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new c87f654901 feat: Enable new dataset creation flow (#22610)
c87f654901 is described below
commit c87f654901f5a975fa2f348c2893b2aa78db5707
Author: Lyndsi Kay Williams <55...@users.noreply.github.com>
AuthorDate: Tue Jan 17 20:05:40 2023 -0600
feat: Enable new dataset creation flow (#22610)
---
.../DatasourcePanel/DatasourcePanel.test.tsx | 21 ---
.../DndColumnSelectControl/ColumnSelectPopover.tsx | 4 +-
.../src/pages/ChartCreation/index.tsx | 5 +-
.../src/views/CRUD/data/database/DatabaseList.tsx | 4 +
.../data/database/DatabaseModal/index.test.tsx | 8 +
.../CRUD/data/database/DatabaseModal/index.tsx | 6 +-
.../data/dataset/AddDataset/AddDataset.test.tsx | 8 +
.../dataset/AddDataset/DatasetPanel/fixtures.ts | 1 +
.../data/dataset/AddDataset/DatasetPanel/index.tsx | 17 +-
.../data/dataset/AddDataset/Footer/Footer.test.tsx | 8 +
.../CRUD/data/dataset/AddDataset/Footer/index.tsx | 14 +-
.../AddDataset/LeftPanel/LeftPanel.test.tsx | 20 ++-
.../data/dataset/AddDataset/LeftPanel/index.tsx | 106 ++++++++-----
.../views/CRUD/data/dataset/AddDataset/index.tsx | 30 ++--
.../views/CRUD/data/dataset/AddDataset/types.tsx | 8 +-
.../views/CRUD/data/dataset/AddDatasetModal.tsx | 172 ---------------------
.../dataset/DatasetLayout/DatasetLayout.test.tsx | 8 +
.../src/views/CRUD/data/dataset/DatasetList.tsx | 45 +-----
superset-frontend/src/views/CRUD/data/hooks.ts | 10 +-
.../src/views/components/RightMenu.test.tsx | 3 -
.../src/views/components/RightMenu.tsx | 17 +-
superset/views/datasource/views.py | 5 +-
22 files changed, 174 insertions(+), 346 deletions(-)
diff --git a/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx b/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx
index eedc2fb101..95258f443e 100644
--- a/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx
+++ b/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx
@@ -186,27 +186,6 @@ test('should render a create dataset infobox', async () => {
expect(infoboxText).toBeVisible();
});
-test('should render a save dataset modal when "Create a dataset" is clicked', async () => {
- const newProps = {
- ...props,
- datasource: {
- ...datasource,
- type: DatasourceType.Query,
- },
- };
- render(<DatasourcePanel {...newProps} />, { useRedux: true, useDnd: true });
-
- const createButton = await screen.findByRole('button', {
- name: /create a dataset/i,
- });
-
- userEvent.click(createButton);
-
- const saveDatasetModalTitle = screen.getByText(/save or overwrite dataset/i);
-
- expect(saveDatasetModalTitle).toBeVisible();
-});
-
test('should not render a save dataset modal when datasource is not query or dataset', async () => {
const newProps = {
...props,
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
index fee2eb941f..dbbc8fe948 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
@@ -231,7 +231,9 @@ const ColumnSelectPopover = ({
}, []);
const setDatasetAndClose = () => {
- if (setDatasetModal) setDatasetModal(true);
+ if (setDatasetModal) {
+ setDatasetModal(true);
+ }
onClose();
};
diff --git a/superset-frontend/src/pages/ChartCreation/index.tsx b/superset-frontend/src/pages/ChartCreation/index.tsx
index 4aeb7aeed4..bea530fd3a 100644
--- a/superset-frontend/src/pages/ChartCreation/index.tsx
+++ b/superset-frontend/src/pages/ChartCreation/index.tsx
@@ -337,10 +337,7 @@ export class ChartCreation extends React.PureComponent<
const isButtonDisabled = this.isBtnDisabled();
const datasetHelpText = this.state.canCreateDataset ? (
<span data-test="dataset-write">
- <Link
- to="/tablemodelview/list/#create"
- data-test="add-chart-new-dataset"
- >
+ <Link to="/dataset/add/" data-test="add-chart-new-dataset">
{t('Add a dataset')}
</Link>
{` ${t('or')} `}
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx
index 744edb51b1..0e3642493a 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx
@@ -21,6 +21,7 @@ import React, { useState, useMemo, useEffect } from 'react';
import rison from 'rison';
import { useSelector } from 'react-redux';
import { useQueryParams, BooleanParam } from 'use-query-params';
+import { LocalStorageKeys, setItem } from 'src/utils/localStorageHelpers';
import Loading from 'src/components/Loading';
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
@@ -157,6 +158,9 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
refreshData();
addSuccessToast(t('Deleted: %s', dbName));
+ // Delete user-selected db from local storage
+ setItem(LocalStorageKeys.db, null);
+
// Close delete modal
setDatabaseCurrentlyDeleting(null);
},
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.tsx
index 96bcace647..8457d8d174 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.tsx
@@ -43,6 +43,14 @@ jest.mock('@superset-ui/core', () => ({
isFeatureEnabled: () => true,
}));
+const mockHistoryPush = jest.fn();
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useHistory: () => ({
+ push: mockHistoryPush,
+ }),
+}));
+
const dbProps = {
show: true,
database_name: 'my database',
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 fae25219cf..39f6c15874 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
@@ -31,6 +31,7 @@ import React, {
useReducer,
Reducer,
} from 'react';
+import { useHistory } from 'react-router-dom';
import { setItem, LocalStorageKeys } from 'src/utils/localStorageHelpers';
import { UploadChangeParam, UploadFile } from 'antd/lib/upload/interface';
import Tabs from 'src/components/Tabs';
@@ -518,6 +519,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
t('database'),
addDangerToast,
);
+ const history = useHistory();
const [tabKey, setTabKey] = useState<string>(DEFAULT_TAB_KEY);
const [availableDbs, getAvailableDbs] = useAvailableDatabases();
@@ -1295,7 +1297,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
onClick={() => {
setLoading(true);
fetchAndSetDB();
- window.location.href = '/tablemodelview/list#create';
+ history.push('/dataset/add/');
}}
>
{t('CREATE DATASET')}
@@ -1306,7 +1308,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
onClick={() => {
setLoading(true);
fetchAndSetDB();
- window.location.href = `/superset/sqllab/?db=true`;
+ history.push(`/superset/sqllab/?db=true`);
}}
>
{t('QUERY DATA IN SQL LAB')}
diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/AddDataset.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/AddDataset.test.tsx
index 39fb2b295b..7e5a7de12a 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/AddDataset.test.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/AddDataset.test.tsx
@@ -20,6 +20,14 @@ import React from 'react';
import { render, screen } from 'spec/helpers/testing-library';
import AddDataset from 'src/views/CRUD/data/dataset/AddDataset';
+const mockHistoryPush = jest.fn();
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useHistory: () => ({
+ push: mockHistoryPush,
+ }),
+}));
+
describe('AddDataset', () => {
it('renders a blank state AddDataset', async () => {
render(<AddDataset />, { useRedux: true });
diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/fixtures.ts b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/fixtures.ts
index d3ee58da14..5c09188c61 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/fixtures.ts
+++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/fixtures.ts
@@ -40,6 +40,7 @@ export const exampleDataset: DatasetObject[] = [
id: 1,
database_name: 'test_database',
owners: [1],
+ backend: 'test_backend',
},
schema: 'test_schema',
dataset_name: 'example_dataset',
diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/index.tsx
index 15e6225e56..73bea70b41 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/index.tsx
@@ -17,8 +17,9 @@
* under the License.
*/
import React, { useEffect, useState, useRef } from 'react';
-import { SupersetClient } from '@superset-ui/core';
+import { SupersetClient, logging, t } from '@superset-ui/core';
import { DatasetObject } from 'src/views/CRUD/data/dataset/AddDataset/types';
+import { addDangerToast } from 'src/components/MessageToasts/actions';
import DatasetPanel from './DatasetPanel';
import { ITableColumn, IDatabaseTable, isIDatabaseTable } from './types';
@@ -94,9 +95,17 @@ const DatasetPanelWrapper = ({
setColumnList([]);
setHasColumns?.(false);
setHasError(true);
- // eslint-disable-next-line no-console
- console.error(
- `The API response from ${path} does not match the IDatabaseTable interface.`,
+ addDangerToast(
+ t(
+ 'The API response from %s does not match the IDatabaseTable interface.',
+ path,
+ ),
+ );
+ logging.error(
+ t(
+ 'The API response from %s does not match the IDatabaseTable interface.',
+ path,
+ ),
);
}
} catch (error) {
diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/Footer.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/Footer.test.tsx
index 8fcbd83b15..a1818cdf22 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/Footer.test.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/Footer.test.tsx
@@ -20,6 +20,14 @@ import React from 'react';
import { render, screen } from 'spec/helpers/testing-library';
import Footer from 'src/views/CRUD/data/dataset/AddDataset/Footer';
+const mockHistoryPush = jest.fn();
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useHistory: () => ({
+ push: mockHistoryPush,
+ }),
+}));
+
const mockedProps = {
url: 'realwebsite.com',
};
diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx
index 5aecec0bb8..7f6717857f 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx
@@ -17,6 +17,7 @@
* under the License.
*/
import React from 'react';
+import { useHistory } from 'react-router-dom';
import Button from 'src/components/Button';
import { t } from '@superset-ui/core';
import { useSingleViewResource } from 'src/views/CRUD/hooks';
@@ -49,12 +50,12 @@ const LOG_ACTIONS = [
];
function Footer({
- url,
datasetObject,
addDangerToast,
hasColumns = false,
datasets,
}: FooterProps) {
+ const history = useHistory();
const { createResource } = useSingleViewResource<Partial<DatasetObject>>(
'dataset',
t('dataset'),
@@ -72,11 +73,6 @@ function Footer({
return LOG_ACTIONS[value];
};
- const goToPreviousUrl = () => {
- // this is a placeholder url until the final feature gets implemented
- // at that point we will be passing in the url of the previous location.
- window.location.href = url;
- };
const cancelButtonOnClick = () => {
if (!datasetObject) {
@@ -85,7 +81,7 @@ function Footer({
const logAction = createLogAction(datasetObject);
logEvent(logAction, datasetObject);
}
- goToPreviousUrl();
+ history.goBack();
};
const tooltipText = t('Select a database table.');
@@ -104,13 +100,13 @@ function Footer({
if (typeof response === 'number') {
logEvent(LOG_ACTIONS_DATASET_CREATION_SUCCESS, datasetObject);
// When a dataset is created the response we get is its ID number
- goToPreviousUrl();
+ history.push(`/chart/add/?dataset=${datasetObject.table_name}`);
}
});
}
};
- const CREATE_DATASET_TEXT = t('Create Dataset');
+ const CREATE_DATASET_TEXT = t('Create Dataset and Create Chart');
const disabledCheck =
!datasetObject?.table_name ||
!hasColumns ||
diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/LeftPanel.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/LeftPanel.test.tsx
index 7457f0c250..bc8c1d03de 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/LeftPanel.test.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/LeftPanel.test.tsx
@@ -21,6 +21,7 @@ import fetchMock from 'fetch-mock';
import userEvent from '@testing-library/user-event';
import { render, screen, waitFor } from 'spec/helpers/testing-library';
import LeftPanel from 'src/views/CRUD/data/dataset/AddDataset/LeftPanel';
+import { exampleDataset } from 'src/views/CRUD/data/dataset/AddDataset/DatasetPanel/fixtures';
const databasesEndpoint = 'glob:*/api/v1/database/?q*';
const schemasEndpoint = 'glob:*/api/v1/database/*/schemas*';
@@ -181,7 +182,7 @@ test('does not render blank state if there is nothing selected', async () => {
});
test('renders list of options when user clicks on schema', async () => {
- render(<LeftPanel setDataset={mockFun} schema="schema_a" dbId={1} />, {
+ render(<LeftPanel setDataset={mockFun} dataset={exampleDataset[0]} />, {
useRedux: true,
});
@@ -189,23 +190,21 @@ test('renders list of options when user clicks on schema', async () => {
const databaseSelect = screen.getByRole('combobox', {
name: 'Select database or type database name',
});
- // Schema select should be disabled until database is selected
- const schemaSelect = screen.getByRole('combobox', {
- name: /select schema or type schema name/i,
- });
userEvent.click(databaseSelect);
expect(await screen.findByText('test-postgres')).toBeInTheDocument();
- expect(schemaSelect).toBeDisabled();
userEvent.click(screen.getByText('test-postgres'));
- // Wait for schema field to be enabled
+ // Schema select will be automatically populated if there is only one schema
+ const schemaSelect = screen.getByRole('combobox', {
+ name: /select schema or type schema name/i,
+ });
await waitFor(() => {
expect(schemaSelect).toBeEnabled();
});
});
test('searches for a table name', async () => {
- render(<LeftPanel setDataset={mockFun} schema="schema_a" dbId={1} />, {
+ render(<LeftPanel setDataset={mockFun} dataset={exampleDataset[0]} />, {
useRedux: true,
});
@@ -245,9 +244,8 @@ test('renders a warning icon when a table name has a pre-existing dataset', asyn
render(
<LeftPanel
setDataset={mockFun}
- schema="schema_a"
- dbId={1}
- datasets={['Sheet2']}
+ dataset={exampleDataset[0]}
+ datasetNames={['Sheet2']}
/>,
{
useRedux: true,
diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx
index 4f7dfca196..14dd7dca4b 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx
@@ -16,7 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { useEffect, useState, SetStateAction, Dispatch } from 'react';
+import React, {
+ useEffect,
+ useState,
+ SetStateAction,
+ Dispatch,
+ useCallback,
+} from 'react';
import {
SupersetClient,
t,
@@ -40,13 +46,16 @@ import {
emptyStateComponent,
} from 'src/components/EmptyState';
import { useToasts } from 'src/components/MessageToasts/withToasts';
-import { DatasetActionType } from '../types';
+import { LocalStorageKeys, getItem } from 'src/utils/localStorageHelpers';
+import {
+ DatasetActionType,
+ DatasetObject,
+} from 'src/views/CRUD/data/dataset/AddDataset/types';
interface LeftPanelProps {
setDataset: Dispatch<SetStateAction<object>>;
- schema?: string | null | undefined;
- dbId?: number;
- datasets?: (string | null | undefined)[] | undefined;
+ dataset?: Partial<DatasetObject> | null;
+ datasetNames?: (string | null | undefined)[] | undefined;
}
const SearchIcon = styled(Icons.Search)`
@@ -145,9 +154,8 @@ const LeftPanelStyle = styled.div`
export default function LeftPanel({
setDataset,
- schema,
- dbId,
- datasets,
+ dataset,
+ datasetNames,
}: LeftPanelProps) {
const theme = useTheme();
@@ -160,11 +168,14 @@ export default function LeftPanel({
const { addDangerToast } = useToasts();
- const setDatabase = (db: Partial<DatabaseObject>) => {
- setDataset({ type: DatasetActionType.selectDatabase, payload: { db } });
- setSelectedTable(null);
- setResetTables(true);
- };
+ const setDatabase = useCallback(
+ (db: Partial<DatabaseObject>) => {
+ setDataset({ type: DatasetActionType.selectDatabase, payload: { db } });
+ setSelectedTable(null);
+ setResetTables(true);
+ },
+ [setDataset],
+ );
const setTable = (tableName: string, index: number) => {
setSelectedTable(index);
@@ -174,28 +185,32 @@ export default function LeftPanel({
});
};
- const getTablesList = (url: string) => {
- SupersetClient.get({ url })
- .then(({ json }) => {
- const options: TableOption[] = json.options.map((table: Table) => {
- const option: TableOption = {
- value: table.value,
- label: <TableOption table={table} />,
- text: table.label,
- };
+ const getTablesList = useCallback(
+ (url: string) => {
+ SupersetClient.get({ url })
+ .then(({ json }) => {
+ const options: TableOption[] = json.options.map((table: Table) => {
+ const option: TableOption = {
+ value: table.value,
+ label: <TableOption table={table} />,
+ text: table.label,
+ };
- return option;
- });
+ return option;
+ });
- setTableOptions(options);
- setLoadTables(false);
- setResetTables(false);
- setRefresh(false);
- })
- .catch(error =>
- logging.error('There was an error fetching tables', error),
- );
- };
+ setTableOptions(options);
+ setLoadTables(false);
+ setResetTables(false);
+ setRefresh(false);
+ })
+ .catch(error => {
+ addDangerToast(t('There was an error fetching tables'));
+ logging.error(t('There was an error fetching tables'), error);
+ });
+ },
+ [addDangerToast],
+ );
const setSchema = (schema: string) => {
if (schema) {
@@ -209,16 +224,28 @@ export default function LeftPanel({
setResetTables(true);
};
- const encodedSchema = schema ? encodeURIComponent(schema) : undefined;
+ const encodedSchema = dataset?.schema
+ ? encodeURIComponent(dataset?.schema)
+ : undefined;
+
+ useEffect(() => {
+ const currentUserSelectedDb = getItem(
+ LocalStorageKeys.db,
+ null,
+ ) as DatabaseObject;
+ if (currentUserSelectedDb) {
+ setDatabase(currentUserSelectedDb);
+ }
+ }, [setDatabase]);
useEffect(() => {
if (loadTables) {
const endpoint = encodeURI(
- `/superset/tables/${dbId}/${encodedSchema}/${refresh}/`,
+ `/superset/tables/${dataset?.db?.id}/${encodedSchema}/${refresh}/`,
);
getTablesList(endpoint);
}
- }, [loadTables]);
+ }, [loadTables, dataset?.db?.id, encodedSchema, getTablesList, refresh]);
useEffect(() => {
if (resetTables) {
@@ -262,6 +289,7 @@ export default function LeftPanel({
{SELECT_DATABASE_AND_SCHEMA_TEXT}
</p>
<DatabaseSelector
+ db={dataset?.db}
handleError={addDangerToast}
onDbChange={setDatabase}
onSchemaChange={setSchema}
@@ -269,7 +297,7 @@ export default function LeftPanel({
onEmptyResults={onEmptyResults}
/>
{loadTables && !refresh && Loader(TABLE_LOADING_TEXT)}
- {schema && !loadTables && !tableOptions.length && !searchVal && (
+ {dataset?.schema && !loadTables && !tableOptions.length && !searchVal && (
<div className="emptystate">
<EmptyStateMedium
image="empty-table.svg"
@@ -279,7 +307,7 @@ export default function LeftPanel({
</div>
)}
- {schema && (tableOptions.length > 0 || searchVal.length > 0) && (
+ {dataset?.schema && (tableOptions.length > 0 || searchVal.length > 0) && (
<>
<Form>
<p className="table-title">{SELECT_DATABASE_TABLE_TEXT}</p>
@@ -323,7 +351,7 @@ export default function LeftPanel({
onClick={() => setTable(option.value, i)}
>
{option.label}
- {datasets?.includes(option.value) && (
+ {datasetNames?.includes(option.value) && (
<Icons.Warning
iconColor={
selectedTable === i
diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/index.tsx
index e4dbaa9a69..1cb4b0d5ae 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/index.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/index.tsx
@@ -16,10 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { useReducer, Reducer, useEffect, useState } from 'react';
-import { logging } from '@superset-ui/core';
+import React, {
+ useReducer,
+ Reducer,
+ useEffect,
+ useState,
+ useCallback,
+} from 'react';
+import { logging, t } from '@superset-ui/core';
import { UseGetDatasetsList } from 'src/views/CRUD/data/hooks';
import rison from 'rison';
+import { addDangerToast } from 'src/components/MessageToasts/actions';
import Header from './Header';
import DatasetPanel from './DatasetPanel';
import LeftPanel from './LeftPanel';
@@ -85,27 +92,29 @@ export default function AddDataset() {
const queryParams = dataset?.schema
? rison.encode_uri({
filters: [
+ { col: 'database', opr: 'rel_o_m', value: dataset?.db?.id },
{ col: 'schema', opr: 'eq', value: encodedSchema },
{ col: 'sql', opr: 'dataset_is_null_or_empty', value: '!t' },
],
})
: undefined;
- const getDatasetsList = async () => {
+ const getDatasetsList = useCallback(async () => {
await UseGetDatasetsList(queryParams)
.then(json => {
setDatasets(json?.result);
})
- .catch(error =>
- logging.error('There was an error fetching dataset', error),
- );
- };
+ .catch(error => {
+ addDangerToast(t('There was an error fetching dataset'));
+ logging.error(t('There was an error fetching dataset'), error);
+ });
+ }, [queryParams]);
useEffect(() => {
if (dataset?.schema) {
getDatasetsList();
}
- }, [dataset?.schema]);
+ }, [dataset?.schema, getDatasetsList]);
const HeaderComponent = () => (
<Header setDataset={setDataset} title={dataset?.table_name} />
@@ -114,9 +123,8 @@ export default function AddDataset() {
const LeftPanelComponent = () => (
<LeftPanel
setDataset={setDataset}
- schema={dataset?.schema}
- dbId={dataset?.db?.id}
- datasets={datasetNames}
+ dataset={dataset}
+ datasetNames={datasetNames}
/>
);
diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/types.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/types.tsx
index dbeef93ead..89473e5426 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/types.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/types.tsx
@@ -16,6 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { DatabaseObject } from 'src/components/DatabaseSelector';
+
export enum DatasetActionType {
selectDatabase,
selectSchema,
@@ -24,11 +26,7 @@ export enum DatasetActionType {
}
export interface DatasetObject {
- db: {
- id: number;
- database_name?: string;
- owners?: number[];
- };
+ db: DatabaseObject & { owners: [number] };
schema?: string | null;
dataset_name: string;
table_name?: string | null;
diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx
deleted file mode 100644
index d4b1470f38..0000000000
--- a/superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import React, { FunctionComponent, useState, useEffect } from 'react';
-import { styled, t } from '@superset-ui/core';
-import { useSingleViewResource } from 'src/views/CRUD/hooks';
-import Modal from 'src/components/Modal';
-import TableSelector from 'src/components/TableSelector';
-import withToasts from 'src/components/MessageToasts/withToasts';
-import { DatabaseObject } from 'src/components/DatabaseSelector';
-import {
- getItem,
- LocalStorageKeys,
- setItem,
-} from 'src/utils/localStorageHelpers';
-import { isEmpty } from 'lodash';
-
-type DatasetAddObject = {
- id: number;
- database: number;
- schema: string;
- table_name: string;
-};
-interface DatasetModalProps {
- addDangerToast: (msg: string) => void;
- addSuccessToast: (msg: string) => void;
- onDatasetAdd?: (dataset: DatasetAddObject) => void;
- onHide: () => void;
- show: boolean;
- history?: any; // So we can render the modal when not using SPA
-}
-
-const TableSelectorContainer = styled.div`
- padding-bottom: 340px;
- width: 65%;
-`;
-
-const DatasetModal: FunctionComponent<DatasetModalProps> = ({
- addDangerToast,
- onDatasetAdd,
- onHide,
- show,
- history,
-}) => {
- const [currentDatabase, setCurrentDatabase] = useState<
- DatabaseObject | undefined
- >();
- const [currentSchema, setSchema] = useState<string | undefined>('');
- const [currentTableName, setTableName] = useState('');
- const [disableSave, setDisableSave] = useState(true);
- const {
- createResource,
- state: { loading },
- } = useSingleViewResource<Partial<DatasetAddObject>>(
- 'dataset',
- t('dataset'),
- addDangerToast,
- );
-
- useEffect(() => {
- setDisableSave(currentDatabase === undefined || currentTableName === '');
- }, [currentTableName, currentDatabase]);
-
- useEffect(() => {
- const currentUserSelectedDb = getItem(
- LocalStorageKeys.db,
- null,
- ) as DatabaseObject;
- if (currentUserSelectedDb) setCurrentDatabase(currentUserSelectedDb);
- }, []);
-
- const onDbChange = (db: DatabaseObject) => {
- setCurrentDatabase(db);
- };
-
- const onSchemaChange = (schema?: string) => {
- setSchema(schema);
- };
-
- const onTableChange = (tableName: string) => {
- setTableName(tableName);
- };
-
- const clearModal = () => {
- setSchema('');
- setTableName('');
- setCurrentDatabase(undefined);
- setDisableSave(true);
- };
-
- const cleanup = () => {
- clearModal();
- setItem(LocalStorageKeys.db, null);
- };
-
- const hide = () => {
- cleanup();
- onHide();
- };
-
- const onSave = () => {
- if (currentDatabase === undefined) {
- return;
- }
- const data = {
- database: currentDatabase.id,
- ...(currentSchema ? { schema: currentSchema } : {}),
- table_name: currentTableName,
- };
- createResource(data).then(response => {
- if (!response) {
- return;
- }
- if (onDatasetAdd) {
- onDatasetAdd({ id: response.id, ...response });
- }
- // We need to be able to work with no SPA routes opening the modal
- // So useHistory wont be available always thus we check for it
- if (!isEmpty(history)) {
- history?.push(`/chart/add?dataset=${currentTableName}`);
- cleanup();
- } else {
- window.location.href = `/chart/add?dataset=${currentTableName}`;
- cleanup();
- onHide();
- }
- });
- };
-
- return (
- <Modal
- disablePrimaryButton={disableSave}
- primaryButtonLoading={loading}
- onHandledPrimaryAction={onSave}
- onHide={hide}
- primaryButtonName={t('Add Dataset and Create Chart')}
- show={show}
- title={t('Add dataset')}
- >
- <TableSelectorContainer>
- <TableSelector
- clearable={false}
- formMode
- database={currentDatabase}
- schema={currentSchema}
- tableValue={currentTableName}
- onDbChange={onDbChange}
- onSchemaChange={onSchemaChange}
- onTableSelectChange={onTableChange}
- handleError={addDangerToast}
- />
- </TableSelectorContainer>
- </Modal>
- );
-};
-
-export default withToasts(DatasetModal);
diff --git a/superset-frontend/src/views/CRUD/data/dataset/DatasetLayout/DatasetLayout.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/DatasetLayout/DatasetLayout.test.tsx
index 35375a52b4..a1939761aa 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/DatasetLayout/DatasetLayout.test.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/DatasetLayout/DatasetLayout.test.tsx
@@ -25,6 +25,14 @@ import DatasetPanel from 'src/views/CRUD/data/dataset/AddDataset/DatasetPanel';
import RightPanel from 'src/views/CRUD/data/dataset/AddDataset/RightPanel';
import Footer from 'src/views/CRUD/data/dataset/AddDataset/Footer';
+const mockHistoryPush = jest.fn();
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useHistory: () => ({
+ push: mockHistoryPush,
+ }),
+}));
+
describe('DatasetLayout', () => {
it('renders nothing when no components are passed in', () => {
render(<DatasetLayout />);
diff --git a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx
index 68c65a7ad1..0906776506 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx
@@ -22,16 +22,14 @@ import React, {
useState,
useMemo,
useCallback,
- useEffect,
} from 'react';
+import { useHistory } from 'react-router-dom';
import rison from 'rison';
-import { useHistory, useLocation } from 'react-router-dom';
import {
createFetchRelated,
createFetchDistinct,
createErrorHandler,
} from 'src/views/CRUD/utils';
-import { getItem, LocalStorageKeys } from 'src/utils/localStorageHelpers';
import { ColumnObject } from 'src/views/CRUD/data/dataset/types';
import { useListViewResource } from 'src/views/CRUD/hooks';
import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
@@ -60,7 +58,6 @@ import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
import WarningIconWithTooltip from 'src/components/WarningIconWithTooltip';
import { isUserAdmin } from 'src/dashboard/util/permissionUtils';
import { GenericLink } from 'src/components/GenericLink/GenericLink';
-import AddDatasetModal from './AddDatasetModal';
import {
PAGE_SIZE,
@@ -139,6 +136,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
addSuccessToast,
user,
}) => {
+ const history = useHistory();
const {
state: {
loading,
@@ -152,9 +150,6 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
refreshData,
} = useListViewResource<Dataset>('dataset', t('dataset'), addDangerToast);
- const [datasetAddModalOpen, setDatasetAddModalOpen] =
- useState<boolean>(false);
-
const [datasetCurrentlyDeleting, setDatasetCurrentlyDeleting] = useState<
(Dataset & { chart_count: number; dashboard_count: number }) | null
>(null);
@@ -191,12 +186,6 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
hasPerm('can_export') && isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT);
const initialSort = SORT_BY;
- useEffect(() => {
- const db = getItem(LocalStorageKeys.db, null);
- if (!loading && db) {
- setDatasetAddModalOpen(true);
- }
- }, [loading]);
const openDatasetEditModal = useCallback(
({ id }: Dataset) => {
@@ -603,26 +592,6 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
});
}
- const CREATE_HASH = '#create';
- const location = useLocation();
- const history = useHistory();
-
- // Sync Dataset Add modal with #create hash
- useEffect(() => {
- const modalOpen = location.hash === CREATE_HASH && canCreate;
- setDatasetAddModalOpen(modalOpen);
- }, [canCreate, location.hash]);
-
- // Add #create hash
- const openDatasetAddModal = useCallback(() => {
- history.replace(`${location.pathname}${location.search}${CREATE_HASH}`);
- }, [history, location.pathname, location.search]);
-
- // Remove #create hash
- const closeDatasetAddModal = useCallback(() => {
- history.replace(`${location.pathname}${location.search}`);
- }, [history, location.pathname, location.search]);
-
if (canCreate) {
buttonArr.push({
name: (
@@ -630,7 +599,9 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
<i className="fa fa-plus" /> {t('Dataset')}{' '}
</>
),
- onClick: openDatasetAddModal,
+ onClick: () => {
+ history.push('/dataset/add/');
+ },
buttonStyle: 'primary',
});
@@ -727,12 +698,6 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
return (
<>
<SubMenu {...menuData} />
- <AddDatasetModal
- show={datasetAddModalOpen}
- onHide={closeDatasetAddModal}
- onDatasetAdd={refreshData}
- history={history}
- />
{datasetCurrentlyDeleting && (
<DeleteModal
description={t(
diff --git a/superset-frontend/src/views/CRUD/data/hooks.ts b/superset-frontend/src/views/CRUD/data/hooks.ts
index 2f2bdd9a2c..e15e4be957 100644
--- a/superset-frontend/src/views/CRUD/data/hooks.ts
+++ b/superset-frontend/src/views/CRUD/data/hooks.ts
@@ -17,7 +17,8 @@
* under the License.
*/
import { useState, useEffect } from 'react';
-import { SupersetClient, logging } from '@superset-ui/core';
+import { SupersetClient, logging, t } from '@superset-ui/core';
+import { addDangerToast } from 'src/components/MessageToasts/actions';
type BaseQueryObject = {
id: number;
@@ -80,6 +81,7 @@ export const UseGetDatasetsList = (queryParams: string | undefined) =>
endpoint: `/api/v1/dataset/?q=${queryParams}`,
})
.then(({ json }) => json)
- .catch(error =>
- logging.error('There was an error fetching dataset', error),
- );
+ .catch(error => {
+ addDangerToast(t('There was an error fetching dataset'));
+ logging.error(t('There was an error fetching dataset'), error);
+ });
diff --git a/superset-frontend/src/views/components/RightMenu.test.tsx b/superset-frontend/src/views/components/RightMenu.test.tsx
index ec12e644db..907c305ff6 100644
--- a/superset-frontend/src/views/components/RightMenu.test.tsx
+++ b/superset-frontend/src/views/components/RightMenu.test.tsx
@@ -30,9 +30,6 @@ jest.mock('react-redux', () => ({
}));
jest.mock('src/views/CRUD/data/database/DatabaseModal', () => () => <span />);
-jest.mock('src/views/CRUD/data/dataset/AddDatasetModal.tsx', () => () => (
- <span />
-));
const dropdownItems = [
{
diff --git a/superset-frontend/src/views/components/RightMenu.tsx b/superset-frontend/src/views/components/RightMenu.tsx
index 59e7f7f448..1957060502 100644
--- a/superset-frontend/src/views/components/RightMenu.tsx
+++ b/superset-frontend/src/views/components/RightMenu.tsx
@@ -51,7 +51,6 @@ import {
GlobalMenuDataOptions,
RightMenuProps,
} from './types';
-import AddDatasetModal from '../CRUD/data/dataset/AddDatasetModal';
const extensionsRegistry = getExtensionsRegistry();
@@ -143,7 +142,6 @@ const RightMenu = ({
HAS_GSHEETS_INSTALLED,
} = useSelector<any, ExtentionConfigs>(state => state.common.conf);
const [showDatabaseModal, setShowDatabaseModal] = useState<boolean>(false);
- const [showDatasetModal, setShowDatasetModal] = useState<boolean>(false);
const [engine, setEngine] = useState<string>('');
const canSql = findPermission('can_sqllab', 'Superset', roles);
const canDashboard = findPermission('can_write', 'Dashboard', roles);
@@ -179,6 +177,7 @@ const RightMenu = ({
{
label: t('Create dataset'),
name: GlobalMenuDataOptions.DATASET_CREATION,
+ url: '/dataset/add/',
perm: canDataset && nonExamplesDBConnected,
},
{
@@ -286,8 +285,6 @@ const RightMenu = ({
} else if (itemChose.key === GlobalMenuDataOptions.GOOGLE_SHEETS) {
setShowDatabaseModal(true);
setEngine('Google Sheets');
- } else if (itemChose.key === GlobalMenuDataOptions.DATASET_CREATION) {
- setShowDatasetModal(true);
}
};
@@ -296,10 +293,6 @@ const RightMenu = ({
setShowDatabaseModal(false);
};
- const handleOnHideDatasetModalModal = () => {
- setShowDatasetModal(false);
- };
-
const isDisabled = isAdmin && !allowUploads;
const tooltipText = t(
@@ -344,7 +337,6 @@ const RightMenu = ({
);
const handleDatabaseAdd = () => setQuery({ databaseAdded: true });
- const handleDatasetAdd = () => setQuery({ datasetAdded: true });
const theme = useTheme();
@@ -358,13 +350,6 @@ const RightMenu = ({
onDatabaseAdd={handleDatabaseAdd}
/>
)}
- {canDataset && (
- <AddDatasetModal
- onHide={handleOnHideDatasetModalModal}
- show={showDatasetModal}
- onDatasetAdd={handleDatasetAdd}
- />
- )}
{environmentTag?.text && (
<Label
css={{ borderRadius: `${theme.gridUnit * 125}px` }}
diff --git a/superset/views/datasource/views.py b/superset/views/datasource/views.py
index c2db174cb1..4f158e8369 100644
--- a/superset/views/datasource/views.py
+++ b/superset/views/datasource/views.py
@@ -228,10 +228,7 @@ class DatasetEditor(BaseSupersetView):
@has_access
@permission_name("read")
def root(self) -> FlaskResponse:
- dev = request.args.get("testing")
- if dev is not None:
- return super().render_app_template()
- return redirect("/")
+ return super().render_app_template()
@expose("/<pk>", methods=["GET"])
@has_access