mirror of
https://github.com/apache/superset.git
synced 2024-09-18 19:49:37 -04:00
chore: Homepage cleanup (#14823)
* initial commit * update welcome * fix lint * add enum * more choring * fix lint * redo logic for api stick api calls * fix test * fix chart test * lint fix and remove unused code * fix flicker and add suggestions * lint * fix test * add suggestions * add suggestions and fix test * revert packagelock * fix space
This commit is contained in:
parent
53df152362
commit
8e6a5a6f52
23
superset-frontend/src/views/CRUD/storageKeys.ts
Normal file
23
superset-frontend/src/views/CRUD/storageKeys.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* 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
|
||||||
|
* 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
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// storage keys for welcome page sticky tabs..
|
||||||
|
export const HOMEPAGE_CHART_FILTER = 'homepage_chart_filter';
|
||||||
|
export const HOMEPAGE_ACTIVITY_FILTER = 'homepage_activity_filter';
|
||||||
|
export const HOMEPAGE_DASHBOARD_FILTER = 'homepage_dashboard_filter';
|
@ -23,6 +23,11 @@ export type FavoriteStatus = {
|
|||||||
[id: number]: boolean;
|
[id: number]: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum TableTabTypes {
|
||||||
|
FAVORITE = 'Favorite',
|
||||||
|
MINE = 'Mine',
|
||||||
|
}
|
||||||
|
|
||||||
export type Filters = {
|
export type Filters = {
|
||||||
col: string;
|
col: string;
|
||||||
opr: string;
|
opr: string;
|
||||||
|
@ -23,7 +23,6 @@ import { ReactWrapper } from 'enzyme';
|
|||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint';
|
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
import ActivityTable from 'src/views/CRUD/welcome/ActivityTable';
|
import ActivityTable from 'src/views/CRUD/welcome/ActivityTable';
|
||||||
|
|
||||||
@ -82,7 +81,7 @@ describe('ActivityTable', () => {
|
|||||||
activityData: mockData,
|
activityData: mockData,
|
||||||
setActiveChild: jest.fn(),
|
setActiveChild: jest.fn(),
|
||||||
user: { userId: '1' },
|
user: { userId: '1' },
|
||||||
loading: false,
|
loadedCount: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
let wrapper: ReactWrapper;
|
let wrapper: ReactWrapper;
|
||||||
@ -113,19 +112,21 @@ describe('ActivityTable', () => {
|
|||||||
handler({} as any);
|
handler({} as any);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await waitForComponentToPaint(wrapper);
|
|
||||||
const dashboardCall = fetchMock.calls(/dashboard\/\?q/);
|
const dashboardCall = fetchMock.calls(/dashboard\/\?q/);
|
||||||
const chartCall = fetchMock.calls(/chart\/\?q/);
|
const chartCall = fetchMock.calls(/chart\/\?q/);
|
||||||
|
// waitforcomponenttopaint does not work here in this instance...
|
||||||
|
setTimeout(() => {
|
||||||
expect(chartCall).toHaveLength(1);
|
expect(chartCall).toHaveLength(1);
|
||||||
expect(dashboardCall).toHaveLength(1);
|
expect(dashboardCall).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
it('show empty state if there is no data', () => {
|
it('show empty state if there is no data', () => {
|
||||||
const activityProps = {
|
const activityProps = {
|
||||||
activeChild: 'Created',
|
activeChild: 'Created',
|
||||||
activityData: {},
|
activityData: {},
|
||||||
setActiveChild: jest.fn(),
|
setActiveChild: jest.fn(),
|
||||||
user: { userId: '1' },
|
user: { userId: '1' },
|
||||||
loading: false,
|
loadedCount: 3,
|
||||||
};
|
};
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
|
@ -24,9 +24,10 @@ import { setInLocalStorage } from 'src/utils/localStorageHelpers';
|
|||||||
import Loading from 'src/components/Loading';
|
import Loading from 'src/components/Loading';
|
||||||
import ListViewCard from 'src/components/ListViewCard';
|
import ListViewCard from 'src/components/ListViewCard';
|
||||||
import SubMenu from 'src/components/Menu/SubMenu';
|
import SubMenu from 'src/components/Menu/SubMenu';
|
||||||
|
import { mq, CardStyles, getEditedObjects } from 'src/views/CRUD/utils';
|
||||||
|
import { HOMEPAGE_ACTIVITY_FILTER } from 'src/views/CRUD/storageKeys';
|
||||||
import { Chart } from 'src/types/Chart';
|
import { Chart } from 'src/types/Chart';
|
||||||
import { Dashboard, SavedQueryObject } from 'src/views/CRUD/types';
|
import { Dashboard, SavedQueryObject } from 'src/views/CRUD/types';
|
||||||
import { mq, CardStyles, getEditedObjects } from 'src/views/CRUD/utils';
|
|
||||||
|
|
||||||
import { ActivityData } from './Welcome';
|
import { ActivityData } from './Welcome';
|
||||||
import EmptyState from './EmptyState';
|
import EmptyState from './EmptyState';
|
||||||
@ -51,6 +52,12 @@ interface RecentDashboard extends RecentActivity {
|
|||||||
item_type: 'dashboard';
|
item_type: 'dashboard';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum SetTabType {
|
||||||
|
EDITED = 'Edited',
|
||||||
|
CREATED = 'Created',
|
||||||
|
VIEWED = 'Viewed',
|
||||||
|
EXAMPLE = 'Examples',
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Recent activity objects fetched by `getRecentAcitivtyObjs`.
|
* Recent activity objects fetched by `getRecentAcitivtyObjs`.
|
||||||
*/
|
*/
|
||||||
@ -68,6 +75,7 @@ interface ActivityProps {
|
|||||||
activeChild: string;
|
activeChild: string;
|
||||||
setActiveChild: (arg0: string) => void;
|
setActiveChild: (arg0: string) => void;
|
||||||
activityData: ActivityData;
|
activityData: ActivityData;
|
||||||
|
loadedCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ActivityContainer = styled.div`
|
const ActivityContainer = styled.div`
|
||||||
@ -161,20 +169,11 @@ export default function ActivityTable({
|
|||||||
setActiveChild,
|
setActiveChild,
|
||||||
activityData,
|
activityData,
|
||||||
user,
|
user,
|
||||||
|
loadedCount,
|
||||||
}: ActivityProps) {
|
}: ActivityProps) {
|
||||||
const [editedObjs, setEditedObjs] = useState<Array<ActivityData>>();
|
const [editedObjs, setEditedObjs] = useState<Array<ActivityData>>();
|
||||||
const [loadingState, setLoadingState] = useState(false);
|
const [loadingState, setLoadingState] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (activeChild === 'Edited') {
|
|
||||||
setLoadingState(true);
|
|
||||||
getEditedObjects(user.userId).then(r => {
|
|
||||||
setEditedObjs([...r.editedChart, ...r.editedDash]);
|
|
||||||
setLoadingState(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const getEditedCards = () => {
|
const getEditedCards = () => {
|
||||||
setLoadingState(true);
|
setLoadingState(true);
|
||||||
getEditedObjects(user.userId).then(r => {
|
getEditedObjects(user.userId).then(r => {
|
||||||
@ -182,14 +181,21 @@ export default function ActivityTable({
|
|||||||
setLoadingState(false);
|
setLoadingState(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeChild === 'Edited') {
|
||||||
|
setLoadingState(true);
|
||||||
|
getEditedCards();
|
||||||
|
}
|
||||||
|
}, [activeChild]);
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
name: 'Edited',
|
name: 'Edited',
|
||||||
label: t('Edited'),
|
label: t('Edited'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setActiveChild('Edited');
|
setActiveChild('Edited');
|
||||||
setInLocalStorage('activity', { activity: 'Edited' });
|
setInLocalStorage(HOMEPAGE_ACTIVITY_FILTER, SetTabType.EDITED);
|
||||||
getEditedCards();
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -197,7 +203,7 @@ export default function ActivityTable({
|
|||||||
label: t('Created'),
|
label: t('Created'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setActiveChild('Created');
|
setActiveChild('Created');
|
||||||
setInLocalStorage('activity', { activity: 'Created' });
|
setInLocalStorage(HOMEPAGE_ACTIVITY_FILTER, SetTabType.CREATED);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -208,7 +214,7 @@ export default function ActivityTable({
|
|||||||
label: t('Viewed'),
|
label: t('Viewed'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setActiveChild('Viewed');
|
setActiveChild('Viewed');
|
||||||
setInLocalStorage('activity', { activity: 'Viewed' });
|
setInLocalStorage(HOMEPAGE_ACTIVITY_FILTER, SetTabType.VIEWED);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -217,7 +223,7 @@ export default function ActivityTable({
|
|||||||
label: t('Examples'),
|
label: t('Examples'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setActiveChild('Examples');
|
setActiveChild('Examples');
|
||||||
setInLocalStorage('activity', { activity: 'Examples' });
|
setInLocalStorage(HOMEPAGE_ACTIVITY_FILTER, SetTabType.EXAMPLE);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -246,16 +252,15 @@ export default function ActivityTable({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (loadingState && !editedObjs) {
|
|
||||||
|
const doneFetching = loadedCount < 3;
|
||||||
|
|
||||||
|
if ((loadingState && !editedObjs) || doneFetching) {
|
||||||
return <Loading position="inline" />;
|
return <Loading position="inline" />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SubMenu
|
<SubMenu activeChild={activeChild} tabs={tabs} />
|
||||||
activeChild={activeChild}
|
|
||||||
// eslint-disable-next-line react/no-children-prop
|
|
||||||
tabs={tabs}
|
|
||||||
/>
|
|
||||||
{activityData[activeChild]?.length > 0 ||
|
{activityData[activeChild]?.length > 0 ||
|
||||||
(activeChild === 'Edited' && editedObjs && editedObjs.length > 0) ? (
|
(activeChild === 'Edited' && editedObjs && editedObjs.length > 0) ? (
|
||||||
<ActivityContainer>{renderActivity()}</ActivityContainer>
|
<ActivityContainer>{renderActivity()}</ActivityContainer>
|
||||||
|
@ -85,11 +85,21 @@ describe('ChartTable', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
await waitForComponentToPaint(wrapper);
|
await waitForComponentToPaint(wrapper);
|
||||||
expect(fetchMock.calls(chartsEndpoint)).toHaveLength(1);
|
expect(fetchMock.calls(chartsEndpoint)).toHaveLength(3);
|
||||||
expect(wrapper.find('ChartCard')).toExist();
|
expect(wrapper.find('ChartCard')).toExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('display EmptyState if there is no data', async () => {
|
it('display EmptyState if there is no data', async () => {
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mount(
|
||||||
|
<ChartTable
|
||||||
|
chartFilter="Mine"
|
||||||
|
user={{ userId: '2' }}
|
||||||
|
mine={[]}
|
||||||
|
store={store}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
});
|
||||||
expect(wrapper.find('EmptyState')).toExist();
|
expect(wrapper.find('EmptyState')).toExist();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -29,8 +29,11 @@ import {
|
|||||||
} from 'src/utils/localStorageHelpers';
|
} from 'src/utils/localStorageHelpers';
|
||||||
import withToasts from 'src/messageToasts/enhancers/withToasts';
|
import withToasts from 'src/messageToasts/enhancers/withToasts';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { TableTabTypes } from 'src/views/CRUD/types';
|
||||||
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
||||||
import { User } from 'src/types/bootstrapTypes';
|
import { User } from 'src/types/bootstrapTypes';
|
||||||
|
import { CardContainer } from 'src/views/CRUD/utils';
|
||||||
|
import { HOMEPAGE_CHART_FILTER } from 'src/views/CRUD/storageKeys';
|
||||||
import ChartCard from 'src/views/CRUD/chart/ChartCard';
|
import ChartCard from 'src/views/CRUD/chart/ChartCard';
|
||||||
import Chart from 'src/types/Chart';
|
import Chart from 'src/types/Chart';
|
||||||
import handleResourceExport from 'src/utils/export';
|
import handleResourceExport from 'src/utils/export';
|
||||||
@ -38,7 +41,6 @@ import Loading from 'src/components/Loading';
|
|||||||
import ErrorBoundary from 'src/components/ErrorBoundary';
|
import ErrorBoundary from 'src/components/ErrorBoundary';
|
||||||
import SubMenu from 'src/components/Menu/SubMenu';
|
import SubMenu from 'src/components/Menu/SubMenu';
|
||||||
import EmptyState from './EmptyState';
|
import EmptyState from './EmptyState';
|
||||||
import { CardContainer } from '../utils';
|
|
||||||
|
|
||||||
const PAGE_SIZE = 3;
|
const PAGE_SIZE = 3;
|
||||||
|
|
||||||
@ -60,6 +62,9 @@ function ChartTable({
|
|||||||
showThumbnails,
|
showThumbnails,
|
||||||
}: ChartTableProps) {
|
}: ChartTableProps) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const filterStore = getFromLocalStorage(HOMEPAGE_CHART_FILTER, null);
|
||||||
|
const initialFilter = filterStore || TableTabTypes.MINE;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
state: { loading, resourceCollection: charts, bulkSelectEnabled },
|
state: { loading, resourceCollection: charts, bulkSelectEnabled },
|
||||||
setResourceCollection: setCharts,
|
setResourceCollection: setCharts,
|
||||||
@ -71,12 +76,11 @@ function ChartTable({
|
|||||||
t('chart'),
|
t('chart'),
|
||||||
addDangerToast,
|
addDangerToast,
|
||||||
true,
|
true,
|
||||||
mine,
|
initialFilter === 'Favorite' ? [] : mine,
|
||||||
[],
|
[],
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {});
|
|
||||||
const chartIds = useMemo(() => charts.map(c => c.id), [charts]);
|
const chartIds = useMemo(() => charts.map(c => c.id), [charts]);
|
||||||
const [saveFavoriteStatus, favoriteStatus] = useFavoriteStatus(
|
const [saveFavoriteStatus, favoriteStatus] = useFavoriteStatus(
|
||||||
'chart',
|
'chart',
|
||||||
@ -90,15 +94,12 @@ function ChartTable({
|
|||||||
closeChartEditModal,
|
closeChartEditModal,
|
||||||
} = useChartEditModal(setCharts, charts);
|
} = useChartEditModal(setCharts, charts);
|
||||||
|
|
||||||
const [chartFilter, setChartFilter] = useState('Mine');
|
const [chartFilter, setChartFilter] = useState(initialFilter);
|
||||||
const [preparingExport, setPreparingExport] = useState<boolean>(false);
|
const [preparingExport, setPreparingExport] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const filter = getFromLocalStorage('chart', null);
|
getData(chartFilter);
|
||||||
if (!filter) {
|
}, [chartFilter]);
|
||||||
setChartFilter('Mine');
|
|
||||||
} else setChartFilter(filter.tab);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleBulkChartExport = (chartsToExport: Chart[]) => {
|
const handleBulkChartExport = (chartsToExport: Chart[]) => {
|
||||||
const ids = chartsToExport.map(({ id }) => id);
|
const ids = chartsToExport.map(({ id }) => id);
|
||||||
@ -159,20 +160,18 @@ function ChartTable({
|
|||||||
{
|
{
|
||||||
name: 'Favorite',
|
name: 'Favorite',
|
||||||
label: t('Favorite'),
|
label: t('Favorite'),
|
||||||
onClick: () =>
|
onClick: () => {
|
||||||
getData('Favorite').then(() => {
|
|
||||||
setChartFilter('Favorite');
|
setChartFilter('Favorite');
|
||||||
setInLocalStorage('chart', { tab: 'Favorite' });
|
setInLocalStorage(HOMEPAGE_CHART_FILTER, TableTabTypes.FAVORITE);
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Mine',
|
name: 'Mine',
|
||||||
label: t('Mine'),
|
label: t('Mine'),
|
||||||
onClick: () =>
|
onClick: () => {
|
||||||
getData('Mine').then(() => {
|
|
||||||
setChartFilter('Mine');
|
setChartFilter('Mine');
|
||||||
setInLocalStorage('chart', { tab: 'Mine' });
|
setInLocalStorage(HOMEPAGE_CHART_FILTER, TableTabTypes.MINE);
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
buttons={[
|
buttons={[
|
||||||
|
@ -19,20 +19,26 @@
|
|||||||
import React, { useState, useMemo, useEffect } from 'react';
|
import React, { useState, useMemo, useEffect } from 'react';
|
||||||
import { SupersetClient, t } from '@superset-ui/core';
|
import { SupersetClient, t } from '@superset-ui/core';
|
||||||
import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks';
|
import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks';
|
||||||
import { Dashboard, DashboardTableProps } from 'src/views/CRUD/types';
|
import {
|
||||||
|
Dashboard,
|
||||||
|
DashboardTableProps,
|
||||||
|
TableTabTypes,
|
||||||
|
} from 'src/views/CRUD/types';
|
||||||
import handleResourceExport from 'src/utils/export';
|
import handleResourceExport from 'src/utils/export';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
setInLocalStorage,
|
setInLocalStorage,
|
||||||
getFromLocalStorage,
|
getFromLocalStorage,
|
||||||
} from 'src/utils/localStorageHelpers';
|
} from 'src/utils/localStorageHelpers';
|
||||||
|
import { createErrorHandler, CardContainer } from 'src/views/CRUD/utils';
|
||||||
|
import { HOMEPAGE_DASHBOARD_FILTER } from 'src/views/CRUD/storageKeys';
|
||||||
|
|
||||||
import withToasts from 'src/messageToasts/enhancers/withToasts';
|
import withToasts from 'src/messageToasts/enhancers/withToasts';
|
||||||
import Loading from 'src/components/Loading';
|
import Loading from 'src/components/Loading';
|
||||||
import PropertiesModal from 'src/dashboard/components/PropertiesModal';
|
import PropertiesModal from 'src/dashboard/components/PropertiesModal';
|
||||||
import DashboardCard from 'src/views/CRUD/dashboard/DashboardCard';
|
import DashboardCard from 'src/views/CRUD/dashboard/DashboardCard';
|
||||||
import SubMenu from 'src/components/Menu/SubMenu';
|
import SubMenu from 'src/components/Menu/SubMenu';
|
||||||
import EmptyState from './EmptyState';
|
import EmptyState from './EmptyState';
|
||||||
import { createErrorHandler, CardContainer } from '../utils';
|
|
||||||
|
|
||||||
const PAGE_SIZE = 3;
|
const PAGE_SIZE = 3;
|
||||||
|
|
||||||
@ -50,6 +56,9 @@ function DashboardTable({
|
|||||||
showThumbnails,
|
showThumbnails,
|
||||||
}: DashboardTableProps) {
|
}: DashboardTableProps) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const filterStore = getFromLocalStorage(HOMEPAGE_DASHBOARD_FILTER, null);
|
||||||
|
const defaultFilter = filterStore || TableTabTypes.MINE;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
state: { loading, resourceCollection: dashboards },
|
state: { loading, resourceCollection: dashboards },
|
||||||
setResourceCollection: setDashboards,
|
setResourceCollection: setDashboards,
|
||||||
@ -61,7 +70,7 @@ function DashboardTable({
|
|||||||
t('dashboard'),
|
t('dashboard'),
|
||||||
addDangerToast,
|
addDangerToast,
|
||||||
true,
|
true,
|
||||||
mine,
|
defaultFilter === 'Favorite' ? [] : mine,
|
||||||
[],
|
[],
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@ -71,16 +80,14 @@ function DashboardTable({
|
|||||||
dashboardIds,
|
dashboardIds,
|
||||||
addDangerToast,
|
addDangerToast,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [editModal, setEditModal] = useState<Dashboard>();
|
const [editModal, setEditModal] = useState<Dashboard>();
|
||||||
const [dashboardFilter, setDashboardFilter] = useState('Mine');
|
const [dashboardFilter, setDashboardFilter] = useState(defaultFilter);
|
||||||
const [preparingExport, setPreparingExport] = useState<boolean>(false);
|
const [preparingExport, setPreparingExport] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const filter = getFromLocalStorage('dashboard', null);
|
getData(dashboardFilter);
|
||||||
if (!filter) {
|
}, [dashboardFilter]);
|
||||||
setDashboardFilter('Mine');
|
|
||||||
} else setDashboardFilter(filter.tab);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleBulkDashboardExport = (dashboardsToExport: Dashboard[]) => {
|
const handleBulkDashboardExport = (dashboardsToExport: Dashboard[]) => {
|
||||||
const ids = dashboardsToExport.map(({ id }) => id);
|
const ids = dashboardsToExport.map(({ id }) => id);
|
||||||
@ -128,14 +135,6 @@ function DashboardTable({
|
|||||||
}
|
}
|
||||||
return filters;
|
return filters;
|
||||||
};
|
};
|
||||||
const subMenus = [];
|
|
||||||
if (dashboards.length > 0 && dashboardFilter === 'favorite') {
|
|
||||||
subMenus.push({
|
|
||||||
name: 'Favorite',
|
|
||||||
label: t('Favorite'),
|
|
||||||
onClick: () => setDashboardFilter('Favorite'),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const getData = (filter: string) =>
|
const getData = (filter: string) =>
|
||||||
fetchData({
|
fetchData({
|
||||||
@ -160,20 +159,19 @@ function DashboardTable({
|
|||||||
name: 'Favorite',
|
name: 'Favorite',
|
||||||
label: t('Favorite'),
|
label: t('Favorite'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
getData('Favorite').then(() => {
|
setDashboardFilter(TableTabTypes.FAVORITE);
|
||||||
setDashboardFilter('Favorite');
|
setInLocalStorage(
|
||||||
setInLocalStorage('dashboard', { tab: 'Favorite' });
|
HOMEPAGE_DASHBOARD_FILTER,
|
||||||
});
|
TableTabTypes.FAVORITE,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Mine',
|
name: 'Mine',
|
||||||
label: t('Mine'),
|
label: t('Mine'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
getData('Mine').then(() => {
|
setDashboardFilter(TableTabTypes.MINE);
|
||||||
setDashboardFilter('Mine');
|
setInLocalStorage(HOMEPAGE_DASHBOARD_FILTER, TableTabTypes.MINE);
|
||||||
setInLocalStorage('dashboard', { tab: 'Mine' });
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
@ -132,10 +132,10 @@ describe('Welcome', () => {
|
|||||||
const savedQueryCall = fetchMock.calls(/saved_query\/\?q/);
|
const savedQueryCall = fetchMock.calls(/saved_query\/\?q/);
|
||||||
const recentCall = fetchMock.calls(/superset\/recent_activity\/*/);
|
const recentCall = fetchMock.calls(/superset\/recent_activity\/*/);
|
||||||
const dashboardCall = fetchMock.calls(/dashboard\/\?q/);
|
const dashboardCall = fetchMock.calls(/dashboard\/\?q/);
|
||||||
expect(chartCall).toHaveLength(1);
|
expect(chartCall).toHaveLength(2);
|
||||||
expect(recentCall).toHaveLength(1);
|
expect(recentCall).toHaveLength(1);
|
||||||
expect(savedQueryCall).toHaveLength(1);
|
expect(savedQueryCall).toHaveLength(1);
|
||||||
expect(dashboardCall).toHaveLength(1);
|
expect(dashboardCall).toHaveLength(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ import {
|
|||||||
mq,
|
mq,
|
||||||
getUserOwnedObjects,
|
getUserOwnedObjects,
|
||||||
} from 'src/views/CRUD/utils';
|
} from 'src/views/CRUD/utils';
|
||||||
|
import { HOMEPAGE_ACTIVITY_FILTER } from 'src/views/CRUD/storageKeys';
|
||||||
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
||||||
import { Switch } from 'src/common/components';
|
import { Switch } from 'src/common/components';
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ const WelcomeContainer = styled.div`
|
|||||||
margin: 0px ${({ theme }) => theme.gridUnit * 6}px;
|
margin: 0px ${({ theme }) => theme.gridUnit * 6}px;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
${[mq[1]]} {
|
${mq[1]} {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin: 0px 2px;
|
margin: 0px 2px;
|
||||||
}
|
}
|
||||||
@ -104,7 +105,7 @@ const WelcomeNav = styled.div`
|
|||||||
|
|
||||||
function Welcome({ user, addDangerToast }: WelcomeProps) {
|
function Welcome({ user, addDangerToast }: WelcomeProps) {
|
||||||
const recent = `/superset/recent_activity/${user.userId}/?limit=6`;
|
const recent = `/superset/recent_activity/${user.userId}/?limit=6`;
|
||||||
const [activeChild, setActiveChild] = useState('Viewed');
|
const [activeChild, setActiveChild] = useState('Loading');
|
||||||
const [checked, setChecked] = useState(true);
|
const [checked, setChecked] = useState(true);
|
||||||
const [activityData, setActivityData] = useState<ActivityData | null>(null);
|
const [activityData, setActivityData] = useState<ActivityData | null>(null);
|
||||||
const [chartData, setChartData] = useState<Array<object> | null>(null);
|
const [chartData, setChartData] = useState<Array<object> | null>(null);
|
||||||
@ -112,12 +113,14 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
|
|||||||
const [dashboardData, setDashboardData] = useState<Array<object> | null>(
|
const [dashboardData, setDashboardData] = useState<Array<object> | null>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
const [loadedCount, setLoadedCount] = useState(0);
|
||||||
|
|
||||||
const userid = user.userId;
|
const userid = user.userId;
|
||||||
const id = userid.toString();
|
const id = userid.toString();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const userKey = getFromLocalStorage(id, null);
|
const userKey = getFromLocalStorage(id, null);
|
||||||
|
const activeTab = getFromLocalStorage(HOMEPAGE_ACTIVITY_FILTER, null);
|
||||||
if (userKey && !userKey.thumbnails) setChecked(false);
|
if (userKey && !userKey.thumbnails) setChecked(false);
|
||||||
getRecentAcitivtyObjs(user.userId, recent, addDangerToast)
|
getRecentAcitivtyObjs(user.userId, recent, addDangerToast)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -125,13 +128,14 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
|
|||||||
if (res.viewed) {
|
if (res.viewed) {
|
||||||
const filtered = reject(res.viewed, ['item_url', null]).map(r => r);
|
const filtered = reject(res.viewed, ['item_url', null]).map(r => r);
|
||||||
data.Viewed = filtered;
|
data.Viewed = filtered;
|
||||||
const savedActivity = getFromLocalStorage('activity', null);
|
if (!activeTab) {
|
||||||
if (!savedActivity) {
|
|
||||||
setActiveChild('Viewed');
|
setActiveChild('Viewed');
|
||||||
} else setActiveChild(savedActivity.activity);
|
} else setActiveChild(activeTab);
|
||||||
} else {
|
} else {
|
||||||
data.Examples = res.examples;
|
data.Examples = res.examples;
|
||||||
|
if (activeTab === 'Viewed' || !activeTab) {
|
||||||
setActiveChild('Examples');
|
setActiveChild('Examples');
|
||||||
|
} else setActiveChild(activeTab);
|
||||||
}
|
}
|
||||||
setActivityData(activityData => ({ ...activityData, ...data }));
|
setActivityData(activityData => ({ ...activityData, ...data }));
|
||||||
})
|
})
|
||||||
@ -145,12 +149,15 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Sets other activity data in parallel with recents api call
|
// Sets other activity data in parallel with recents api call
|
||||||
|
|
||||||
getUserOwnedObjects(id, 'dashboard')
|
getUserOwnedObjects(id, 'dashboard')
|
||||||
.then(r => {
|
.then(r => {
|
||||||
setDashboardData(r);
|
setDashboardData(r);
|
||||||
|
setLoadedCount(loadedCount => loadedCount + 1);
|
||||||
})
|
})
|
||||||
.catch((err: unknown) => {
|
.catch((err: unknown) => {
|
||||||
setDashboardData([]);
|
setDashboardData([]);
|
||||||
|
setLoadedCount(loadedCount => loadedCount + 1);
|
||||||
addDangerToast(
|
addDangerToast(
|
||||||
t('There was an issues fetching your dashboards: %s', err),
|
t('There was an issues fetching your dashboards: %s', err),
|
||||||
);
|
);
|
||||||
@ -158,17 +165,21 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
|
|||||||
getUserOwnedObjects(id, 'chart')
|
getUserOwnedObjects(id, 'chart')
|
||||||
.then(r => {
|
.then(r => {
|
||||||
setChartData(r);
|
setChartData(r);
|
||||||
|
setLoadedCount(loadedCount => loadedCount + 1);
|
||||||
})
|
})
|
||||||
.catch((err: unknown) => {
|
.catch((err: unknown) => {
|
||||||
setChartData([]);
|
setChartData([]);
|
||||||
|
setLoadedCount(loadedCount => loadedCount + 1);
|
||||||
addDangerToast(t('There was an issues fetching your chart: %s', err));
|
addDangerToast(t('There was an issues fetching your chart: %s', err));
|
||||||
});
|
});
|
||||||
getUserOwnedObjects(id, 'saved_query')
|
getUserOwnedObjects(id, 'saved_query')
|
||||||
.then(r => {
|
.then(r => {
|
||||||
setQueryData(r);
|
setQueryData(r);
|
||||||
|
setLoadedCount(loadedCount => loadedCount + 1);
|
||||||
})
|
})
|
||||||
.catch((err: unknown) => {
|
.catch((err: unknown) => {
|
||||||
setQueryData([]);
|
setQueryData([]);
|
||||||
|
setLoadedCount(loadedCount => loadedCount + 1);
|
||||||
addDangerToast(
|
addDangerToast(
|
||||||
t('There was an issues fetching your saved queries: %s', err),
|
t('There was an issues fetching your saved queries: %s', err),
|
||||||
);
|
);
|
||||||
@ -204,12 +215,17 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
|
|||||||
</WelcomeNav>
|
</WelcomeNav>
|
||||||
<Collapse defaultActiveKey={['1', '2', '3', '4']} ghost bigger>
|
<Collapse defaultActiveKey={['1', '2', '3', '4']} ghost bigger>
|
||||||
<Collapse.Panel header={t('Recents')} key="1">
|
<Collapse.Panel header={t('Recents')} key="1">
|
||||||
{activityData && (activityData.Viewed || activityData.Examples) ? (
|
{activityData &&
|
||||||
|
(activityData.Viewed ||
|
||||||
|
activityData.Examples ||
|
||||||
|
activityData.Created) &&
|
||||||
|
activeChild !== 'Loading' ? (
|
||||||
<ActivityTable
|
<ActivityTable
|
||||||
user={user}
|
user={user}
|
||||||
activeChild={activeChild}
|
activeChild={activeChild}
|
||||||
setActiveChild={setActiveChild}
|
setActiveChild={setActiveChild}
|
||||||
activityData={activityData}
|
activityData={activityData}
|
||||||
|
loadedCount={loadedCount}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Loading position="inline" />
|
<Loading position="inline" />
|
||||||
|
Loading…
Reference in New Issue
Block a user