From 5640c7430a5d7c47b93e4feb72369a8f2c65da40 Mon Sep 17 00:00:00 2001
From: Maxime Beauchemin
Date: Wed, 15 Jan 2025 00:08:37 -0800
Subject: [PATCH 1/3] chore: Empty state refactor
- making `size` a prop instead of one-component-per-size
- fixing up the svg so its themable using `currentColor`
- centralizing/fixing up references
---
.../SqlLab/components/QueryHistory/index.tsx | 5 +-
.../SqlLab/components/SouthPane/Results.tsx | 4 +-
.../src/SqlLab/components/SqlEditor/index.tsx | 5 +-
.../components/SqlEditorLeftBar/index.tsx | 6 +-
.../components/TabbedSqlEditors/index.tsx | 5 +-
superset-frontend/src/assets/images/chart.svg | 6 +-
.../src/assets/images/document.svg | 4 +-
.../src/assets/images/empty-charts.svg | 22 +-
.../src/assets/images/empty-dashboard.svg | 14 +-
.../src/assets/images/empty-dataset.svg | 39 +--
.../src/assets/images/empty-queries.svg | 16 +-
.../src/assets/images/empty-query.svg | 12 +-
.../src/assets/images/empty-table.svg | 6 +-
superset-frontend/src/assets/images/empty.svg | 6 +-
.../src/assets/images/empty_sql_chart.svg | 6 +-
.../src/assets/images/filter-results.svg | 67 +++--
.../src/assets/images/filter.svg | 52 +++-
.../src/assets/images/star-circle.svg | 6 +-
superset-frontend/src/assets/images/union.svg | 6 +-
.../src/assets/images/vector.svg | 4 +-
.../src/components/Chart/Chart.tsx | 8 +-
.../src/components/Chart/ChartRenderer.jsx | 7 +-
.../Chart/DrillDetail/DrillDetailPane.tsx | 4 +-
.../DatabaseSelector.test.tsx | 4 +-
.../EmptyState/EmptyState.stories.tsx | 99 ++++---
.../src/components/EmptyState/index.tsx | 251 +++++++-----------
.../src/components/ListView/ListView.tsx | 8 +-
.../src/components/Table/index.tsx | 59 ++--
.../DashboardBuilder/DashboardBuilder.tsx | 5 +-
.../dashboard/components/DashboardGrid.jsx | 11 +-
.../gridComponents/ChartHolder.test.tsx | 2 +-
.../components/gridComponents/Tab.jsx | 4 +-
.../components/gridComponents/Tab.test.tsx | 4 +-
.../nativeFilters/FilterBar/Vertical.tsx | 5 +-
.../DataTablesPane/components/SamplesPane.tsx | 4 +-
.../components/useResultsPane.tsx | 6 +-
.../AnnotationLayer.jsx | 5 +-
.../ColumnSelectPopover.tsx | 11 +-
.../AdhocMetricEditPopover/index.jsx | 8 +-
.../features/allEntities/AllEntitiesTable.tsx | 5 +-
.../DatasetPanel/MessageContent.tsx | 7 +-
.../AddDataset/EditDataset/UsageTab/index.tsx | 7 +-
.../datasets/AddDataset/LeftPanel/index.tsx | 21 +-
.../src/features/home/EmptyState.tsx | 206 +++++---------
44 files changed, 500 insertions(+), 542 deletions(-)
diff --git a/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx b/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx
index 30103dafa566c..6916e1e19b1a5 100644
--- a/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx
+++ b/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx
@@ -20,7 +20,7 @@ import { useEffect, useMemo, useState } from 'react';
import { shallowEqual, useSelector } from 'react-redux';
import { useInView } from 'react-intersection-observer';
import { omit } from 'lodash';
-import { EmptyStateMedium } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import {
t,
styled,
@@ -143,8 +143,9 @@ const QueryHistory = ({
>
) : (
-
diff --git a/superset-frontend/src/SqlLab/components/SouthPane/Results.tsx b/superset-frontend/src/SqlLab/components/SouthPane/Results.tsx
index 3dfec40bdc037..6a2a60831bf74 100644
--- a/superset-frontend/src/SqlLab/components/SouthPane/Results.tsx
+++ b/superset-frontend/src/SqlLab/components/SouthPane/Results.tsx
@@ -19,7 +19,7 @@
import { FC } from 'react';
import { shallowEqual, useSelector } from 'react-redux';
import Alert from 'src/components/Alert';
-import { EmptyStateMedium } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import { FeatureFlag, styled, t, isFeatureEnabled } from '@superset-ui/core';
import { SqlLabRootState } from 'src/SqlLab/types';
@@ -67,7 +67,7 @@ const Results: FC = ({
) {
return (
-
diff --git a/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx b/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx
index cab82cd02f5c2..b3d176d90e1dc 100644
--- a/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx
+++ b/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx
@@ -100,7 +100,7 @@ import {
LocalStorageKeys,
setItem,
} from 'src/utils/localStorageHelpers';
-import { EmptyStateBig } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import Alert from 'src/components/Alert';
import getBootstrapData from 'src/utils/getBootstrapData';
import useLogAction from 'src/logger/useLogAction';
@@ -967,8 +967,9 @@ const SqlEditor: FC = ({
) : showEmptyState && !hasSqlStatement ? (
- (
null,
);
@@ -249,7 +249,7 @@ const SqlEditorLeftBar = ({
}
database={userSelectedDb}
getDbList={handleDbList}
handleError={handleError}
diff --git a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx
index df3099994ec31..7f43e8adb7bb1 100644
--- a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx
+++ b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx
@@ -27,7 +27,7 @@ import { Logger } from 'src/logger/LogUtils';
import { Tooltip } from 'src/components/Tooltip';
import { detectOS } from 'src/utils/common';
import * as Actions from 'src/SqlLab/actions/sqlLab';
-import { EmptyStateBig } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import getBootstrapData from 'src/utils/getBootstrapData';
import { locationContext } from 'src/pages/SqlLab/LocationContext';
import SqlEditor from '../SqlEditor';
@@ -255,8 +255,9 @@ class TabbedSqlEditors extends PureComponent {
tab={emptyTab}
closable={false}
>
-
diff --git a/superset-frontend/src/assets/images/chart.svg b/superset-frontend/src/assets/images/chart.svg
index 2267342bccd1f..34e45631e08d8 100644
--- a/superset-frontend/src/assets/images/chart.svg
+++ b/superset-frontend/src/assets/images/chart.svg
@@ -16,7 +16,7 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
-
- }
- />
-);
diff --git a/superset-frontend/src/components/ListView/ListView.tsx b/superset-frontend/src/components/ListView/ListView.tsx
index 30bcb99aa3b98..cfa060f11da63 100644
--- a/superset-frontend/src/components/ListView/ListView.tsx
+++ b/superset-frontend/src/components/ListView/ListView.tsx
@@ -37,7 +37,7 @@ import {
ViewModeType,
} from './types';
import { ListViewError, useListViewState } from './utils';
-import { EmptyStateBig, EmptyStateProps } from '../EmptyState';
+import { EmptyState, EmptyStateProps } from '../EmptyState';
const ListViewStyles = styled.div`
text-align: center;
@@ -447,17 +447,19 @@ function ListView({
{!loading && rows.length === 0 && (
{query.filters ? (
- handleClearFilterControls()}
buttonText={t('clear all filters')}
/>
) : (
-
)}
diff --git a/superset-frontend/src/components/Table/index.tsx b/superset-frontend/src/components/Table/index.tsx
index 1495befa5acc9..11a803893b92c 100644
--- a/superset-frontend/src/components/Table/index.tsx
+++ b/superset-frontend/src/components/Table/index.tsx
@@ -16,13 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { useState, useEffect, useRef, ReactElement, Key } from 'react';
+import { useState, useEffect, useRef, Key } from 'react';
import AntTable, {
ColumnsType,
TableProps as AntTableProps,
} from 'antd/lib/table';
-import ConfigProvider from 'antd/lib/config-provider';
import { PaginationProps } from 'antd/lib/pagination';
import { t, useTheme, logging, styled } from '@superset-ui/core';
import Loading from 'src/components/Loading';
@@ -116,10 +115,6 @@ export interface TableProps {
* Set table to display no data even if data has been provided
*/
hideData?: boolean;
- /**
- * emptyComponent
- */
- emptyComponent?: ReactElement;
/**
* Enables setting the text displayed in various components and tooltips within the Table UI.
*/
@@ -256,7 +251,6 @@ export function Table(
defaultPageSize = 15,
pageSizeOptions = ['5', '15', '25', '50', '100'],
hideData = false,
- emptyComponent,
locale,
height,
virtualize = false,
@@ -288,9 +282,6 @@ export function Table(
onChange: onSelectChange,
};
- const renderEmpty = () =>
- emptyComponent ?? {mergedLocale.emptyText}
;
-
// Log use of experimental features
useEffect(() => {
if (reorderable === true) {
@@ -403,31 +394,29 @@ export function Table(
};
return (
-
-
- {!virtualize && (
-
- )}
- {virtualize && (
-
- )}
-
-
+
+ {!virtualize && (
+
+ )}
+ {virtualize && (
+
+ )}
+
);
}
diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
index e5caed6968642..cdddff00b0e8e 100644
--- a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
+++ b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
@@ -64,7 +64,7 @@ import {
} from 'src/dashboard/util/constants';
import FilterBar from 'src/dashboard/components/nativeFilters/FilterBar';
import Loading from 'src/components/Loading';
-import { EmptyStateBig } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import { useUiConfig } from 'src/components/UiConfigContext';
import ResizableSidebar from 'src/components/ResizableSidebar';
import {
@@ -666,8 +666,9 @@ const DashboardBuilder = () => {
{!editMode &&
!topLevelTabs &&
dashboardLayout[DASHBOARD_GRID_ID]?.children?.length === 0 && (
-
@@ -228,8 +229,9 @@ class DashboardGrid extends PureComponent {
);
const topLevelTabEmptyState = editMode ? (
-
) : (
- {
'Make sure that the controls are configured properly and the datasource contains data for the selected time range',
),
).not.toBeInTheDocument(); // description should display only in Explore view
- expect(screen.getByAltText('empty')).toBeVisible();
+ expect(screen.getByRole('img', { name: 'empty' })).toBeVisible();
});
it('should render anchor link when not editing', async () => {
diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx b/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx
index 2c4695f8c7285..36a77316413be 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx
@@ -22,7 +22,7 @@ import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { styled, t } from '@superset-ui/core';
-import { EmptyStateMedium } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import EditableTitle from 'src/components/EditableTitle';
import { setEditMode } from 'src/dashboard/actions/dashboardState';
import DashboardComponent from 'src/dashboard/containers/DashboardComponent';
@@ -197,7 +197,7 @@ const Tab = props => {
)}
{shouldDisplayEmptyState && (
- {
expect(
screen.getByText('There are no components added to this tab'),
).toBeVisible();
- expect(screen.getByAltText('empty')).toBeVisible();
+ expect(screen.getByRole('img', { name: 'empty' })).toBeVisible();
expect(screen.queryByText('edit mode')).not.toBeInTheDocument();
});
@@ -397,7 +397,7 @@ test('Render tab content with no children, editMode: true, canEdit: true', () =>
expect(
screen.getByText('Drag and drop components to this tab'),
).toBeVisible();
- expect(screen.getByAltText('empty')).toBeVisible();
+ expect(screen.getByRole('img', { name: 'empty' })).toBeVisible();
expect(
screen.getByRole('link', { name: 'create a new chart' }),
).toBeVisible();
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx
index b76b65c13395c..d6960ad37027f 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx
@@ -33,7 +33,7 @@ import cx from 'classnames';
import { FeatureFlag, isFeatureEnabled, styled, t } from '@superset-ui/core';
import Icons from 'src/components/Icons';
import Loading from 'src/components/Loading';
-import { EmptyStateSmall } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import { getFilterBarTestId } from './utils';
import { VerticalBarProps } from './types';
import Header from './Header';
@@ -168,7 +168,8 @@ const VerticalFilterBar: FC = ({
() =>
filterValues.length === 0 ? (
- ;
+ return ;
}
return (
diff --git a/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx b/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
index fe262fe72078d..e96963d10854d 100644
--- a/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
+++ b/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
@@ -26,7 +26,7 @@ import {
getClientErrorObject,
} from '@superset-ui/core';
import Loading from 'src/components/Loading';
-import { EmptyStateMedium } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import { getChartDataRequest } from 'src/components/Chart/chartAction';
import { ResultsPaneProps, QueryResultInterface } from '../types';
import { SingleQueryResultPane } from './SingleQueryResultPane';
@@ -110,7 +110,7 @@ export const useResultsPane = ({
if (errorMessage) {
const title = t('Run a query to display results');
return Array(queryCount).fill(
- ,
+ ,
);
}
@@ -136,7 +136,7 @@ export const useResultsPane = ({
if (resultResp.length === 0) {
const title = t('No results were returned for this query');
return Array(queryCount).fill(
- ,
+ ,
);
}
return resultResp
diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx
index 304ec3409d342..905fd04f9ceb5 100644
--- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx
+++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx
@@ -38,7 +38,7 @@ import TextControl from 'src/explore/components/controls/TextControl';
import CheckboxControl from 'src/explore/components/controls/CheckboxControl';
import PopoverSection from 'src/components/PopoverSection';
import ControlHeader from 'src/explore/components/ControlHeader';
-import { EmptyStateSmall } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import {
ANNOTATION_SOURCE_TYPES,
ANNOTATION_TYPES,
@@ -111,8 +111,9 @@ const NotFoundContentWrapper = styled.div`
const NotFoundContent = () => (
-
{t('Add an annotation layer')}{' '}
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
index 711cad392de2f..6e0a256965bba 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
@@ -43,7 +43,7 @@ import { Select } from 'src/components';
import { Form, FormItem } from 'src/components/Form';
import sqlKeywords from 'src/SqlLab/utils/sqlKeywords';
import { SQLEditor } from 'src/components/AsyncAceEditor';
-import { EmptyStateSmall } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import { getColumnKeywords } from 'src/explore/controlUtils/getColumnKeywords';
import { StyledColumnOption } from 'src/explore/components/optionRenderers';
import {
@@ -334,8 +334,9 @@ const ColumnSelectPopover = ({
/>
) : datasourceType === DatasourceType.Table ? (
-
) : (
-
{isTemporal && simpleColumns.length === 0 ? (
-
) : datasource.type === DatasourceType.Table ? (
-
) : (
-
diff --git a/superset-frontend/src/features/allEntities/AllEntitiesTable.tsx b/superset-frontend/src/features/allEntities/AllEntitiesTable.tsx
index 8ecbf33872185..ae51762d788ae 100644
--- a/superset-frontend/src/features/allEntities/AllEntitiesTable.tsx
+++ b/superset-frontend/src/features/allEntities/AllEntitiesTable.tsx
@@ -23,7 +23,7 @@ import { TagsList } from 'src/components/Tags';
import FacePile from 'src/components/FacePile';
import Tag from 'src/types/TagType';
import Owner from 'src/types/Owner';
-import { EmptyStateBig } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import { NumberParam, useQueryParam } from 'use-query-params';
const MAX_TAGS_TO_SHOW = 3;
@@ -160,8 +160,9 @@ export default function AllEntitiesTable({
{renderTable('query')}
>
) : (
- setShowTagModal(true)}
buttonText={t('Add tag to entities')}
diff --git a/superset-frontend/src/features/datasets/AddDataset/DatasetPanel/MessageContent.tsx b/superset-frontend/src/features/datasets/AddDataset/DatasetPanel/MessageContent.tsx
index 9f57935947897..5aab72027222a 100644
--- a/superset-frontend/src/features/datasets/AddDataset/DatasetPanel/MessageContent.tsx
+++ b/superset-frontend/src/features/datasets/AddDataset/DatasetPanel/MessageContent.tsx
@@ -18,7 +18,7 @@
*/
import { t, styled } from '@superset-ui/core';
-import { EmptyStateBig } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import { Link } from 'react-router-dom';
const StyledContainer = styled.div`
@@ -31,7 +31,7 @@ const StyledContainer = styled.div`
height: 100%;
`;
-const StyledEmptyStateBig = styled(EmptyStateBig)`
+const StyledEmptyState = styled(EmptyState)`
max-width: 50%;
p {
@@ -91,8 +91,9 @@ export const MessageContent = (props: MessageContentProps) => {
}
return (
-
diff --git a/superset-frontend/src/features/datasets/AddDataset/EditDataset/UsageTab/index.tsx b/superset-frontend/src/features/datasets/AddDataset/EditDataset/UsageTab/index.tsx
index 0e41182096130..289a67f5aa98f 100644
--- a/superset-frontend/src/features/datasets/AddDataset/EditDataset/UsageTab/index.tsx
+++ b/superset-frontend/src/features/datasets/AddDataset/EditDataset/UsageTab/index.tsx
@@ -32,7 +32,7 @@ import Table, {
TableSize,
OnChangeFunction,
} from 'src/components/Table';
-import { EmptyStateBig } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import ChartImage from 'src/assets/images/chart.svg';
import Icons from 'src/components/Icons';
import { useToasts } from 'src/components/MessageToasts/withToasts';
@@ -147,7 +147,7 @@ const emptyStateButtonText = (
>
);
-const StyledEmptyStateBig = styled(EmptyStateBig)`
+const StyledEmptyState = styled(EmptyState)`
margin: ${({ theme }) => 13 * theme.gridUnit}px 0;
`;
@@ -250,8 +250,9 @@ const DatasetUsage = ({ datasetId }: DatasetUsageProps) => {
onChange={onChange}
/>
{!data.length && !loading ? (
- }
+ size="large"
title={t('No charts')}
description={t('This dataset is not used to power any charts.')}
buttonText={emptyStateButtonText}
diff --git a/superset-frontend/src/features/datasets/AddDataset/LeftPanel/index.tsx b/superset-frontend/src/features/datasets/AddDataset/LeftPanel/index.tsx
index c14109aede56f..adb52234224b9 100644
--- a/superset-frontend/src/features/datasets/AddDataset/LeftPanel/index.tsx
+++ b/superset-frontend/src/features/datasets/AddDataset/LeftPanel/index.tsx
@@ -20,7 +20,7 @@ import { useEffect, SetStateAction, Dispatch, useCallback } from 'react';
import { styled, t } from '@superset-ui/core';
import TableSelector, { TableOption } from 'src/components/TableSelector';
import { DatabaseObject } from 'src/components/DatabaseSelector';
-import { emptyStateComponent } from 'src/components/EmptyState';
+import { EmptyState } from 'src/components/EmptyState';
import { useToasts } from 'src/components/MessageToasts/withToasts';
import { LocalStorageKeys, getItem } from 'src/utils/localStorageHelpers';
import {
@@ -178,13 +178,30 @@ export default function LeftPanel({
),
[datasetNames],
);
+ const getDatabaseEmptyState = (emptyResultsWithSearch: boolean) => (
+
+ {t('Manage your databases')}{' '}
+ {t('here')}
+
+ }
+ size="small"
+ />
+ );
return (
= {
- [WelcomeTable.Charts]: t('charts'),
- [WelcomeTable.Dashboards]: t('dashboards'),
- [WelcomeTable.Recents]: t('recents'),
- [WelcomeTable.SavedQueries]: t('saved queries'),
-};
-
-const welcomeTableEmpty: Record = {
- [WelcomeTable.Charts]: t('No charts yet'),
- [WelcomeTable.Dashboards]: t('No dashboards yet'),
- [WelcomeTable.Recents]: t('No recents yet'),
- [WelcomeTable.SavedQueries]: t('No saved queries yet'),
-};
-
-const welcomeTableWillAppear: Record string> =
- {
- [WelcomeTable.Charts]: (other: string) =>
- t('%(other)s charts will appear here', { other }),
- [WelcomeTable.Dashboards]: (other: string) =>
- t('%(other)s dashboards will appear here', { other }),
- [WelcomeTable.Recents]: (other: string) =>
- t('%(other)s recents will appear here', { other }),
- [WelcomeTable.SavedQueries]: (other: string) =>
- t('%(other)s saved queries will appear here', { other }),
- };
-
-export interface EmptyStateProps {
- tableName: WelcomeTable;
- tab?: string;
- otherTabTitle?: string;
-}
const EmptyContainer = styled.div`
min-height: 200px;
display: flex;
+ color: ${({ theme }) => theme.colors.grayscale.light2};
flex-direction: column;
justify-content: space-around;
`;
-const ButtonContainer = styled.div`
- Button {
- svg {
- color: ${({ theme }) => theme.colors.grayscale.light5};
- }
- }
-`;
-type Redirects = Record<
- WelcomeTable.Charts | WelcomeTable.Dashboards | WelcomeTable.SavedQueries,
- string
->;
+const ICONS = {
+ [WelcomeTable.Charts]: 'empty-charts.svg',
+ [WelcomeTable.Dashboards]: 'empty-dashboard.svg',
+ [WelcomeTable.Recents]: 'union.svg',
+ [WelcomeTable.SavedQueries]: 'empty-queries.svg',
+} as const;
-export default function EmptyState({
- tableName,
- tab,
- otherTabTitle,
-}: EmptyStateProps) {
- const mineRedirects: Redirects = {
+const REDIRECTS = {
+ create: {
[WelcomeTable.Charts]: '/chart/add',
[WelcomeTable.Dashboards]: '/dashboard/new',
[WelcomeTable.SavedQueries]: '/sqllab?new=true',
- };
- const favRedirects: Redirects = {
+ },
+ viewAll: {
[WelcomeTable.Charts]: '/chart/list',
[WelcomeTable.Dashboards]: '/dashboard/list/',
[WelcomeTable.SavedQueries]: '/savedqueryview/list/',
- };
- const tableIcon: Record = {
- [WelcomeTable.Charts]: 'empty-charts.svg',
- [WelcomeTable.Dashboards]: 'empty-dashboard.svg',
- [WelcomeTable.Recents]: 'union.svg',
- [WelcomeTable.SavedQueries]: 'empty-queries.svg',
- };
- const mine = {welcomeTableEmpty[tableName]};
- const recent = (
-
- {(() => {
- if (tab === TableTab.Viewed) {
- return t(
- `Recently viewed charts, dashboards, and saved queries will appear here`,
- );
- }
- if (tab === TableTab.Created) {
- return t(
- 'Recently created charts, dashboards, and saved queries will appear here',
- );
- }
- if (tab === TableTab.Other) {
- const other = otherTabTitle || t('Other');
- return welcomeTableWillAppear[tableName](other);
- }
- if (tab === TableTab.Edited) {
- return t(
- `Recently edited charts, dashboards, and saved queries will appear here`,
- );
- }
- return null;
- })()}
-
- );
+ },
+} as const;
+
+export interface EmptyStateProps {
+ tableName: WelcomeTable;
+ tab?: string;
+ otherTabTitle?: string;
+}
+
+export default function EmptyState({
+ tableName,
+ tab,
+ otherTabTitle,
+}: EmptyStateProps) {
+ const getActionButton = () => {
+ if (tableName === WelcomeTable.Recents) {
+ return null;
+ }
+
+ const isFavorite = tab === TableTab.Favorite;
+ const buttonText =
+ tableName === WelcomeTable.SavedQueries
+ ? isFavorite
+ ? t('SQL Lab queries')
+ : t('SQL query')
+ : isFavorite
+ ? t(tableName.toLowerCase())
+ : tableName.slice(0, -1);
+
+ const url = isFavorite
+ ? REDIRECTS.viewAll[tableName]
+ : REDIRECTS.create[tableName];
- // Mine and Recent Activity(all tabs) tab empty state
- if (
- tab === TableTab.Mine ||
- tableName === WelcomeTable.Recents ||
- tab === TableTab.Other
- ) {
return (
-
-
- {tableName !== WelcomeTable.Recents && (
-
-
-
-
-
- )}
-
-
+
);
- }
- // Favorite tab empty state
+ };
+
+ const image =
+ tab === TableTab.Favorite ? 'star-circle.svg' : ICONS[tableName];
+
return (
-
- {t("You don't have any favorites yet!")}
-
- }
+
-
-
+ {getActionButton()}
+
);
}
From 3f82485053f32c048e303bc46f2d0f023139f97d Mon Sep 17 00:00:00 2001
From: Maxime Beauchemin
Date: Wed, 15 Jan 2025 22:58:21 -0800
Subject: [PATCH 2/3] fixed two tets
---
superset-frontend/src/features/home/ChartTable.test.tsx | 4 +---
superset-frontend/src/features/home/EmptyState.test.tsx | 4 +---
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/superset-frontend/src/features/home/ChartTable.test.tsx b/superset-frontend/src/features/home/ChartTable.test.tsx
index f03a705245e81..0e19f8c059ad4 100644
--- a/superset-frontend/src/features/home/ChartTable.test.tsx
+++ b/superset-frontend/src/features/home/ChartTable.test.tsx
@@ -87,9 +87,7 @@ const renderChartTable = (props: any) =>
test('renders with EmptyState if no data present', async () => {
await renderChartTable(mockedProps);
expect(screen.getAllByRole('tab')).toHaveLength(3);
- expect(
- screen.getByText(/other charts will appear here/i),
- ).toBeInTheDocument();
+ expect(screen.getByText(/nothing here yet/i)).toBeInTheDocument();
});
test('fetches chart favorites and renders chart cards', async () => {
diff --git a/superset-frontend/src/features/home/EmptyState.test.tsx b/superset-frontend/src/features/home/EmptyState.test.tsx
index fe633bc788632..3753b70deedff 100644
--- a/superset-frontend/src/features/home/EmptyState.test.tsx
+++ b/superset-frontend/src/features/home/EmptyState.test.tsx
@@ -95,9 +95,7 @@ describe('EmptyState', () => {
expect(wrapper.find('.ant-empty-image').children()).toHaveLength(1);
// Check the correct text is displayed
- expect(textContainer.text()).toContain(
- `Recently ${recent.tab?.toLowerCase()} charts, dashboards, and saved queries will appear here`,
- );
+ expect(textContainer.text()).toContain(`Nothing here yet`);
});
});
});
From a6746a640dfb4f488cd1bab147ebbeaf26057793 Mon Sep 17 00:00:00 2001
From: Maxime Beauchemin
Date: Thu, 16 Jan 2025 00:29:25 -0800
Subject: [PATCH 3/3] nothing here yet
---
superset-frontend/package-lock.json | 118 ++++--------------
.../src/features/home/ActivityTable.test.tsx | 6 +-
.../src/features/home/EmptyState.test.tsx | 10 +-
3 files changed, 26 insertions(+), 108 deletions(-)
diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json
index 337ee7a84294a..57230094854bc 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -1702,15 +1702,18 @@
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.24.8",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
- "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
+ "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
+ "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.24.7",
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+ "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -3481,13 +3484,13 @@
"license": "MIT"
},
"node_modules/@babel/types": {
- "version": "7.25.2",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz",
- "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==",
+ "version": "7.26.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.5.tgz",
+ "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==",
+ "license": "MIT",
"dependencies": {
- "@babel/helper-string-parser": "^7.24.8",
- "@babel/helper-validator-identifier": "^7.24.7",
- "to-fast-properties": "^2.0.0"
+ "@babel/helper-string-parser": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.25.9"
},
"engines": {
"node": ">=6.9.0"
@@ -51614,13 +51617,6 @@
"dev": true,
"license": "BSD-3-Clause"
},
- "node_modules/to-fast-properties": {
- "version": "2.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/to-object-path": {
"version": "0.3.0",
"dev": true,
@@ -57074,26 +57070,6 @@
"node": ">=6.9.0"
}
},
- "packages/superset-ui-demo/node_modules/@babel/helper-string-parser": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
- "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "packages/superset-ui-demo/node_modules/@babel/helper-validator-identifier": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
- "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
"packages/superset-ui-demo/node_modules/@babel/helper-validator-option": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz",
@@ -59086,26 +59062,6 @@
"react-dom": "^16.13.1"
}
},
- "plugins/plugin-chart-pivot-table/node_modules/@babel/helper-string-parser": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
- "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "plugins/plugin-chart-pivot-table/node_modules/@babel/helper-validator-identifier": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
- "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
"plugins/plugin-chart-pivot-table/node_modules/@babel/types": {
"version": "7.26.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz",
@@ -60212,12 +60168,14 @@
}
},
"@babel/helper-string-parser": {
- "version": "7.24.8",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
- "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ=="
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
+ "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="
},
"@babel/helper-validator-identifier": {
- "version": "7.24.7"
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+ "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="
},
"@babel/helper-validator-option": {
"version": "7.24.7"
@@ -61267,13 +61225,12 @@
}
},
"@babel/types": {
- "version": "7.25.2",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz",
- "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==",
+ "version": "7.26.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.5.tgz",
+ "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==",
"requires": {
- "@babel/helper-string-parser": "^7.24.8",
- "@babel/helper-validator-identifier": "^7.24.7",
- "to-fast-properties": "^2.0.0"
+ "@babel/helper-string-parser": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.25.9"
}
},
"@base2/pretty-print-object": {
@@ -67537,18 +67494,6 @@
"integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==",
"dev": true
},
- "@babel/helper-string-parser": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
- "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
- "dev": true
- },
- "@babel/helper-validator-identifier": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
- "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
- "dev": true
- },
"@babel/helper-validator-option": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz",
@@ -69677,18 +69622,6 @@
"jest": "^29.7.0"
},
"dependencies": {
- "@babel/helper-string-parser": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
- "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
- "dev": true
- },
- "@babel/helper-validator-identifier": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
- "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
- "dev": true
- },
"@babel/types": {
"version": "7.26.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz",
@@ -95191,9 +95124,6 @@
"version": "1.0.5",
"dev": true
},
- "to-fast-properties": {
- "version": "2.0.0"
- },
"to-object-path": {
"version": "0.3.0",
"dev": true,
diff --git a/superset-frontend/src/features/home/ActivityTable.test.tsx b/superset-frontend/src/features/home/ActivityTable.test.tsx
index 54fe3c7542ee0..9b5ee127b7f4e 100644
--- a/superset-frontend/src/features/home/ActivityTable.test.tsx
+++ b/superset-frontend/src/features/home/ActivityTable.test.tsx
@@ -137,9 +137,5 @@ test('calls the getEdited batch call when edited tab is clicked', async () => {
});
test('show empty state if there is no data', () => {
renderActivityTable(emptyActivityProps);
- expect(
- screen.getByText(
- /recently created charts, dashboards, and saved queries will appear here/i,
- ),
- ).toBeInTheDocument();
+ expect(screen.getByText(/nothing here yet/i)).toBeInTheDocument();
});
diff --git a/superset-frontend/src/features/home/EmptyState.test.tsx b/superset-frontend/src/features/home/EmptyState.test.tsx
index 3753b70deedff..0be86559dcf63 100644
--- a/superset-frontend/src/features/home/EmptyState.test.tsx
+++ b/superset-frontend/src/features/home/EmptyState.test.tsx
@@ -70,15 +70,7 @@ describe('EmptyState', () => {
// Select the first description node
const textContainer = wrapper.find('.ant-empty-description').at(0);
- expect(textContainer.text()).toEqual(
- variant.tab === TableTab.Favorite
- ? "You don't have any favorites yet!"
- : `No ${
- variant.tableName === WelcomeTable.SavedQueries
- ? 'saved queries'
- : variant.tableName.toLowerCase()
- } yet`,
- );
+ expect(textContainer.text()).toEqual('Nothing here yet');
expect(wrapper.find('button')).toHaveLength(1);
});
});