feat(homepage): conditionally render viewed tab and move examples to chart and dashboard table (#15792)

* test examples

* fix lint

* more lint

* last test

* add suggestions

* fix lint

* fix wrong localstor

* fix tests

* add suggestions

* Update superset-frontend/src/views/CRUD/types.ts

Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>

* Update superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx

Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>

* fix lint

* fix default tab

* fix test

Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>
This commit is contained in:
Phillip Kelley-Dotson 2021-07-22 10:41:49 -07:00 committed by GitHub
parent 5e1c469f42
commit 04c0680f6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 130 additions and 76 deletions

View File

@ -26,6 +26,7 @@ export type FavoriteStatus = {
export enum TableTabTypes {
FAVORITE = 'Favorite',
MINE = 'Mine',
EXAMPLES = 'Examples',
}
export type Filters = {
@ -42,6 +43,7 @@ export interface DashboardTableProps {
mine: Array<Dashboard>;
showThumbnails?: boolean;
featureFlag?: boolean;
examples: Array<Dashboard>;
}
export interface Dashboard {

View File

@ -219,17 +219,7 @@ export default function ActivityTable({
setInLocalStorage(HOMEPAGE_ACTIVITY_FILTER, SetTabType.VIEWED);
},
});
} else {
tabs.unshift({
name: 'Examples',
label: t('Examples'),
onClick: () => {
setActiveChild('Examples');
setInLocalStorage(HOMEPAGE_ACTIVITY_FILTER, SetTabType.EXAMPLE);
},
});
}
const renderActivity = () =>
(activeChild !== 'Edited' ? activityData[activeChild] : editedObjs).map(
(entity: ActivityObject) => {

View File

@ -85,7 +85,7 @@ describe('ChartTable', () => {
}
});
await waitForComponentToPaint(wrapper);
expect(fetchMock.calls(chartsEndpoint)).toHaveLength(3);
expect(fetchMock.calls(chartsEndpoint)).toHaveLength(1);
expect(wrapper.find('ChartCard')).toExist();
});

View File

@ -18,6 +18,7 @@
*/
import React, { useState, useMemo, useEffect } from 'react';
import { t } from '@superset-ui/core';
import { filter } from 'lodash';
import {
useListViewResource,
useChartEditModal,
@ -52,6 +53,7 @@ interface ChartTableProps {
user?: User;
mine: Array<any>;
showThumbnails: boolean;
examples?: Array<object>;
}
function ChartTable({
@ -60,10 +62,17 @@ function ChartTable({
addSuccessToast,
mine,
showThumbnails,
examples,
}: ChartTableProps) {
const history = useHistory();
const filterStore = getFromLocalStorage(HOMEPAGE_CHART_FILTER, null);
const initialFilter = filterStore || TableTabTypes.MINE;
let initialFilter = filterStore || TableTabTypes.EXAMPLES;
if (!examples && filterStore === TableTabTypes.EXAMPLES) {
initialFilter = TableTabTypes.MINE;
}
const filteredExamples = filter(examples, obj => 'viz_type' in obj);
const {
state: { loading, resourceCollection: charts, bulkSelectEnabled },
@ -76,7 +85,7 @@ function ChartTable({
t('chart'),
addDangerToast,
true,
initialFilter === 'Favorite' ? [] : mine,
initialFilter === 'Mine' ? mine : filteredExamples,
[],
false,
);
@ -96,9 +105,13 @@ function ChartTable({
const [chartFilter, setChartFilter] = useState(initialFilter);
const [preparingExport, setPreparingExport] = useState<boolean>(false);
const [loaded, setLoaded] = useState<boolean>(false);
useEffect(() => {
getData(chartFilter);
if (loaded || chartFilter === 'Favorite') {
getData(chartFilter);
}
setLoaded(true);
}, [chartFilter]);
const handleBulkChartExport = (chartsToExport: Chart[]) => {
@ -118,7 +131,7 @@ function ChartTable({
operator: 'rel_o_m',
value: `${user?.userId}`,
});
} else {
} else if (filterName === 'Favorite') {
filters.push({
id: 'id',
operator: 'chart_is_favorite',
@ -128,6 +141,36 @@ function ChartTable({
return filters;
};
const menuTabs = [
{
name: 'Favorite',
label: t('Favorite'),
onClick: () => {
setChartFilter(TableTabTypes.FAVORITE);
setInLocalStorage(HOMEPAGE_CHART_FILTER, TableTabTypes.FAVORITE);
},
},
{
name: 'Mine',
label: t('Mine'),
onClick: () => {
setChartFilter(TableTabTypes.MINE);
setInLocalStorage(HOMEPAGE_CHART_FILTER, TableTabTypes.MINE);
},
},
];
if (examples) {
menuTabs.push({
name: 'Examples',
label: t('Examples'),
onClick: () => {
setChartFilter(TableTabTypes.EXAMPLES);
setInLocalStorage(HOMEPAGE_CHART_FILTER, TableTabTypes.EXAMPLES);
},
});
}
const getData = (filter: string) =>
fetchData({
pageIndex: 0,
@ -156,24 +199,7 @@ function ChartTable({
<SubMenu
activeChild={chartFilter}
// eslint-disable-next-line react/no-children-prop
tabs={[
{
name: 'Favorite',
label: t('Favorite'),
onClick: () => {
setChartFilter('Favorite');
setInLocalStorage(HOMEPAGE_CHART_FILTER, TableTabTypes.FAVORITE);
},
},
{
name: 'Mine',
label: t('Mine'),
onClick: () => {
setChartFilter('Mine');
setInLocalStorage(HOMEPAGE_CHART_FILTER, TableTabTypes.MINE);
},
},
]}
tabs={menuTabs}
buttons={[
{
name: (

View File

@ -72,9 +72,9 @@ describe('DashboardTable', () => {
it('render a submenu with clickable tabs and buttons', async () => {
expect(wrapper.find('SubMenu')).toExist();
expect(wrapper.find('li.no-router')).toHaveLength(2);
expect(wrapper.find('Button')).toHaveLength(4);
expect(wrapper.find('Button')).toHaveLength(6);
act(() => {
const handler = wrapper.find('li.no-router a').at(1).prop('onClick');
const handler = wrapper.find('li.no-router a').at(0).prop('onClick');
if (handler) {
handler({} as any);
}

View File

@ -18,6 +18,7 @@
*/
import React, { useState, useMemo, useEffect } from 'react';
import { SupersetClient, t } from '@superset-ui/core';
import { filter } from 'lodash';
import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks';
import {
Dashboard,
@ -54,10 +55,17 @@ function DashboardTable({
addSuccessToast,
mine,
showThumbnails,
examples,
}: DashboardTableProps) {
const history = useHistory();
const filterStore = getFromLocalStorage(HOMEPAGE_DASHBOARD_FILTER, null);
const defaultFilter = filterStore || TableTabTypes.MINE;
let defaultFilter = filterStore || TableTabTypes.EXAMPLES;
if (!examples && filterStore === TableTabTypes.EXAMPLES) {
defaultFilter = TableTabTypes.MINE;
}
const filteredExamples = filter(examples, obj => !('viz_type' in obj));
const {
state: { loading, resourceCollection: dashboards },
@ -70,7 +78,7 @@ function DashboardTable({
t('dashboard'),
addDangerToast,
true,
defaultFilter === 'Favorite' ? [] : mine,
defaultFilter === 'Mine' ? mine : filteredExamples,
[],
false,
);
@ -84,9 +92,13 @@ function DashboardTable({
const [editModal, setEditModal] = useState<Dashboard>();
const [dashboardFilter, setDashboardFilter] = useState(defaultFilter);
const [preparingExport, setPreparingExport] = useState<boolean>(false);
const [loaded, setLoaded] = useState<boolean>(false);
useEffect(() => {
getData(dashboardFilter);
if (loaded || dashboardFilter === 'Favorite') {
getData(dashboardFilter);
}
setLoaded(true);
}, [dashboardFilter]);
const handleBulkDashboardExport = (dashboardsToExport: Dashboard[]) => {
@ -126,7 +138,7 @@ function DashboardTable({
operator: 'rel_m_m',
value: `${user?.userId}`,
});
} else {
} else if (filterName === 'Favorite') {
filters.push({
id: 'id',
operator: 'dashboard_is_favorite',
@ -136,6 +148,36 @@ function DashboardTable({
return filters;
};
const menuTabs = [
{
name: 'Favorite',
label: t('Favorite'),
onClick: () => {
setDashboardFilter(TableTabTypes.FAVORITE);
setInLocalStorage(HOMEPAGE_DASHBOARD_FILTER, TableTabTypes.FAVORITE);
},
},
{
name: 'Mine',
label: t('Mine'),
onClick: () => {
setDashboardFilter(TableTabTypes.MINE);
setInLocalStorage(HOMEPAGE_DASHBOARD_FILTER, TableTabTypes.MINE);
},
},
];
if (examples) {
menuTabs.push({
name: 'Examples',
label: t('Examples'),
onClick: () => {
setDashboardFilter(TableTabTypes.EXAMPLES);
setInLocalStorage(HOMEPAGE_DASHBOARD_FILTER, TableTabTypes.EXAMPLES);
},
});
}
const getData = (filter: string) =>
fetchData({
pageIndex: 0,
@ -154,27 +196,7 @@ function DashboardTable({
<>
<SubMenu
activeChild={dashboardFilter}
tabs={[
{
name: 'Favorite',
label: t('Favorite'),
onClick: () => {
setDashboardFilter(TableTabTypes.FAVORITE);
setInLocalStorage(
HOMEPAGE_DASHBOARD_FILTER,
TableTabTypes.FAVORITE,
);
},
},
{
name: 'Mine',
label: t('Mine'),
onClick: () => {
setDashboardFilter(TableTabTypes.MINE);
setInLocalStorage(HOMEPAGE_DASHBOARD_FILTER, TableTabTypes.MINE);
},
},
]}
tabs={menuTabs}
buttons={[
{
name: (

View File

@ -132,10 +132,10 @@ describe('Welcome', () => {
const savedQueryCall = fetchMock.calls(/saved_query\/\?q/);
const recentCall = fetchMock.calls(/superset\/recent_activity\/*/);
const dashboardCall = fetchMock.calls(/dashboard\/\?q/);
expect(chartCall).toHaveLength(2);
expect(chartCall).toHaveLength(1);
expect(recentCall).toHaveLength(1);
expect(savedQueryCall).toHaveLength(1);
expect(dashboardCall).toHaveLength(2);
expect(dashboardCall).toHaveLength(1);
});
});

View File

@ -54,6 +54,8 @@ export interface ActivityData {
Examples?: Array<object>;
}
const DEFAULT_TAB_ARR = ['2', '3'];
const WelcomeContainer = styled.div`
background-color: ${({ theme }) => theme.colors.grayscale.light4};
.ant-row.menu {
@ -114,11 +116,9 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
null,
);
const [loadedCount, setLoadedCount] = useState(0);
const [activeState, setActiveState] = useState<Array<string>>([
'1',
'2',
'3',
]);
const [activeState, setActiveState] = useState<Array<string>>(
DEFAULT_TAB_ARR,
);
const userid = user.userId;
const id = userid.toString();
@ -136,14 +136,15 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
if (res.viewed) {
const filtered = reject(res.viewed, ['item_url', null]).map(r => r);
data.Viewed = filtered;
if (!activeTab) {
if (!activeTab && data.Viewed) {
setActiveChild('Viewed');
} else if (!activeTab && !data.Viewed) {
setActiveChild('Created');
} else setActiveChild(activeTab);
} else {
if (!activeTab) setActiveChild('Created');
else setActiveChild(activeTab);
data.Examples = res.examples;
if (activeTab === 'Viewed' || !activeTab) {
setActiveChild('Examples');
} else setActiveChild(activeTab);
}
setActivityData(activityData => ({ ...activityData, ...data }));
})
@ -200,9 +201,14 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
};
useEffect(() => {
if (queryData?.length) {
setActiveState(['1', '2', '3', '4']);
const defaultArr = DEFAULT_TAB_ARR;
if (activityData?.Viewed) {
defaultArr.push('1');
}
if (queryData?.length) {
defaultArr.push('4');
}
setActiveState(defaultArr);
setActivityData(activityData => ({
...activityData,
Created: [
@ -213,6 +219,8 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
}));
}, [chartData, queryData, dashboardData]);
const isRecentActivityLoading =
!activityData?.Examples && !activityData?.Viewed;
return (
<WelcomeContainer>
<WelcomeNav>
@ -243,21 +251,27 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
)}
</Collapse.Panel>
<Collapse.Panel header={t('Dashboards')} key="2">
{!dashboardData ? (
{!dashboardData || isRecentActivityLoading ? (
<Loading position="inline" />
) : (
<DashboardTable
user={user}
mine={dashboardData}
showThumbnails={checked}
examples={activityData?.Examples}
/>
)}
</Collapse.Panel>
<Collapse.Panel header={t('Charts')} key="3">
{!chartData ? (
{!chartData || isRecentActivityLoading ? (
<Loading position="inline" />
) : (
<ChartTable showThumbnails={checked} user={user} mine={chartData} />
<ChartTable
showThumbnails={checked}
user={user}
mine={chartData}
examples={activityData?.Examples}
/>
)}
</Collapse.Panel>
<Collapse.Panel header={t('Saved queries')} key="4">