From a846015f4d01c78fe84f78883c0423e5c2d519c6 Mon Sep 17 00:00:00 2001
From: Lyndsi Kay Williams <55605634+lyndsiWilliams@users.noreply.github.com>
Date: Tue, 20 Apr 2021 18:59:48 -0500
Subject: [PATCH] fix: Center each import icon and add a tooltip II (#14192)
---
.../views/CRUD/chart/ChartList_spec.jsx | 45 +++++++++++++++++++
.../CRUD/dashboard/DashboardList_spec.jsx | 45 +++++++++++++++++++
.../CRUD/data/database/DatabaseList_spec.jsx | 44 ++++++++++++++++++
.../CRUD/data/dataset/DatasetList_spec.jsx | 45 +++++++++++++++++++
.../data/savedquery/SavedQueryList_spec.jsx | 34 +++++++++-----
.../src/components/Menu/SubMenu.tsx | 2 +
.../src/views/CRUD/chart/ChartList.tsx | 10 ++++-
.../views/CRUD/dashboard/DashboardList.tsx | 10 ++++-
.../views/CRUD/data/database/DatabaseList.tsx | 10 ++++-
.../views/CRUD/data/dataset/DatasetList.tsx | 10 ++++-
.../CRUD/data/savedquery/SavedQueryList.tsx | 14 +++++-
11 files changed, 252 insertions(+), 17 deletions(-)
diff --git a/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx
index dfd19b7da3f..00d74033c68 100644
--- a/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx
+++ b/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx
@@ -24,6 +24,10 @@ import fetchMock from 'fetch-mock';
import * as featureFlags from 'src/featureFlags';
import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint';
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 { act } from 'react-dom/test-utils';
import ChartList from 'src/views/CRUD/chart/ChartList';
import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
@@ -156,3 +160,44 @@ describe('ChartList', () => {
expect(wrapper.find(ConfirmStatusChange)).toExist();
});
});
+
+describe('RTL', () => {
+ async function renderAndWait() {
+ const mounted = act(async () => {
+ const mockedProps = {};
+ render(
+
+
+ ,
+ { useRedux: true },
+ );
+ });
+
+ return mounted;
+ }
+
+ let isFeatureEnabledMock;
+ beforeEach(async () => {
+ isFeatureEnabledMock = jest
+ .spyOn(featureFlags, 'isFeatureEnabled')
+ .mockImplementation(() => true);
+ await renderAndWait();
+ });
+
+ afterEach(() => {
+ cleanup();
+ isFeatureEnabledMock.mockRestore();
+ });
+
+ it('renders an "Import Chart" tooltip under import button', async () => {
+ const importButton = screen.getByTestId('import-button');
+ userEvent.hover(importButton);
+
+ await screen.findByRole('tooltip');
+ const importTooltip = screen.getByRole('tooltip', {
+ name: 'Import charts',
+ });
+
+ expect(importTooltip).toBeInTheDocument();
+ });
+});
diff --git a/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx
index c8d26862494..8bb9a48b11d 100644
--- a/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx
+++ b/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx
@@ -25,6 +25,10 @@ import * as featureFlags from 'src/featureFlags';
import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint';
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 { act } from 'react-dom/test-utils';
import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
import DashboardList from 'src/views/CRUD/dashboard/DashboardList';
@@ -172,3 +176,44 @@ describe('DashboardList', () => {
expect(wrapper.find(ConfirmStatusChange)).toExist();
});
});
+
+describe('RTL', () => {
+ async function renderAndWait() {
+ const mounted = act(async () => {
+ const mockedProps = {};
+ render(
+
+
+ ,
+ { useRedux: true },
+ );
+ });
+
+ return mounted;
+ }
+
+ let isFeatureEnabledMock;
+ beforeEach(async () => {
+ isFeatureEnabledMock = jest
+ .spyOn(featureFlags, 'isFeatureEnabled')
+ .mockImplementation(() => true);
+ await renderAndWait();
+ });
+
+ afterEach(() => {
+ cleanup();
+ isFeatureEnabledMock.mockRestore();
+ });
+
+ it('renders an "Import Dashboard" tooltip under import button', async () => {
+ const importButton = screen.getByTestId('import-button');
+ userEvent.hover(importButton);
+
+ await screen.findByRole('tooltip');
+ const importTooltip = screen.getByRole('tooltip', {
+ name: 'Import dashboards',
+ });
+
+ expect(importTooltip).toBeInTheDocument();
+ });
+});
diff --git a/superset-frontend/spec/javascripts/views/CRUD/data/database/DatabaseList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/data/database/DatabaseList_spec.jsx
index 56455779d06..eabbc915b0a 100644
--- a/superset-frontend/spec/javascripts/views/CRUD/data/database/DatabaseList_spec.jsx
+++ b/superset-frontend/spec/javascripts/views/CRUD/data/database/DatabaseList_spec.jsx
@@ -22,6 +22,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';
@@ -178,3 +182,43 @@ describe('DatabaseList', () => {
);
});
});
+
+describe('RTL', () => {
+ async function renderAndWait() {
+ const mounted = act(async () => {
+ render(
+
+
+ ,
+ { useRedux: true },
+ );
+ });
+
+ 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 = screen.getByTestId('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/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx
index a816a60910f..b141da8d302 100644
--- a/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx
+++ b/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx
@@ -22,6 +22,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 DatasetList from 'src/views/CRUD/data/dataset/DatasetList';
import ListView from 'src/components/ListView';
@@ -175,3 +179,44 @@ describe('DatasetList', () => {
).toMatchInlineSnapshot(`"3 Selected (2 Physical, 1 Virtual)"`);
});
});
+
+describe('RTL', () => {
+ async function renderAndWait() {
+ const mounted = act(async () => {
+ const mockedProps = {};
+ render(
+
+
+ ,
+ { useRedux: true },
+ );
+ });
+
+ return mounted;
+ }
+
+ let isFeatureEnabledMock;
+ beforeEach(async () => {
+ isFeatureEnabledMock = jest
+ .spyOn(featureFlags, 'isFeatureEnabled')
+ .mockImplementation(() => true);
+ await renderAndWait();
+ });
+
+ afterEach(() => {
+ cleanup();
+ isFeatureEnabledMock.mockRestore();
+ });
+
+ it('renders an "Import Dataset" tooltip under import button', async () => {
+ const importButton = screen.getByTestId('import-button');
+ userEvent.hover(importButton);
+
+ await screen.findByRole('tooltip');
+ const importTooltip = screen.getByRole('tooltip', {
+ name: 'Import datasets',
+ });
+
+ expect(importTooltip).toBeInTheDocument();
+ });
+});
diff --git a/superset-frontend/spec/javascripts/views/CRUD/data/savedquery/SavedQueryList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/data/savedquery/SavedQueryList_spec.jsx
index 019c8c3fa8c..ac6f8c293e5 100644
--- a/superset-frontend/spec/javascripts/views/CRUD/data/savedquery/SavedQueryList_spec.jsx
+++ b/superset-frontend/spec/javascripts/views/CRUD/data/savedquery/SavedQueryList_spec.jsx
@@ -22,7 +22,7 @@ import configureStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import fetchMock from 'fetch-mock';
import { styledMount as mount } from 'spec/helpers/theming';
-import { render, screen, cleanup } from 'spec/helpers/testing-library';
+import { render, screen, cleanup, waitFor } from 'spec/helpers/testing-library';
import userEvent from '@testing-library/user-event';
import { QueryParamProvider } from 'use-query-params';
import { act } from 'react-dom/test-utils';
@@ -229,10 +229,9 @@ describe('RTL', () => {
const mounted = act(async () => {
render(
-
-
-
+
,
+ { useRedux: true },
);
});
@@ -296,26 +295,39 @@ describe('RTL', () => {
it('renders an import button in the submenu', () => {
// Grab and assert that import saved query button is visible
- const importSavedQueryButton = screen.getAllByRole('button')[2];
- expect(importSavedQueryButton).toBeVisible();
+ const importButton = screen.getByTestId('import-button');
+ expect(importButton).toBeVisible();
+ });
+
+ it('renders an "Import Saved Query" tooltip under import button', async () => {
+ const importButton = screen.getByTestId('import-button');
+ userEvent.hover(importButton);
+ waitFor(() => {
+ expect(importButton).toHaveClass('ant-tooltip-open');
+ screen.findByTestId('import-tooltip-test');
+ const importTooltip = screen.getByRole('tooltip', {
+ name: 'Import queries',
+ });
+ expect(importTooltip).toBeInTheDocument();
+ });
});
it('renders an import model when import button is clicked', async () => {
// Grab and click import saved query button to reveal modal
- const importSavedQueryButton = screen.getAllByRole('button')[2];
- userEvent.click(importSavedQueryButton);
+ const importButton = screen.getByTestId('import-button');
+ userEvent.click(importButton);
// Grab and assert that saved query import modal's heading is visible
const importSavedQueryModalHeading = screen.getByRole('heading', {
- name: /import saved query/i,
+ name: 'Import queries',
});
expect(importSavedQueryModalHeading).toBeVisible();
});
it('imports a saved query', () => {
// Grab and click import saved query button to reveal modal
- const importSavedQueryButton = screen.getAllByRole('button')[2];
- userEvent.click(importSavedQueryButton);
+ const importButton = screen.getByTestId('import-button');
+ userEvent.click(importButton);
// Grab "Choose File" input from import modal
const chooseFileInput = screen.getByLabelText(/file\*/i);
diff --git a/superset-frontend/src/components/Menu/SubMenu.tsx b/superset-frontend/src/components/Menu/SubMenu.tsx
index d109aa7f4c5..f8f9e3a9d34 100644
--- a/superset-frontend/src/components/Menu/SubMenu.tsx
+++ b/superset-frontend/src/components/Menu/SubMenu.tsx
@@ -33,6 +33,8 @@ const StyledHeader = styled.header`
margin-right: ${({ theme }) => theme.gridUnit * 3}px;
}
.navbar-right {
+ display: flex;
+ align-items: center;
padding: 8px 0;
margin-right: 0;
}
diff --git a/superset-frontend/src/views/CRUD/chart/ChartList.tsx b/superset-frontend/src/views/CRUD/chart/ChartList.tsx
index 368db789d2b..7667b913e49 100644
--- a/superset-frontend/src/views/CRUD/chart/ChartList.tsx
+++ b/superset-frontend/src/views/CRUD/chart/ChartList.tsx
@@ -553,7 +553,15 @@ function ChartList(props: ChartListProps) {
}
if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) {
subMenuButtons.push({
- name: ,
+ name: (
+
+
+
+ ),
buttonStyle: 'link',
onClick: openChartImportModal,
});
diff --git a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx
index 6113ed69c47..28efa59ac2f 100644
--- a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx
+++ b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx
@@ -500,7 +500,15 @@ function DashboardList(props: DashboardListProps) {
}
if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) {
subMenuButtons.push({
- name: ,
+ name: (
+
+
+
+ ),
buttonStyle: 'link',
onClick: openDashboardImportModal,
});
diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx
index 13d2ab8b540..81c99105c8a 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx
@@ -184,7 +184,15 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) {
if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) {
menuData.buttons.push({
- name: ,
+ name: (
+
+
+
+ ),
buttonStyle: 'link',
onClick: openDatabaseImportModal,
});
diff --git a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx
index b6806dd17d3..e37c6fd27f4 100644
--- a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx
+++ b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx
@@ -492,7 +492,15 @@ const DatasetList: FunctionComponent = ({
if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) {
buttonArr.push({
- name: ,
+ name: (
+
+
+
+ ),
buttonStyle: 'link',
onClick: openDatasetImportModal,
});
diff --git a/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx b/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx
index 9f90bf559be..83200bdfef8 100644
--- a/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx
+++ b/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx
@@ -38,6 +38,7 @@ import SubMenu, {
import ListView, { ListViewProps, Filters } from 'src/components/ListView';
import DeleteModal from 'src/components/DeleteModal';
import ActionsBar, { ActionProps } from 'src/components/ListView/ActionsBar';
+import { Tooltip } from 'src/common/components/Tooltip';
import { commonMenuData } from 'src/views/CRUD/data/common';
import { SavedQueryObject } from 'src/views/CRUD/types';
import copyTextToClipboard from 'src/utils/copy';
@@ -180,7 +181,16 @@ function SavedQueryList({
if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) {
subMenuButtons.push({
- name: ,
+ name: (
+
+
+
+ ),
buttonStyle: 'link',
onClick: openSavedQueryImportModal,
'data-test': 'import-button',
@@ -517,7 +527,7 @@ function SavedQueryList({