fix: A newly connected database doesn't appear in the databases list if user connected database using the 'plus' button (#19967)

* fix: A newly connected database doesn't appear in the databases list if user connected database using the 'plus' button

* include onDatabaseAdd on successful import
This commit is contained in:
Diego Medina 2022-06-12 11:21:30 -03:00 committed by GitHub
parent 86368dd406
commit 8345eb4644
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 21 deletions

View File

@ -20,6 +20,8 @@ import { SupersetClient, t, styled } from '@superset-ui/core';
import React, { useState, useMemo, useEffect } from 'react';
import rison from 'rison';
import { useSelector } from 'react-redux';
import { useQueryParams, BooleanParam } from 'use-query-params';
import Loading from 'src/components/Loading';
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
import { useListViewResource } from 'src/views/CRUD/hooks';
@ -91,6 +93,10 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
state => state.user,
);
const [query, setQuery] = useQueryParams({
databaseAdded: BooleanParam,
});
const [databaseModalOpen, setDatabaseModalOpen] = useState<boolean>(false);
const [databaseCurrentlyDeleting, setDatabaseCurrentlyDeleting] =
useState<DatabaseDeleteObject | null>(null);
@ -110,6 +116,13 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
ALLOWED_EXTENSIONS,
} = useSelector<any, ExtentionConfigs>(state => state.common.conf);
useEffect(() => {
if (query?.databaseAdded) {
setQuery({ databaseAdded: undefined });
refreshData();
}
}, [query, setQuery, refreshData]);
const openDatabaseDeleteModal = (database: DatabaseObject) =>
SupersetClient.get({
endpoint: `/api/v1/database/${database.id}/related_objects/`,

View File

@ -519,7 +519,6 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
setImportingModal(false);
setPasswords({});
setConfirmedOverwrite(false);
if (onDatabaseAdd) onDatabaseAdd();
onHide();
};
@ -652,6 +651,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
confirmedOverwrite,
);
if (dbId) {
if (onDatabaseAdd) onDatabaseAdd();
onClose();
addSuccessToast(t('Database connected'));
}

View File

