From 8d1c4491b76831c4e998d7d87c9787bcc25c2025 Mon Sep 17 00:00:00 2001 From: amlannandy Date: Wed, 4 Dec 2024 21:12:28 +0530 Subject: [PATCH 1/8] feat: add functionality to export dashboard as json from listing page --- .../ListOfDashboard/DashboardsList.tsx | 28 +++++++++++++++++++ .../DashboardDescription/index.tsx | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/frontend/src/container/ListOfDashboard/DashboardsList.tsx b/frontend/src/container/ListOfDashboard/DashboardsList.tsx index 0a5b3b5130..d45ddaebdd 100644 --- a/frontend/src/container/ListOfDashboard/DashboardsList.tsx +++ b/frontend/src/container/ListOfDashboard/DashboardsList.tsx @@ -27,6 +27,8 @@ import { AxiosError } from 'axios'; import cx from 'classnames'; import { ENTITY_VERSION_V4 } from 'constants/app'; import ROUTES from 'constants/routes'; +import { sanitizeDashboardData } from 'container/NewDashboard/DashboardDescription'; +import { downloadObjectAsJson } from 'container/NewDashboard/DashboardDescription/utils'; import { Base64Icons } from 'container/NewDashboard/DashboardSettings/General/utils'; import dayjs from 'dayjs'; import { useGetAllDashboard } from 'hooks/dashboard/useGetAllDashboard'; @@ -44,6 +46,7 @@ import { EllipsisVertical, Expand, ExternalLink, + FileJson, Github, HdmiPort, LayoutGrid, @@ -450,6 +453,23 @@ function DashboardsList(): JSX.Element { }); }; + const handleJsonExport = (event: React.MouseEvent): void => { + event.stopPropagation(); + event.preventDefault(); + const selectedDashboardData = dashboards?.find( + (d) => d.uuid === dashboard.id, + ); + if (selectedDashboardData) { + downloadObjectAsJson( + sanitizeDashboardData({ + ...selectedDashboardData.data, + uuid: selectedDashboardData.uuid, + }), + dashboard.name, + ); + } + }; + return (
@@ -523,6 +543,14 @@ function DashboardsList(): JSX.Element { > Copy Link +
{ if (!selectedData?.variables) { From 715f8a2363e69f24b8e57da6d9040a13ef10c2c3 Mon Sep 17 00:00:00 2001 From: amlannandy Date: Thu, 5 Dec 2024 11:19:25 +0530 Subject: [PATCH 2/8] feat: address comments --- .../container/ListOfDashboard/DashboardsList.tsx | 14 +------------- .../NewDashboard/DashboardDescription/index.tsx | 2 +- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/frontend/src/container/ListOfDashboard/DashboardsList.tsx b/frontend/src/container/ListOfDashboard/DashboardsList.tsx index d45ddaebdd..afaa597139 100644 --- a/frontend/src/container/ListOfDashboard/DashboardsList.tsx +++ b/frontend/src/container/ListOfDashboard/DashboardsList.tsx @@ -27,7 +27,6 @@ import { AxiosError } from 'axios'; import cx from 'classnames'; import { ENTITY_VERSION_V4 } from 'constants/app'; import ROUTES from 'constants/routes'; -import { sanitizeDashboardData } from 'container/NewDashboard/DashboardDescription'; import { downloadObjectAsJson } from 'container/NewDashboard/DashboardDescription/utils'; import { Base64Icons } from 'container/NewDashboard/DashboardSettings/General/utils'; import dayjs from 'dayjs'; @@ -456,18 +455,7 @@ function DashboardsList(): JSX.Element { const handleJsonExport = (event: React.MouseEvent): void => { event.stopPropagation(); event.preventDefault(); - const selectedDashboardData = dashboards?.find( - (d) => d.uuid === dashboard.id, - ); - if (selectedDashboardData) { - downloadObjectAsJson( - sanitizeDashboardData({ - ...selectedDashboardData.data, - uuid: selectedDashboardData.uuid, - }), - dashboard.name, - ); - } + downloadObjectAsJson(dashboard, dashboard.name); }; return ( diff --git a/frontend/src/container/NewDashboard/DashboardDescription/index.tsx b/frontend/src/container/NewDashboard/DashboardDescription/index.tsx index 7845cf818e..151fba7609 100644 --- a/frontend/src/container/NewDashboard/DashboardDescription/index.tsx +++ b/frontend/src/container/NewDashboard/DashboardDescription/index.tsx @@ -65,7 +65,7 @@ interface DashboardDescriptionProps { handle: FullScreenHandle; } -export function sanitizeDashboardData( +function sanitizeDashboardData( selectedData: DashboardData, ): Omit { if (!selectedData?.variables) { From b35b9757986972e9d4408d3a0928c013b0bc44b2 Mon Sep 17 00:00:00 2001 From: amlannandy Date: Fri, 6 Dec 2024 10:05:45 +0530 Subject: [PATCH 3/8] chore: address comments --- .../ListOfDashboard/DashboardsList.tsx | 24 +++++++++++++++++-- .../DashboardDescription/index.tsx | 2 +- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/frontend/src/container/ListOfDashboard/DashboardsList.tsx b/frontend/src/container/ListOfDashboard/DashboardsList.tsx index afaa597139..14718a562b 100644 --- a/frontend/src/container/ListOfDashboard/DashboardsList.tsx +++ b/frontend/src/container/ListOfDashboard/DashboardsList.tsx @@ -27,6 +27,7 @@ import { AxiosError } from 'axios'; import cx from 'classnames'; import { ENTITY_VERSION_V4 } from 'constants/app'; import ROUTES from 'constants/routes'; +import { sanitizeDashboardData } from 'container/NewDashboard/DashboardDescription'; import { downloadObjectAsJson } from 'container/NewDashboard/DashboardDescription/utils'; import { Base64Icons } from 'container/NewDashboard/DashboardSettings/General/utils'; import dayjs from 'dayjs'; @@ -68,12 +69,18 @@ import { useRef, useState, } from 'react'; +import { Layout } from 'react-grid-layout'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { generatePath, Link } from 'react-router-dom'; import { useCopyToClipboard } from 'react-use'; import { AppState } from 'store/reducers'; -import { Dashboard } from 'types/api/dashboard/getAll'; +import { + Dashboard, + IDashboardVariable, + WidgetRow, + Widgets, +} from 'types/api/dashboard/getAll'; import AppReducer from 'types/reducer/app'; import { isCloudUser } from 'utils/app'; @@ -262,6 +269,11 @@ function DashboardsList(): JSX.Element { isLocked: !!e.isLocked || false, lastUpdatedBy: e.updated_by, image: e.data.image || Base64Icons[0], + variables: e.data.variables, + widgets: e.data.widgets, + layout: e.data.layout, + panelMap: e.data.panelMap, + version: e.data.version, refetchDashboardList, })) || []; @@ -455,7 +467,10 @@ function DashboardsList(): JSX.Element { const handleJsonExport = (event: React.MouseEvent): void => { event.stopPropagation(); event.preventDefault(); - downloadObjectAsJson(dashboard, dashboard.name); + downloadObjectAsJson( + sanitizeDashboardData({ ...dashboard, title: dashboard.name }), + dashboard.name, + ); }; return ( @@ -1121,6 +1136,11 @@ export interface Data { isLocked: boolean; id: string; image?: string; + widgets?: Array; + layout?: Layout[]; + panelMap?: Record; + variables: Record; + version?: string; } export default DashboardsList; diff --git a/frontend/src/container/NewDashboard/DashboardDescription/index.tsx b/frontend/src/container/NewDashboard/DashboardDescription/index.tsx index 151fba7609..7845cf818e 100644 --- a/frontend/src/container/NewDashboard/DashboardDescription/index.tsx +++ b/frontend/src/container/NewDashboard/DashboardDescription/index.tsx @@ -65,7 +65,7 @@ interface DashboardDescriptionProps { handle: FullScreenHandle; } -function sanitizeDashboardData( +export function sanitizeDashboardData( selectedData: DashboardData, ): Omit { if (!selectedData?.variables) { From b499b103337dc25c8dce41eedf3aa871132d9a3f Mon Sep 17 00:00:00 2001 From: amlannandy Date: Sat, 7 Dec 2024 10:40:14 +0530 Subject: [PATCH 4/8] feat: add unit test --- .../ListOfDashboard/DashboardsList.tsx | 116 +++++++++--------- .../__tests__/DashboardListPage.test.tsx | 25 +++- 2 files changed, 83 insertions(+), 58 deletions(-) diff --git a/frontend/src/container/ListOfDashboard/DashboardsList.tsx b/frontend/src/container/ListOfDashboard/DashboardsList.tsx index 14718a562b..254a12b195 100644 --- a/frontend/src/container/ListOfDashboard/DashboardsList.tsx +++ b/frontend/src/container/ListOfDashboard/DashboardsList.tsx @@ -521,63 +521,65 @@ function DashboardsList(): JSX.Element {
{action && ( - -
- - - -
-
- -
-
- } - placement="bottomRight" - arrow={false} - rootClassName="dashboard-actions" - > - { - e.stopPropagation(); - e.preventDefault(); - }} - /> - +
+ +
+ + + +
+
+ +
+
+ } + placement="bottomRight" + arrow={false} + rootClassName="dashboard-actions" + > + { + e.stopPropagation(); + e.preventDefault(); + }} + /> + + )}
diff --git a/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx b/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx index 98bd40ef62..bcb166eeb0 100644 --- a/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx +++ b/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx @@ -1,7 +1,10 @@ /* eslint-disable sonarjs/no-duplicate-string */ import ROUTES from 'constants/routes'; import DashboardsList from 'container/ListOfDashboard'; -import { dashboardEmptyState } from 'mocks-server/__mockdata__/dashboards'; +import { + dashboardEmptyState, + dashboardSuccessResponse, +} from 'mocks-server/__mockdata__/dashboards'; import { server } from 'mocks-server/server'; import { rest } from 'msw'; import { DashboardProvider } from 'providers/Dashboard/Dashboard'; @@ -204,4 +207,24 @@ describe('dashboard list page', () => { ), ); }); + + it('ensure that the popover actions on each list item renders list of options', async () => { + const { getByText, getAllByTestId } = render( + + + + + , + ); + + await waitFor(() => { + const popovers = getAllByTestId('dashboard-action-popover'); + expect(popovers).toHaveLength(dashboardSuccessResponse.data.length); + fireEvent.click([...popovers[0].children][0]); + }); + + expect(getByText('View')).toBeInTheDocument(); + expect(getByText('Copy Link')).toBeInTheDocument(); + expect(getByText('Export JSON')).toBeInTheDocument(); + }); }); From 1b8213653a833418793fa98c1cc6ac3b77b95df8 Mon Sep 17 00:00:00 2001 From: amlannandy Date: Sat, 7 Dec 2024 11:08:57 +0530 Subject: [PATCH 5/8] feat: update tests --- .../ListOfDashboard/DashboardsList.tsx | 117 +++++++++--------- .../__tests__/DashboardListPage.test.tsx | 2 +- 2 files changed, 59 insertions(+), 60 deletions(-) diff --git a/frontend/src/container/ListOfDashboard/DashboardsList.tsx b/frontend/src/container/ListOfDashboard/DashboardsList.tsx index 254a12b195..760fee457d 100644 --- a/frontend/src/container/ListOfDashboard/DashboardsList.tsx +++ b/frontend/src/container/ListOfDashboard/DashboardsList.tsx @@ -521,65 +521,64 @@ function DashboardsList(): JSX.Element {
{action && ( -
- -
- - - -
-
- -
-
- } - placement="bottomRight" - arrow={false} - rootClassName="dashboard-actions" - > - { - e.stopPropagation(); - e.preventDefault(); - }} - /> - - + +
+ + + +
+
+ +
+ + } + placement="bottomRight" + arrow={false} + rootClassName="dashboard-actions" + > + { + e.stopPropagation(); + e.preventDefault(); + }} + /> +
)}
diff --git a/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx b/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx index bcb166eeb0..0fcdea102b 100644 --- a/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx +++ b/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx @@ -218,7 +218,7 @@ describe('dashboard list page', () => { ); await waitFor(() => { - const popovers = getAllByTestId('dashboard-action-popover'); + const popovers = getAllByTestId('dashboard-action-icon'); expect(popovers).toHaveLength(dashboardSuccessResponse.data.length); fireEvent.click([...popovers[0].children][0]); }); From 2508e6f9f17c77ee460e5d555a459b66d449edb6 Mon Sep 17 00:00:00 2001 From: amlannandy Date: Sat, 7 Dec 2024 11:22:10 +0530 Subject: [PATCH 6/8] feat: update unit test --- .../__tests__/DashboardListPage.test.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx b/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx index 0fcdea102b..e8ab48f9c3 100644 --- a/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx +++ b/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx @@ -1,6 +1,7 @@ /* eslint-disable sonarjs/no-duplicate-string */ import ROUTES from 'constants/routes'; import DashboardsList from 'container/ListOfDashboard'; +import * as dashboardUtils from 'container/NewDashboard/DashboardDescription'; import { dashboardEmptyState, dashboardSuccessResponse, @@ -11,6 +12,10 @@ import { DashboardProvider } from 'providers/Dashboard/Dashboard'; import { MemoryRouter, useLocation } from 'react-router-dom'; import { fireEvent, render, waitFor } from 'tests/test-utils'; +jest.mock('container/NewDashboard/DashboardDescription', () => ({ + sanitizeDashboardData: jest.fn(), +})); + jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useLocation: jest.fn(), @@ -208,7 +213,7 @@ describe('dashboard list page', () => { ); }); - it('ensure that the popover actions on each list item renders list of options', async () => { + it('ensure that the popover action renders list of options and export JSON works correctly', async () => { const { getByText, getAllByTestId } = render( @@ -226,5 +231,8 @@ describe('dashboard list page', () => { expect(getByText('View')).toBeInTheDocument(); expect(getByText('Copy Link')).toBeInTheDocument(); expect(getByText('Export JSON')).toBeInTheDocument(); + + fireEvent.click(getByText('Export JSON')); + expect(dashboardUtils.sanitizeDashboardData).toHaveBeenCalled(); }); }); From d09c4d947eddf74c75b8e3e6dd3bc9fe9e4e11d4 Mon Sep 17 00:00:00 2001 From: amlannandy Date: Sat, 7 Dec 2024 11:24:58 +0530 Subject: [PATCH 7/8] feat: update unit test --- .../__tests__/DashboardListPage.test.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx b/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx index e8ab48f9c3..21cfd2ae65 100644 --- a/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx +++ b/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx @@ -213,7 +213,7 @@ describe('dashboard list page', () => { ); }); - it('ensure that the popover action renders list of options and export JSON works correctly', async () => { + it('ensure that the export JSON popover action works correctly', async () => { const { getByText, getAllByTestId } = render( @@ -228,11 +228,9 @@ describe('dashboard list page', () => { fireEvent.click([...popovers[0].children][0]); }); - expect(getByText('View')).toBeInTheDocument(); - expect(getByText('Copy Link')).toBeInTheDocument(); - expect(getByText('Export JSON')).toBeInTheDocument(); - - fireEvent.click(getByText('Export JSON')); + const exportJsonBtn = getByText('Export JSON'); + expect(exportJsonBtn).toBeInTheDocument(); + fireEvent.click(exportJsonBtn); expect(dashboardUtils.sanitizeDashboardData).toHaveBeenCalled(); }); }); From 8a3319cdf585a0446bf3ea5d1bdde86208e4f8d1 Mon Sep 17 00:00:00 2001 From: amlannandy Date: Tue, 10 Dec 2024 18:17:16 +0530 Subject: [PATCH 8/8] chore: address comments --- .../__tests__/DashboardListPage.test.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx b/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx index 21cfd2ae65..d075316422 100644 --- a/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx +++ b/frontend/src/pages/DashboardsListPage/__tests__/DashboardListPage.test.tsx @@ -214,13 +214,7 @@ describe('dashboard list page', () => { }); it('ensure that the export JSON popover action works correctly', async () => { - const { getByText, getAllByTestId } = render( - - - - - , - ); + const { getByText, getAllByTestId } = render(); await waitFor(() => { const popovers = getAllByTestId('dashboard-action-icon'); @@ -231,6 +225,13 @@ describe('dashboard list page', () => { const exportJsonBtn = getByText('Export JSON'); expect(exportJsonBtn).toBeInTheDocument(); fireEvent.click(exportJsonBtn); - expect(dashboardUtils.sanitizeDashboardData).toHaveBeenCalled(); + const firstDashboardData = dashboardSuccessResponse.data[0]; + expect(dashboardUtils.sanitizeDashboardData).toHaveBeenCalledWith( + expect.objectContaining({ + id: firstDashboardData.uuid, + title: firstDashboardData.data.title, + createdAt: firstDashboardData.created_at, + }), + ); }); });