diff --git a/superset-frontend/src/dashboard/util/findTabIndexByComponentId.test.js b/superset-frontend/src/dashboard/util/findTabIndexByComponentId.test.js index 3a3672c030b82..c41ea486335f6 100644 --- a/superset-frontend/src/dashboard/util/findTabIndexByComponentId.test.js +++ b/superset-frontend/src/dashboard/util/findTabIndexByComponentId.test.js @@ -4,7 +4,7 @@ * 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 + * "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 diff --git a/superset-frontend/src/dashboard/util/updateComponentParentsList.test.js b/superset-frontend/src/dashboard/util/updateComponentParentsList.test.js index 4a788ad35de1f..c5a15d72901b6 100644 --- a/superset-frontend/src/dashboard/util/updateComponentParentsList.test.js +++ b/superset-frontend/src/dashboard/util/updateComponentParentsList.test.js @@ -4,7 +4,7 @@ * 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 + * "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 diff --git a/superset-frontend/src/utils/localStorageHelpers.ts b/superset-frontend/src/utils/localStorageHelpers.ts index b6dad501f5af4..a535a42956558 100644 --- a/superset-frontend/src/utils/localStorageHelpers.ts +++ b/superset-frontend/src/utils/localStorageHelpers.ts @@ -17,7 +17,7 @@ * under the License. */ -import { TableTabTypes } from 'src/views/CRUD/types'; +import { TableTab } from 'src/views/CRUD/types'; import { SetTabType } from 'src/views/CRUD/welcome/ActivityTable'; import { DashboardContextForExplore } from 'src/types/DashboardContextForExplore'; @@ -65,8 +65,8 @@ export type LocalStorageValues = { controls_width: number; datasource_width: number; is_datapanel_open: boolean; - homepage_chart_filter: TableTabTypes; - homepage_dashboard_filter: TableTabTypes; + homepage_chart_filter: TableTab; + homepage_dashboard_filter: TableTab; homepage_collapse_state: string[]; datasetname_set_successful: boolean; homepage_activity_filter: SetTabType | null; diff --git a/superset-frontend/src/utils/urlUtils.test.ts b/superset-frontend/src/utils/urlUtils.test.ts index 5f413ac59034b..19e2a470d1821 100644 --- a/superset-frontend/src/utils/urlUtils.test.ts +++ b/superset-frontend/src/utils/urlUtils.test.ts @@ -4,14 +4,14 @@ * 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 + * "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 + * "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. diff --git a/superset-frontend/src/utils/urlUtils.ts b/superset-frontend/src/utils/urlUtils.ts index 24442a2f485b2..07c8ad550074d 100644 --- a/superset-frontend/src/utils/urlUtils.ts +++ b/superset-frontend/src/utils/urlUtils.ts @@ -4,14 +4,14 @@ * 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 + * "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 + * "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. diff --git a/superset-frontend/src/views/CRUD/types.ts b/superset-frontend/src/views/CRUD/types.ts index 4d32e28b667ec..86784c9704b84 100644 --- a/superset-frontend/src/views/CRUD/types.ts +++ b/superset-frontend/src/views/CRUD/types.ts @@ -24,13 +24,16 @@ export type FavoriteStatus = { [id: number]: boolean; }; -export enum TableTabTypes { - FAVORITE = 'Favorite', - MINE = 'Mine', - OTHER = 'Other', +export enum TableTab { + Favorite = 'Favorite', + Mine = 'Mine', + Other = 'Other', + Viewed = 'Viewed', + Created = 'Created', + Edited = 'Edited', } -export type Filters = { +export type Filter = { col: string; opr: string; value: string | number; @@ -39,12 +42,11 @@ export type Filters = { export interface DashboardTableProps { addDangerToast: (message: string) => void; addSuccessToast: (message: string) => void; - search: string; user?: User; mine: Array; showThumbnails?: boolean; - featureFlag?: boolean; otherTabData: Array; + otherTabFilters: Filter[]; otherTabTitle: string; } diff --git a/superset-frontend/src/views/CRUD/utils.test.tsx b/superset-frontend/src/views/CRUD/utils.test.tsx index e727a0c896bdb..af89c94413e22 100644 --- a/superset-frontend/src/views/CRUD/utils.test.tsx +++ b/superset-frontend/src/views/CRUD/utils.test.tsx @@ -18,12 +18,12 @@ */ import rison from 'rison'; import { - isNeedsPassword, - isAlreadyExists, - getPasswordsNeeded, + checkUploadExtensions, getAlreadyExists, + getPasswordsNeeded, hasTerminalValidation, - checkUploadExtensions, + isAlreadyExists, + isNeedsPassword, } from 'src/views/CRUD/utils'; const terminalErrors = { diff --git a/superset-frontend/src/views/CRUD/utils.tsx b/superset-frontend/src/views/CRUD/utils.tsx index f3e7b999c71f1..ed5549803203c 100644 --- a/superset-frontend/src/views/CRUD/utils.tsx +++ b/superset-frontend/src/views/CRUD/utils.tsx @@ -30,10 +30,12 @@ import Chart from 'src/types/Chart'; import { intersection } from 'lodash'; import rison from 'rison'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; -import { FetchDataConfig } from 'src/components/ListView'; +import { FetchDataConfig, FilterValue } from 'src/components/ListView'; import SupersetText from 'src/utils/textUtils'; import { findPermission } from 'src/utils/findPermission'; -import { Dashboard, Filters } from './types'; +import { Dashboard, Filter, TableTab } from './types'; +import { User } from 'src/types/bootstrapTypes'; +import { WelcomeTable } from './welcome/types'; // Modifies the rison encoding slightly to match the backend's rison encoding/decoding. Applies globally. // Code pulled from rison.js (https://github.com/Nanonid/rison), rison is licensed under the MIT license. @@ -120,7 +122,7 @@ const createFetchResourceMethod = }; export const PAGE_SIZE = 5; -const getParams = (filters?: Array) => { +const getParams = (filters?: Filter[]) => { const params = { order_column: 'changed_on_delta_humanized', order_direction: 'desc', @@ -164,7 +166,7 @@ export const getEditedObjects = (userId: string | number) => { export const getUserOwnedObjects = ( userId: string | number, resource: string, - filters: Array = [ + filters: Filter[] = [ { col: 'owners', opr: 'rel_m_m', @@ -180,7 +182,7 @@ export const getRecentAcitivtyObjs = ( userId: string | number, recent: string, addDangerToast: (arg1: string, arg2: any) => any, - filters: Filters[], + filters: Filter[], ) => SupersetClient.get({ endpoint: recent }).then(recentsRes => { const res: any = {}; @@ -436,3 +438,64 @@ export const uploadUserPerms = ( canUploadData: canUploadCSV || canUploadColumnar || canUploadExcel, }; }; + +export function getFilterValues( + tab: TableTab, + welcomeTable: WelcomeTable, + user?: User, + otherTabFilters?: Filter[], +): FilterValue[] { + if (welcomeTable === WelcomeTable.SavedQueries && tab === TableTab.Mine) { + return [ + { + id: 'created_by', + operator: 'rel_o_m', + value: `${user?.userId}`, + }, + ]; + } + if (welcomeTable === WelcomeTable.SavedQueries) { + return [ + { + id: 'id', + operator: 'saved_query_is_fav', + value: true, + }, + ]; + } + if (tab === TableTab.Created && user) { + return [ + { + id: 'created_by', + operator: 'rel_o_m', + value: `${user.userId}`, + }, + ]; + } + if (tab === TableTab.Mine && user) { + return [ + { + id: 'owners', + operator: 'rel_m_m', + value: `${user.userId}`, + }, + ]; + } + if (tab === TableTab.Favorite) { + return [ + { + id: 'id', + operator: 'dashboard_is_favorite', + value: true, + }, + ]; + } + if (tab === TableTab.Other) { + return (otherTabFilters || []).map(flt => ({ + id: flt.col, + operator: flt.opr, + value: flt.value, + })); + } + return []; +} diff --git a/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx b/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx index d4f4fb4a8be23..753208ec344b7 100644 --- a/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx +++ b/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx @@ -23,6 +23,7 @@ import { setItem, LocalStorageKeys } from 'src/utils/localStorageHelpers'; import { Link } from 'react-router-dom'; import ListViewCard from 'src/components/ListViewCard'; import SubMenu from 'src/views/components/SubMenu'; +import { TableTab } from 'src/views/CRUD/types'; import { ActivityData, LoadingCards } from 'src/views/CRUD/welcome/Welcome'; import { CardContainer, @@ -148,7 +149,7 @@ export default function ActivityTable({ }; useEffect(() => { - if (activeChild === 'Edited') { + if (activeChild === TableTab.Edited) { setLoadingState(true); getEditedCards(); } @@ -214,7 +215,9 @@ export default function ActivityTable({ {activityData[activeChild]?.length > 0 || - (activeChild === 'Edited' && editedObjs && editedObjs.length > 0) ? ( + (activeChild === TableTab.Edited && + editedObjs && + editedObjs.length > 0) ? ( {renderActivity()} diff --git a/superset-frontend/src/views/CRUD/welcome/ChartTable.test.tsx b/superset-frontend/src/views/CRUD/welcome/ChartTable.test.tsx index cfa9230328c08..55b0e309b9366 100644 --- a/superset-frontend/src/views/CRUD/welcome/ChartTable.test.tsx +++ b/superset-frontend/src/views/CRUD/welcome/ChartTable.test.tsx @@ -62,6 +62,11 @@ describe('ChartTable', () => { user: { userId: '2', }, + mine: [], + otherTabData: [], + otherTabFilters: [], + otherTabTitle: 'Other', + showThumbnails: false, }; let wrapper: ReactWrapper; @@ -93,9 +98,12 @@ describe('ChartTable', () => { await act(async () => { wrapper = mount( , ); diff --git a/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx b/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx index b64af060a3b77..b5d016d421400 100644 --- a/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx +++ b/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx @@ -26,15 +26,19 @@ import { } from 'src/views/CRUD/hooks'; import { getItem, - setItem, LocalStorageKeys, + setItem, } from 'src/utils/localStorageHelpers'; import withToasts from 'src/components/MessageToasts/withToasts'; import { useHistory } from 'react-router-dom'; -import { TableTabTypes } from 'src/views/CRUD/types'; +import { Filter, TableTab } from 'src/views/CRUD/types'; import PropertiesModal from 'src/explore/components/PropertiesModal'; import { User } from 'src/types/bootstrapTypes'; -import { CardContainer, PAGE_SIZE } from 'src/views/CRUD/utils'; +import { + CardContainer, + getFilterValues, + PAGE_SIZE, +} from 'src/views/CRUD/utils'; import { LoadingCards } from 'src/views/CRUD/welcome/Welcome'; import ChartCard from 'src/views/CRUD/chart/ChartCard'; import Chart from 'src/types/Chart'; @@ -48,12 +52,11 @@ import { WelcomeTable } from './types'; interface ChartTableProps { addDangerToast: (message: string) => void; addSuccessToast: (message: string) => void; - search: string; - chartFilter?: string; user?: User; mine: Array; showThumbnails: boolean; otherTabData?: Array; + otherTabFilters: Filter[]; otherTabTitle: string; } @@ -64,14 +67,14 @@ function ChartTable({ mine, showThumbnails, otherTabData, + otherTabFilters, otherTabTitle, }: ChartTableProps) { const history = useHistory(); - const filterStore = getItem( + const initialTab = getItem( LocalStorageKeys.homepage_chart_filter, - TableTabTypes.OTHER, + TableTab.Other, ); - const initialFilter = filterStore; const filteredOtherTabData = filter(otherTabData, obj => 'viz_type' in obj); @@ -86,7 +89,7 @@ function ChartTable({ t('chart'), addDangerToast, true, - initialFilter === 'Mine' ? mine : filteredOtherTabData, + initialTab === TableTab.Mine ? mine : filteredOtherTabData, [], false, ); @@ -104,36 +107,11 @@ function ChartTable({ closeChartEditModal, } = useChartEditModal(setCharts, charts); - const [chartFilter, setChartFilter] = useState(initialFilter); + const [activeTab, setActiveTab] = useState(initialTab); const [preparingExport, setPreparingExport] = useState(false); const [loaded, setLoaded] = useState(false); - const getFilters = (filterName: string) => { - const filters = []; - - if (filterName === 'Mine') { - filters.push({ - id: 'owners', - operator: 'rel_m_m', - value: `${user?.userId}`, - }); - } else if (filterName === 'Favorite') { - filters.push({ - id: 'id', - operator: 'chart_is_favorite', - value: true, - }); - } else if (filterName === 'Examples') { - filters.push({ - id: 'created_by', - operator: 'rel_o_m', - value: 0, - }); - } - return filters; - }; - - const getData = (filter: string) => + const getData = (tab: TableTab) => fetchData({ pageIndex: 0, pageSize: PAGE_SIZE, @@ -143,15 +121,15 @@ function ChartTable({ desc: true, }, ], - filters: getFilters(filter), + filters: getFilterValues(tab, WelcomeTable.Charts, user, otherTabFilters), }); useEffect(() => { - if (loaded || chartFilter === 'Favorite') { - getData(chartFilter); + if (loaded || activeTab === TableTab.Favorite) { + getData(activeTab); } setLoaded(true); - }, [chartFilter]); + }, [activeTab]); const handleBulkChartExport = (chartsToExport: Chart[]) => { const ids = chartsToExport.map(({ id }) => id); @@ -163,29 +141,29 @@ function ChartTable({ const menuTabs = [ { - name: 'Favorite', + name: TableTab.Favorite, label: t('Favorite'), onClick: () => { - setChartFilter(TableTabTypes.FAVORITE); - setItem(LocalStorageKeys.homepage_chart_filter, TableTabTypes.FAVORITE); + setActiveTab(TableTab.Favorite); + setItem(LocalStorageKeys.homepage_chart_filter, TableTab.Favorite); }, }, { - name: 'Mine', + name: TableTab.Mine, label: t('Mine'), onClick: () => { - setChartFilter(TableTabTypes.MINE); - setItem(LocalStorageKeys.homepage_chart_filter, TableTabTypes.MINE); + setActiveTab(TableTab.Mine); + setItem(LocalStorageKeys.homepage_chart_filter, TableTab.Mine); }, }, ]; if (otherTabData) { menuTabs.push({ - name: 'Other', + name: TableTab.Other, label: otherTabTitle, onClick: () => { - setChartFilter(TableTabTypes.OTHER); - setItem(LocalStorageKeys.homepage_chart_filter, TableTabTypes.OTHER); + setActiveTab(TableTab.Other); + setItem(LocalStorageKeys.homepage_chart_filter, TableTab.Other); }, }); } @@ -203,7 +181,7 @@ function ChartTable({ )} { const target = - chartFilter === 'Favorite' + activeTab === TableTab.Favorite ? `/chart/list/?filters=(favorite:(label:${t( 'Yes', )},value:!t))` @@ -239,7 +217,7 @@ function ChartTable({ ) : ( - + )} {preparingExport && } diff --git a/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx b/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx index 728fa214ee0f4..0a13dde2cfddc 100644 --- a/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx +++ b/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx @@ -20,22 +20,19 @@ import React, { useEffect, useMemo, useState } from 'react'; import { SupersetClient, t } from '@superset-ui/core'; import { filter } from 'lodash'; import { useFavoriteStatus, useListViewResource } from 'src/views/CRUD/hooks'; -import { - Dashboard, - DashboardTableProps, - TableTabTypes, -} from 'src/views/CRUD/types'; +import { Dashboard, DashboardTableProps, TableTab } from 'src/views/CRUD/types'; import handleResourceExport from 'src/utils/export'; import { useHistory } from 'react-router-dom'; import { getItem, - setItem, LocalStorageKeys, + setItem, } from 'src/utils/localStorageHelpers'; import { LoadingCards } from 'src/views/CRUD/welcome/Welcome'; import { CardContainer, createErrorHandler, + getFilterValues, PAGE_SIZE, } from 'src/views/CRUD/utils'; import withToasts from 'src/components/MessageToasts/withToasts'; @@ -53,14 +50,14 @@ function DashboardTable({ mine, showThumbnails, otherTabData, + otherTabFilters, otherTabTitle, }: DashboardTableProps) { const history = useHistory(); - const filterStore = getItem( + const defaultTab = getItem( LocalStorageKeys.homepage_dashboard_filter, - TableTabTypes.OTHER, + TableTab.Other, ); - const defaultFilter = filterStore; const filteredOtherTabData = filter( otherTabData, @@ -78,7 +75,7 @@ function DashboardTable({ t('dashboard'), addDangerToast, true, - defaultFilter === 'Mine' ? mine : filteredOtherTabData, + defaultTab === TableTab.Mine ? mine : filteredOtherTabData, [], false, ); @@ -90,35 +87,11 @@ function DashboardTable({ ); const [editModal, setEditModal] = useState(); - const [dashboardFilter, setDashboardFilter] = useState(defaultFilter); + const [activeTab, setActiveTab] = useState(defaultTab); const [preparingExport, setPreparingExport] = useState(false); const [loaded, setLoaded] = useState(false); - const getFilters = (filterName: string) => { - const filters = []; - if (filterName === 'Mine') { - filters.push({ - id: 'owners', - operator: 'rel_m_m', - value: `${user?.userId}`, - }); - } else if (filterName === 'Favorite') { - filters.push({ - id: 'id', - operator: 'dashboard_is_favorite', - value: true, - }); - } else if (filterName === 'Examples') { - filters.push({ - id: 'created_by', - operator: 'rel_o_m', - value: 0, - }); - } - return filters; - }; - - const getData = (filter: string) => + const getData = (tab: TableTab) => fetchData({ pageIndex: 0, pageSize: PAGE_SIZE, @@ -128,15 +101,20 @@ function DashboardTable({ desc: true, }, ], - filters: getFilters(filter), + filters: getFilterValues( + tab, + WelcomeTable.Dashboards, + user, + otherTabFilters, + ), }); useEffect(() => { - if (loaded || dashboardFilter === 'Favorite') { - getData(dashboardFilter); + if (loaded || activeTab === TableTab.Favorite) { + getData(activeTab); } setLoaded(true); - }, [dashboardFilter]); + }, [activeTab]); const handleBulkDashboardExport = (dashboardsToExport: Dashboard[]) => { const ids = dashboardsToExport.map(({ id }) => id); @@ -169,36 +147,30 @@ function DashboardTable({ const menuTabs = [ { - name: 'Favorite', + name: TableTab.Favorite, label: t('Favorite'), onClick: () => { - setDashboardFilter(TableTabTypes.FAVORITE); - setItem( - LocalStorageKeys.homepage_dashboard_filter, - TableTabTypes.FAVORITE, - ); + setActiveTab(TableTab.Favorite); + setItem(LocalStorageKeys.homepage_dashboard_filter, TableTab.Favorite); }, }, { - name: 'Mine', + name: TableTab.Mine, label: t('Mine'), onClick: () => { - setDashboardFilter(TableTabTypes.MINE); - setItem(LocalStorageKeys.homepage_dashboard_filter, TableTabTypes.MINE); + setActiveTab(TableTab.Mine); + setItem(LocalStorageKeys.homepage_dashboard_filter, TableTab.Mine); }, }, ]; if (otherTabData) { menuTabs.push({ - name: 'Other', + name: TableTab.Other, label: otherTabTitle, onClick: () => { - setDashboardFilter(TableTabTypes.OTHER); - setItem( - LocalStorageKeys.homepage_dashboard_filter, - TableTabTypes.OTHER, - ); + setActiveTab(TableTab.Other); + setItem(LocalStorageKeys.homepage_dashboard_filter, TableTab.Other); }, }); } @@ -207,7 +179,7 @@ function DashboardTable({ return ( <> { const target = - dashboardFilter === 'Favorite' + activeTab === TableTab.Favorite ? `/dashboard/list/?filters=(favorite:(label:${t( 'Yes', )},value:!t))` @@ -254,7 +226,7 @@ function DashboardTable({ hasPerm={hasPerm} bulkSelectEnabled={false} showThumbnails={showThumbnails} - dashboardFilter={dashboardFilter} + dashboardFilter={activeTab} refreshData={refreshData} addDangerToast={addDangerToast} addSuccessToast={addSuccessToast} @@ -271,7 +243,7 @@ function DashboardTable({ )} {dashboards.length === 0 && ( - + )} {preparingExport && } diff --git a/superset-frontend/src/views/CRUD/welcome/EmptyState.test.tsx b/superset-frontend/src/views/CRUD/welcome/EmptyState.test.tsx index 908ebed6c4f85..fb8ae48ee16b3 100644 --- a/superset-frontend/src/views/CRUD/welcome/EmptyState.test.tsx +++ b/superset-frontend/src/views/CRUD/welcome/EmptyState.test.tsx @@ -18,47 +18,48 @@ */ import React from 'react'; import { styledMount as mount } from 'spec/helpers/theming'; -import EmptyState from 'src/views/CRUD/welcome/EmptyState'; +import { TableTab } from 'src/views/CRUD/types'; +import EmptyState, { EmptyStateProps } from 'src/views/CRUD/welcome/EmptyState'; import { WelcomeTable } from './types'; describe('EmptyState', () => { - const variants = [ + const variants: EmptyStateProps[] = [ { - tab: 'Favorite', + tab: TableTab.Favorite, tableName: WelcomeTable.Dashboards, }, { - tab: 'Mine', + tab: TableTab.Mine, tableName: WelcomeTable.Dashboards, }, { - tab: 'Favorite', + tab: TableTab.Favorite, tableName: WelcomeTable.Charts, }, { - tab: 'Mine', + tab: TableTab.Mine, tableName: WelcomeTable.Charts, }, { - tab: 'Favorite', + tab: TableTab.Favorite, tableName: WelcomeTable.SavedQueries, }, { - tab: 'Mine', + tab: TableTab.Mine, tableName: WelcomeTable.SavedQueries, }, ]; - const recents = [ + const recents: EmptyStateProps[] = [ { - tab: 'Viewed', + tab: TableTab.Viewed, tableName: WelcomeTable.Recents, }, { - tab: 'Edited', + tab: TableTab.Edited, tableName: WelcomeTable.Recents, }, { - tab: 'Created', + tab: TableTab.Created, tableName: WelcomeTable.Recents, }, ]; @@ -68,10 +69,10 @@ describe('EmptyState', () => { expect(wrapper).toExist(); const textContainer = wrapper.find('.ant-empty-description'); expect(textContainer.text()).toEqual( - variant.tab === 'Favorite' + variant.tab === TableTab.Favorite ? "You don't have any favorites yet!" : `No ${ - variant.tableName === 'SAVED_QUERIES' + variant.tableName === WelcomeTable.SavedQueries ? 'saved queries' : variant.tableName.toLowerCase() } yet`, @@ -80,13 +81,13 @@ describe('EmptyState', () => { }); }); recents.forEach(recent => { - it(`it renders an ${recent.tab} ${recent.tableName} empty state`, () => { + it(`it renders a ${recent.tab} ${recent.tableName} empty state`, () => { const wrapper = mount(); expect(wrapper).toExist(); const textContainer = wrapper.find('.ant-empty-description'); expect(wrapper.find('.ant-empty-image').children()).toHaveLength(1); expect(textContainer.text()).toContain( - `Recently ${recent.tab.toLowerCase()} charts, dashboards, and saved queries will appear here`, + `Recently ${recent.tab?.toLowerCase()} charts, dashboards, and saved queries will appear here`, ); }); }); diff --git a/superset-frontend/src/views/CRUD/welcome/EmptyState.tsx b/superset-frontend/src/views/CRUD/welcome/EmptyState.tsx index 525c9ef62e803..856854847de0c 100644 --- a/superset-frontend/src/views/CRUD/welcome/EmptyState.tsx +++ b/superset-frontend/src/views/CRUD/welcome/EmptyState.tsx @@ -17,9 +17,11 @@ * under the License. */ import React from 'react'; +import { capitalize } from 'lodash'; import Button from 'src/components/Button'; import { Empty } from 'src/components'; -import { t, styled } from '@superset-ui/core'; +import { TableTab } from 'src/views/CRUD/types'; +import { styled, t } from '@superset-ui/core'; import { WelcomeTable } from './types'; const welcomeTableLabels: Record = { @@ -29,9 +31,10 @@ const welcomeTableLabels: Record = { [WelcomeTable.SavedQueries]: t('saved queries'), }; -interface EmptyStateProps { +export interface EmptyStateProps { tableName: WelcomeTable; tab?: string; + otherTabTitle?: string; } const EmptyContainer = styled.div` min-height: 200px; @@ -52,7 +55,11 @@ type Redirects = Record< string >; -export default function EmptyState({ tableName, tab }: EmptyStateProps) { +export default function EmptyState({ + tableName, + tab, + otherTabTitle, +}: EmptyStateProps) { const mineRedirects: Redirects = { [WelcomeTable.Charts]: '/chart/add', [WelcomeTable.Dashboards]: '/dashboard/new', @@ -77,22 +84,23 @@ export default function EmptyState({ tableName, tab }: EmptyStateProps) { const recent = ( {(() => { - if (tab === 'Viewed') { + if (tab === TableTab.Viewed) { return t( `Recently viewed charts, dashboards, and saved queries will appear here`, ); } - if (tab === 'Created') { + if (tab === TableTab.Created) { return t( 'Recently created charts, dashboards, and saved queries will appear here', ); } - if (tab === 'Examples') { - return t('Example %(tableName)s will appear here', { + if (tab === TableTab.Other) { + return t('%(other)s %(tableName)s will appear here', { + other: otherTabTitle ? capitalize(otherTabTitle) : t('Other'), tableName: tableName.toLowerCase(), }); } - if (tab === 'Edited') { + if (tab === TableTab.Edited) { return t( `Recently edited charts, dashboards, and saved queries will appear here`, ); @@ -101,17 +109,24 @@ export default function EmptyState({ tableName, tab }: EmptyStateProps) { })()} ); + // Mine and Recent Activity(all tabs) tab empty state - if (tab === 'Mine' || tableName === 'RECENTS' || tab === 'Examples') { + if ( + tab === TableTab.Mine || + tableName === WelcomeTable.Recents || + tab === TableTab.Other + ) { return ( - {tableName !== 'RECENTS' && ( + {tableName !== WelcomeTable.Recents && (