fix(dashboard list): do not show favorite star for anonymous users #18210 (#19409)

* fix: Only show favorite star on dashboard list if user is logged in #18210

* Fix linter errors
This commit is contained in:
dudasaron 2022-04-04 09:38:44 +02:00 committed by GitHub
parent 5db36ec81c
commit b8891acf4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 120 additions and 45 deletions

View File

@ -26,7 +26,7 @@ import CertifiedBadge from '../CertifiedBadge';
const ActionsWrapper = styled.div` const ActionsWrapper = styled.div`
width: 64px; width: 64px;
display: flex; display: flex;
justify-content: space-between; justify-content: flex-end;
`; `;
const StyledCard = styled(AntdCard)` const StyledCard = styled(AntdCard)`

View File

@ -44,7 +44,7 @@ interface DashboardCardProps {
saveFavoriteStatus: (id: number, isStarred: boolean) => void; saveFavoriteStatus: (id: number, isStarred: boolean) => void;
favoriteStatus: boolean; favoriteStatus: boolean;
dashboardFilter?: string; dashboardFilter?: string;
userId?: number; userId?: string | number;
showThumbnails?: boolean; showThumbnails?: boolean;
handleBulkDashboardExport: (dashboardsToExport: Dashboard[]) => void; handleBulkDashboardExport: (dashboardsToExport: Dashboard[]) => void;
} }
@ -171,11 +171,13 @@ function DashboardCard({
e.preventDefault(); e.preventDefault();
}} }}
> >
<FaveStar {userId && (
itemId={dashboard.id} <FaveStar
saveFaveStar={saveFavoriteStatus} itemId={dashboard.id}
isStarred={favoriteStatus} saveFaveStar={saveFavoriteStatus}
/> isStarred={favoriteStatus}
/>
)}
<AntdDropdown overlay={menu}> <AntdDropdown overlay={menu}>
<Icons.MoreVert iconColor={theme.colors.grayscale.base} /> <Icons.MoreVert iconColor={theme.colors.grayscale.base} />
</AntdDropdown> </AntdDropdown>

View File

@ -36,6 +36,9 @@ import DashboardList from 'src/views/CRUD/dashboard/DashboardList';
import ListView from 'src/components/ListView'; import ListView from 'src/components/ListView';
import ListViewCard from 'src/components/ListViewCard'; import ListViewCard from 'src/components/ListViewCard';
import PropertiesModal from 'src/dashboard/components/PropertiesModal'; import PropertiesModal from 'src/dashboard/components/PropertiesModal';
import FaveStar from 'src/components/FaveStar';
import TableCollection from 'src/components/TableCollection';
import CardCollection from 'src/components/ListView/CardCollection';
// store needed for withToasts(DashboardTable) // store needed for withToasts(DashboardTable)
const mockStore = configureStore([thunk]); const mockStore = configureStore([thunk]);
@ -104,15 +107,18 @@ describe('DashboardList', () => {
}); });
const mockedProps = {}; const mockedProps = {};
const wrapper = mount( let wrapper;
<MemoryRouter>
<Provider store={store}>
<DashboardList {...mockedProps} user={mockUser} />
</Provider>
</MemoryRouter>,
);
beforeAll(async () => { beforeAll(async () => {
fetchMock.resetHistory();
wrapper = mount(
<MemoryRouter>
<Provider store={store}>
<DashboardList {...mockedProps} user={mockUser} />
</Provider>
</MemoryRouter>,
);
await waitForComponentToPaint(wrapper); await waitForComponentToPaint(wrapper);
}); });
@ -178,6 +184,18 @@ describe('DashboardList', () => {
await waitForComponentToPaint(wrapper); await waitForComponentToPaint(wrapper);
expect(wrapper.find(ConfirmStatusChange)).toExist(); expect(wrapper.find(ConfirmStatusChange)).toExist();
}); });
it('renders the Favorite Star column in list view for logged in user', async () => {
wrapper.find('[aria-label="list-view"]').first().simulate('click');
await waitForComponentToPaint(wrapper);
expect(wrapper.find(TableCollection).find(FaveStar)).toExist();
});
it('renders the Favorite Star in card view for logged in user', async () => {
wrapper.find('[aria-label="card-view"]').first().simulate('click');
await waitForComponentToPaint(wrapper);
expect(wrapper.find(CardCollection).find(FaveStar)).toExist();
});
}); });
describe('RTL', () => { describe('RTL', () => {
@ -222,3 +240,39 @@ describe('RTL', () => {
expect(importTooltip).toBeInTheDocument(); expect(importTooltip).toBeInTheDocument();
}); });
}); });
describe('DashboardList - anonymous view', () => {
const mockedProps = {};
const mockUserLoggedOut = {};
let wrapper;
beforeAll(async () => {
fetchMock.resetHistory();
wrapper = mount(
<MemoryRouter>
<Provider store={store}>
<DashboardList {...mockedProps} user={mockUserLoggedOut} />
</Provider>
</MemoryRouter>,
);
await waitForComponentToPaint(wrapper);
});
afterAll(() => {
cleanup();
fetch.resetMocks();
});
it('does not render the Favorite Star column in list view for anonymous user', async () => {
wrapper.find('[aria-label="list-view"]').first().simulate('click');
await waitForComponentToPaint(wrapper);
expect(wrapper.find(TableCollection).find(FaveStar)).not.toExist();
});
it('does not render the Favorite Star in card view for anonymous user', async () => {
wrapper.find('[aria-label="card-view"]').first().simulate('click');
await waitForComponentToPaint(wrapper);
expect(wrapper.find(CardCollection).find(FaveStar)).not.toExist();
});
});

