You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by el...@apache.org on 2024/05/22 00:40:57 UTC
(superset) 01/01: add refresh for thumbnail_url
This is an automated email from the ASF dual-hosted git repository.
elizabeth pushed a commit to branch fix/dashboard-perf
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 49bcc719da06a78a306ed429f54197c21dd546ff
Author: Elizabeth Thompson <es...@gmail.com>
AuthorDate: Tue May 21 15:49:04 2024 -0700
add refresh for thumbnail_url
---
.../src/features/dashboards/DashboardCard.test.tsx | 139 +++++++++++++++++++++
.../src/features/dashboards/DashboardCard.tsx | 45 ++++++-
2 files changed, 182 insertions(+), 2 deletions(-)
diff --git a/superset-frontend/src/features/dashboards/DashboardCard.test.tsx b/superset-frontend/src/features/dashboards/DashboardCard.test.tsx
new file mode 100644
index 0000000000..10c31fe231
--- /dev/null
+++ b/superset-frontend/src/features/dashboards/DashboardCard.test.tsx
@@ -0,0 +1,139 @@
+import React from 'react';
+import { MemoryRouter } from 'react-router-dom';
+import { FeatureFlag, SupersetClient } from '@superset-ui/core';
+import * as uiCore from '@superset-ui/core';
+
+import { render, screen, waitFor } from 'spec/helpers/testing-library';
+
+import DashboardCard from './DashboardCard';
+
+const mockDashboard = {
+ id: 1,
+ dashboard_title: 'Sample Dashboard',
+ certified_by: 'John Doe',
+ certification_details: 'Certified on 2022-01-01',
+ published: true,
+ url: '/dashboard/1',
+ thumbnail_url: '/thumbnails/1.png',
+ changed_on_delta_humanized: '2 days ago',
+ owners: [
+ { id: 1, name: 'Alice', first_name: 'Alice', last_name: 'Doe' },
+ { id: 2, name: 'Bob', first_name: 'Bob', last_name: 'Smith' },
+ ],
+ changed_by_name: 'John Doe',
+ changed_by: 'john.doe@example.com',
+};
+
+const mockHasPerm = jest.fn().mockReturnValue(true);
+const mockOpenDashboardEditModal = jest.fn();
+const mockSaveFavoriteStatus = jest.fn();
+const mockHandleBulkDashboardExport = jest.fn();
+const mockOnDelete = jest.fn();
+
+let isFeatureEnabledMock: jest.MockInstance<boolean, [feature: FeatureFlag]>;
+
+beforeAll(() => {
+ isFeatureEnabledMock = jest
+ .spyOn(uiCore, 'isFeatureEnabled')
+ .mockImplementation(() => true);
+});
+
+afterAll(() => {
+ // @ts-ignore
+ isFeatureEnabledMock.mockClear();
+});
+
+beforeEach(() => {
+ render(
+ <MemoryRouter>
+ <DashboardCard
+ dashboard={mockDashboard}
+ hasPerm={mockHasPerm}
+ bulkSelectEnabled={false}
+ loading={false}
+ openDashboardEditModal={mockOpenDashboardEditModal}
+ saveFavoriteStatus={mockSaveFavoriteStatus}
+ favoriteStatus={false}
+ handleBulkDashboardExport={mockHandleBulkDashboardExport}
+ onDelete={mockOnDelete}
+ />
+ </MemoryRouter>,
+ );
+});
+
+it('Renders the dashboard title', () => {
+ const titleElement = screen.getByText('Sample Dashboard');
+ expect(titleElement).toBeInTheDocument();
+});
+
+it('Renders the certification details', () => {
+ const certificationDetailsElement = screen.getByLabelText(/certified/i);
+ expect(certificationDetailsElement).toBeInTheDocument();
+});
+
+it('Renders the published status', () => {
+ const publishedElement = screen.getByText(/published/i);
+ expect(publishedElement).toBeInTheDocument();
+});
+
+it('Renders the modified date', () => {
+ const modifiedDateElement = screen.getByText('Modified 2 days ago');
+ expect(modifiedDateElement).toBeInTheDocument();
+});
+
+it('should fetch thumbnail when dashboard has no thumbnail URL and feature flag is enabled', async () => {
+ const mockGet = jest.spyOn(SupersetClient, 'get').mockResolvedValue({
+ response: new Response(
+ JSON.stringify({ thumbnail_url: '/new-thumbnail.png' }),
+ ),
+ json: () => Promise.resolve({ thumbnail_url: '/new-thumbnail.png' }),
+ });
+ const { rerender } = render(
+ <DashboardCard
+ dashboard={{
+ id: 1,
+ thumbnail_url: '',
+ changed_by_name: '',
+ changed_by: '',
+ dashboard_title: '',
+ published: false,
+ url: '',
+ owners: [],
+ }}
+ hasPerm={() => true}
+ bulkSelectEnabled={false}
+ loading={false}
+ saveFavoriteStatus={() => {}}
+ favoriteStatus={false}
+ handleBulkDashboardExport={() => {}}
+ onDelete={() => {}}
+ />,
+ );
+ await waitFor(() => {
+ expect(mockGet).toHaveBeenCalledWith({
+ endpoint: '/api/v1/dashboard/1',
+ });
+ });
+ rerender(
+ <DashboardCard
+ dashboard={{
+ id: 1,
+ thumbnail_url: '/new-thumbnail.png',
+ changed_by_name: '',
+ changed_by: '',
+ dashboard_title: '',
+ published: false,
+ url: '',
+ owners: [],
+ }}
+ hasPerm={() => true}
+ bulkSelectEnabled={false}
+ loading={false}
+ saveFavoriteStatus={() => {}}
+ favoriteStatus={false}
+ handleBulkDashboardExport={() => {}}
+ onDelete={() => {}}
+ />,
+ );
+ mockGet.mockRestore();
+});
diff --git a/superset-frontend/src/features/dashboards/DashboardCard.tsx b/superset-frontend/src/features/dashboards/DashboardCard.tsx
index e977c62f52..400e358ab2 100644
--- a/superset-frontend/src/features/dashboards/DashboardCard.tsx
+++ b/superset-frontend/src/features/dashboards/DashboardCard.tsx
@@ -16,9 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import { Link, useHistory } from 'react-router-dom';
-import { isFeatureEnabled, FeatureFlag, t, useTheme } from '@superset-ui/core';
+import {
+ isFeatureEnabled,
+ FeatureFlag,
+ t,
+ useTheme,
+ SupersetClient,
+} from '@superset-ui/core';
import { CardStyles } from 'src/views/CRUD/utils';
import { AntdDropdown } from 'src/components';
import { Menu } from 'src/components/Menu';
@@ -62,6 +68,41 @@ function DashboardCard({
const canExport = hasPerm('can_export');
const theme = useTheme();
+
+ const [thumbnailUrl, setThumbnailUrl] = useState<string | null>(null);
+ const [fetchingThumbnail, setFetchingThumbnail] = useState<boolean>(false);
+
+ useEffect(() => {
+ // fetch thumbnail only if it's not already fetched
+ console.error(
+ isFeatureEnabled(FeatureFlag.Thumbnails),
+ thumbnailUrl,
+ fetchingThumbnail,
+ dashboard.id,
+ );
+ if (
+ !fetchingThumbnail &&
+ dashboard.id &&
+ (thumbnailUrl === undefined || thumbnailUrl === null) &&
+ isFeatureEnabled(FeatureFlag.Thumbnails)
+ ) {
+ // fetch thumbnail
+ if (dashboard.thumbnail_url) {
+ // set to empty string if null so that we don't
+ // keep fetching the thumbnail
+ setThumbnailUrl(dashboard.thumbnail_url || '');
+ return;
+ }
+ setFetchingThumbnail(true);
+ SupersetClient.get({
+ endpoint: `/api/v1/dashboard/${dashboard.id}`,
+ }).then(({ json = {} }) => {
+ setThumbnailUrl(json.thumbnail_url || '');
+ setFetchingThumbnail(false);
+ });
+ }
+ }, [dashboard, thumbnailUrl]);
+
const menu = (
<Menu>
{canEdit && openDashboardEditModal && (