@ -248,13 +248,16 @@ beforeEach(() => {
test('should render', () => {
useSelectorMock.mockReturnValue({ roles: user.roles });
const { container } = render(<Menu {...mockedProps} />, { useRedux: true });
const { container } = render(<Menu {...mockedProps} />, {
useRedux: true,
useQueryParams: true,
});
expect(container).toBeInTheDocument();
});
test('should render the navigation', () => {
useSelectorMock.mockReturnValue({ roles: user.roles });
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
expect(screen.getByRole('navigation')).toBeInTheDocument();
});
@ -265,7 +268,7 @@ test('should render the brand', () => {
brand: { alt, icon },
},
} = mockedProps;
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
const image = screen.getByAltText(alt);
expect(image).toHaveAttribute('src', icon);
});
@ -275,7 +278,7 @@ test('should render all the top navbar menu items', () => {
const {
data: { menu },
} = mockedProps;
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
menu.forEach(item => {
expect(screen.getByText(item.label)).toBeInTheDocument();
});
@ -286,7 +289,7 @@ test('should render the top navbar child menu items', async () => {
const {
data: { menu },
} = mockedProps;
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
const sources = screen.getByText('Sources');
userEvent.hover(sources);
const datasets = await screen.findByText('Datasets');
@ -300,7 +303,7 @@ test('should render the top navbar child menu items', async () => {
test('should render the dropdown items', async () => {
useSelectorMock.mockReturnValue({ roles: user.roles });
render(<Menu {...notanonProps} />, { useRedux: true });
render(<Menu {...notanonProps} />, { useRedux: true, useQueryParams: true });
const dropdown = screen.getByTestId('new-dropdown-icon');
userEvent.hover(dropdown);
// todo (philip): test data submenu
@ -326,14 +329,14 @@ test('should render the dropdown items', async () => {
test('should render the Settings', async () => {
useSelectorMock.mockReturnValue({ roles: user.roles });
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
const settings = await screen.findByText('Settings');
expect(settings).toBeInTheDocument();
});
test('should render the Settings menu item', async () => {
useSelectorMock.mockReturnValue({ roles: user.roles });
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
userEvent.hover(screen.getByText('Settings'));
const label = await screen.findByText('Security');
expect(label).toBeInTheDocument();
@ -344,7 +347,7 @@ test('should render the Settings dropdown child menu items', async () => {
const {
data: { settings },
} = mockedProps;
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
userEvent.hover(screen.getByText('Settings'));
const listUsers = await screen.findByText('List Users');
expect(listUsers).toHaveAttribute('href', settings[0].childs[0].url);
@ -352,13 +355,13 @@ test('should render the Settings dropdown child menu items', async () => {
test('should render the plus menu (+) when user is not anonymous', () => {
useSelectorMock.mockReturnValue({ roles: user.roles });
render(<Menu {...notanonProps} />, { useRedux: true });
render(<Menu {...notanonProps} />, { useRedux: true, useQueryParams: true });
expect(screen.getByTestId('new-dropdown')).toBeInTheDocument();
});
test('should NOT render the plus menu (+) when user is anonymous', () => {
useSelectorMock.mockReturnValue({ roles: user.roles });
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
expect(screen.queryByTestId('new-dropdown')).not.toBeInTheDocument();
});
@ -370,7 +373,7 @@ test('should render the user actions when user is not anonymous', async () => {
},
} = mockedProps;
render(<Menu {...notanonProps} />, { useRedux: true });
render(<Menu {...notanonProps} />, { useRedux: true, useQueryParams: true });
userEvent.hover(screen.getByText('Settings'));
const user = await screen.findByText('User');
expect(user).toBeInTheDocument();
@ -384,7 +387,7 @@ test('should render the user actions when user is not anonymous', async () => {
test('should NOT render the user actions when user is anonymous', () => {
useSelectorMock.mockReturnValue({ roles: user.roles });
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
expect(screen.queryByText('User')).not.toBeInTheDocument();
});
@ -396,7 +399,7 @@ test('should render the Profile link when available', async () => {
},
} = mockedProps;
render(<Menu {...notanonProps} />, { useRedux: true });
render(<Menu {...notanonProps} />, { useRedux: true, useQueryParams: true });
userEvent.hover(screen.getByText('Settings'));
const profile = await screen.findByText('Profile');
@ -411,7 +414,7 @@ test('should render the About section and version_string, sha or build_number wh
},
} = mockedProps;
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
userEvent.hover(screen.getByText('Settings'));
const about = await screen.findByText('About');
const version = await screen.findByText(`Version: ${version_string}`);
@ -430,7 +433,7 @@ test('should render the Documentation link when available', async () => {
navbar_right: { documentation_url },
},
} = mockedProps;
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
userEvent.hover(screen.getByText('Settings'));
const doc = await screen.findByTitle('Documentation');
expect(doc).toHaveAttribute('href', documentation_url);
@ -444,7 +447,7 @@ test('should render the Bug Report link when available', async () => {
},
} = mockedProps;
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
const bugReport = await screen.findByTitle('Report a bug');
expect(bugReport).toHaveAttribute('href', bug_report_url);
});
@ -457,19 +460,19 @@ test('should render the Login link when user is anonymous', () => {
},
} = mockedProps;
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
const login = screen.getByText('Login');
expect(login).toHaveAttribute('href', user_login_url);
});
test('should render the Language Picker', () => {
useSelectorMock.mockReturnValue({ roles: user.roles });
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
expect(screen.getByLabelText('Languages')).toBeInTheDocument();
});
test('should hide create button without proper roles', () => {
useSelectorMock.mockReturnValue({ roles: [] });
render(<Menu {...mockedProps} />, { useRedux: true });
render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true });
expect(screen.queryByTestId('new-dropdown')).not.toBeInTheDocument();
});

View File

@ -20,6 +20,8 @@ import React, { Fragment, useState, useEffect } from 'react';
import rison from 'rison';
import { useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { useQueryParams, BooleanParam } from 'use-query-params';
import {
t,
styled,
@ -94,6 +96,10 @@ const RightMenu = ({
state => state.dashboardInfo?.id,
);
const [, setQuery] = useQueryParams({
databaseAdded: BooleanParam,
});
const { roles } = user;
const {
CSV_EXTENSIONS,
@ -250,6 +256,8 @@ const RightMenu = ({
return null;
};
const handleDatabaseAdd = () => setQuery({ databaseAdded: true });
return (
<StyledDiv align={align}>
{canDatabase && (
@ -257,6 +265,7 @@ const RightMenu = ({
onHide={handleOnHideModal}
show={showModal}
dbEngine={engine}
onDatabaseAdd={handleDatabaseAdd}
/>
)}
<Menu