View File

@ -17,7 +17,7 @@
* under the License. * under the License.
*/ */
import { styled, SupersetClient, t } from '@superset-ui/core'; import { styled, SupersetClient, t } from '@superset-ui/core';
import React, { useState, useMemo } from 'react'; import React, { useState, useMemo, useCallback } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import rison from 'rison'; import rison from 'rison';
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
@ -95,7 +95,11 @@ const Actions = styled.div`
`; `;
function DashboardList(props: DashboardListProps) { function DashboardList(props: DashboardListProps) {
const { addDangerToast, addSuccessToast } = props; const {
addDangerToast,
addSuccessToast,
user: { userId },
} = props;
const { const {
state: { state: {
@ -143,7 +147,6 @@ function DashboardList(props: DashboardListProps) {
addSuccessToast(t('Dashboard imported')); addSuccessToast(t('Dashboard imported'));
}; };
const { userId } = props.user;
// TODO: Fix usage of localStorage keying on the user id // TODO: Fix usage of localStorage keying on the user id
const userKey = dangerouslyGetItemDoNotUse(userId?.toString(), null); const userKey = dangerouslyGetItemDoNotUse(userId?.toString(), null);
@ -232,27 +235,25 @@ function DashboardList(props: DashboardListProps) {
const columns = useMemo( const columns = useMemo(
() => [ () => [
...(props.user.userId {
? [ Cell: ({
{ row: {
Cell: ({ original: { id },
row: { },
original: { id }, }: any) =>
}, userId && (
}: any) => ( <FaveStar
<FaveStar itemId={id}
itemId={id} saveFaveStar={saveFavoriteStatus}
saveFaveStar={saveFavoriteStatus} isStarred={favoriteStatus[id]}
isStarred={favoriteStatus[id]} />
/> ),
), Header: '',
Header: '', id: 'id',
id: 'id', disableSortBy: true,
disableSortBy: true, size: 'xs',
size: 'xs', hidden: !userId,
}, },
]
: []),
{ {
Cell: ({ Cell: ({
row: { row: {
@ -422,10 +423,15 @@ function DashboardList(props: DashboardListProps) {
}, },
], ],
[ [
userId,
canEdit, canEdit,
canDelete, canDelete,
canExport, canExport,
...(props.user.userId ? [favoriteStatus] : []), saveFavoriteStatus,
favoriteStatus,
refreshData,
addSuccessToast,
addDangerToast,
], ],
); );
@ -500,7 +506,7 @@ function DashboardList(props: DashboardListProps) {
{ label: t('Draft'), value: false }, { label: t('Draft'), value: false },
], ],
}, },
...(props.user.userId ? [favoritesFilter] : []), ...(userId ? [favoritesFilter] : []),
{ {
Header: t('Certified'), Header: t('Certified'),
id: 'id', id: 'id',
@ -544,8 +550,8 @@ function DashboardList(props: DashboardListProps) {
}, },
]; ];
function renderCard(dashboard: Dashboard) { const renderCard = useCallback(
return ( (dashboard: Dashboard) => (
<DashboardCard <DashboardCard
dashboard={dashboard} dashboard={dashboard}
hasPerm={hasPerm} hasPerm={hasPerm}
@ -556,6 +562,7 @@ function DashboardList(props: DashboardListProps) {
? userKey.thumbnails ? userKey.thumbnails
: isFeatureEnabled(FeatureFlag.THUMBNAILS) : isFeatureEnabled(FeatureFlag.THUMBNAILS)
} }
userId={userId}
loading={loading} loading={loading}
addDangerToast={addDangerToast} addDangerToast={addDangerToast}
addSuccessToast={addSuccessToast} addSuccessToast={addSuccessToast}
@ -564,8 +571,20 @@ function DashboardList(props: DashboardListProps) {
favoriteStatus={favoriteStatus[dashboard.id]} favoriteStatus={favoriteStatus[dashboard.id]}
handleBulkDashboardExport={handleBulkDashboardExport} handleBulkDashboardExport={handleBulkDashboardExport}
/> />
); ),
} [
addDangerToast,
addSuccessToast,
bulkSelectEnabled,
favoriteStatus,
hasPerm,
loading,
userId,
refreshData,
saveFavoriteStatus,
userKey,
],
);
const subMenuButtons: SubMenuProps['buttons'] = []; const subMenuButtons: SubMenuProps['buttons'] = [];
if (canDelete || canExport) { if (canDelete || canExport) {

View File

@ -285,7 +285,7 @@ export function handleDashboardDelete(
addSuccessToast: (arg0: string) => void, addSuccessToast: (arg0: string) => void,
addDangerToast: (arg0: string) => void, addDangerToast: (arg0: string) => void,
dashboardFilter?: string, dashboardFilter?: string,
userId?: number, userId?: string | number,
) { ) {
return SupersetClient.delete({ return SupersetClient.delete({
endpoint: `/api/v1/dashboard/${id}`, endpoint: `/api/v1/dashboard/${id}`,