mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 14:35:56 +08:00
feat: add functionality to export dashboard as json from listing page
This commit is contained in:
commit
9a1cd65b73
@ -27,6 +27,8 @@ import { AxiosError } from 'axios';
|
|||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||||
import ROUTES from 'constants/routes';
|
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 { Base64Icons } from 'container/NewDashboard/DashboardSettings/General/utils';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useGetAllDashboard } from 'hooks/dashboard/useGetAllDashboard';
|
import { useGetAllDashboard } from 'hooks/dashboard/useGetAllDashboard';
|
||||||
@ -44,6 +46,7 @@ import {
|
|||||||
EllipsisVertical,
|
EllipsisVertical,
|
||||||
Expand,
|
Expand,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
|
FileJson,
|
||||||
Github,
|
Github,
|
||||||
HdmiPort,
|
HdmiPort,
|
||||||
LayoutGrid,
|
LayoutGrid,
|
||||||
@ -67,12 +70,18 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import { Layout } from 'react-grid-layout';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { generatePath, Link } from 'react-router-dom';
|
import { generatePath, Link } from 'react-router-dom';
|
||||||
import { useCopyToClipboard } from 'react-use';
|
import { useCopyToClipboard } from 'react-use';
|
||||||
import { AppState } from 'store/reducers';
|
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 AppReducer from 'types/reducer/app';
|
||||||
import { isCloudUser } from 'utils/app';
|
import { isCloudUser } from 'utils/app';
|
||||||
|
|
||||||
@ -261,6 +270,11 @@ function DashboardsList(): JSX.Element {
|
|||||||
isLocked: !!e.isLocked || false,
|
isLocked: !!e.isLocked || false,
|
||||||
lastUpdatedBy: e.updated_by,
|
lastUpdatedBy: e.updated_by,
|
||||||
image: e.data.image || Base64Icons[0],
|
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,
|
refetchDashboardList,
|
||||||
})) || [];
|
})) || [];
|
||||||
|
|
||||||
@ -413,6 +427,15 @@ function DashboardsList(): JSX.Element {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleJsonExport = (event: React.MouseEvent<HTMLElement>): void => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
downloadObjectAsJson(
|
||||||
|
sanitizeDashboardData({ ...dashboard, title: dashboard.name }),
|
||||||
|
dashboard.name,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dashboard-list-item" onClick={onClickHandler}>
|
<div className="dashboard-list-item" onClick={onClickHandler}>
|
||||||
<div className="title-with-action">
|
<div className="title-with-action">
|
||||||
@ -486,6 +509,14 @@ function DashboardsList(): JSX.Element {
|
|||||||
>
|
>
|
||||||
Copy Link
|
Copy Link
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
className="action-btn"
|
||||||
|
icon={<FileJson size={12} />}
|
||||||
|
onClick={handleJsonExport}
|
||||||
|
>
|
||||||
|
Export JSON
|
||||||
|
</Button>
|
||||||
</section>
|
</section>
|
||||||
<section className="section-2">
|
<section className="section-2">
|
||||||
<DeleteButton
|
<DeleteButton
|
||||||
@ -504,6 +535,7 @@ function DashboardsList(): JSX.Element {
|
|||||||
<EllipsisVertical
|
<EllipsisVertical
|
||||||
className="dashboard-action-icon"
|
className="dashboard-action-icon"
|
||||||
size={14}
|
size={14}
|
||||||
|
data-testid="dashboard-action-icon"
|
||||||
onClick={(e): void => {
|
onClick={(e): void => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -1068,6 +1100,11 @@ export interface Data {
|
|||||||
isLocked: boolean;
|
isLocked: boolean;
|
||||||
id: string;
|
id: string;
|
||||||
image?: string;
|
image?: string;
|
||||||
|
widgets?: Array<WidgetRow | Widgets>;
|
||||||
|
layout?: Layout[];
|
||||||
|
panelMap?: Record<string, { widgets: Layout[]; collapsed: boolean }>;
|
||||||
|
variables: Record<string, IDashboardVariable>;
|
||||||
|
version?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DashboardsList;
|
export default DashboardsList;
|
||||||
|
@ -65,7 +65,7 @@ interface DashboardDescriptionProps {
|
|||||||
handle: FullScreenHandle;
|
handle: FullScreenHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sanitizeDashboardData(
|
export function sanitizeDashboardData(
|
||||||
selectedData: DashboardData,
|
selectedData: DashboardData,
|
||||||
): Omit<DashboardData, 'uuid'> {
|
): Omit<DashboardData, 'uuid'> {
|
||||||
if (!selectedData?.variables) {
|
if (!selectedData?.variables) {
|
||||||
|
@ -1,13 +1,21 @@
|
|||||||
/* eslint-disable sonarjs/no-duplicate-string */
|
/* eslint-disable sonarjs/no-duplicate-string */
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import DashboardsList from 'container/ListOfDashboard';
|
import DashboardsList from 'container/ListOfDashboard';
|
||||||
import { dashboardEmptyState } from 'mocks-server/__mockdata__/dashboards';
|
import * as dashboardUtils from 'container/NewDashboard/DashboardDescription';
|
||||||
|
import {
|
||||||
|
dashboardEmptyState,
|
||||||
|
dashboardSuccessResponse,
|
||||||
|
} from 'mocks-server/__mockdata__/dashboards';
|
||||||
import { server } from 'mocks-server/server';
|
import { server } from 'mocks-server/server';
|
||||||
import { rest } from 'msw';
|
import { rest } from 'msw';
|
||||||
import { DashboardProvider } from 'providers/Dashboard/Dashboard';
|
import { DashboardProvider } from 'providers/Dashboard/Dashboard';
|
||||||
import { MemoryRouter, useLocation } from 'react-router-dom';
|
import { MemoryRouter, useLocation } from 'react-router-dom';
|
||||||
import { fireEvent, render, waitFor } from 'tests/test-utils';
|
import { fireEvent, render, waitFor } from 'tests/test-utils';
|
||||||
|
|
||||||
|
jest.mock('container/NewDashboard/DashboardDescription', () => ({
|
||||||
|
sanitizeDashboardData: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => ({
|
jest.mock('react-router-dom', () => ({
|
||||||
...jest.requireActual('react-router-dom'),
|
...jest.requireActual('react-router-dom'),
|
||||||
useLocation: jest.fn(),
|
useLocation: jest.fn(),
|
||||||
@ -204,4 +212,26 @@ describe('dashboard list page', () => {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('ensure that the export JSON popover action works correctly', async () => {
|
||||||
|
const { getByText, getAllByTestId } = render(<DashboardsList />);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
const popovers = getAllByTestId('dashboard-action-icon');
|
||||||
|
expect(popovers).toHaveLength(dashboardSuccessResponse.data.length);
|
||||||
|
fireEvent.click([...popovers[0].children][0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
const exportJsonBtn = getByText('Export JSON');
|
||||||
|
expect(exportJsonBtn).toBeInTheDocument();
|
||||||
|
fireEvent.click(exportJsonBtn);
|
||||||
|
const firstDashboardData = dashboardSuccessResponse.data[0];
|
||||||
|
expect(dashboardUtils.sanitizeDashboardData).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: firstDashboardData.uuid,
|
||||||
|
title: firstDashboardData.data.title,
|
||||||
|
createdAt: firstDashboardData.created_at,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user