feat: add the export panel to the traces explorer (#2983)

* feat: add the export panel to the traces explorer

* feat: onExport dashboard widget is updated

* chore: made common hook useDashboard

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
dnazarenkoo 2023-06-28 15:55:20 +03:00 committed by GitHub
parent 9b8f7a091c
commit 1eabacbaf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 181 additions and 30 deletions

View File

@ -12,4 +12,6 @@ export enum QueryParams {
aggregationOption = 'aggregationOption',
entity = 'entity',
resourceAttributes = 'resourceAttribute',
graphType = 'graphType',
widgetId = 'widgetId',
}

View File

@ -1,12 +1,11 @@
import { Button, Typography } from 'antd';
import createDashboard from 'api/dashboard/create';
import getAll from 'api/dashboard/getAll';
import axios from 'axios';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useGetAllDashboard } from 'hooks/dashboard/useGetAllDashboard';
import { useNotifications } from 'hooks/useNotifications';
import { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useMutation, useQuery } from 'react-query';
import { useMutation } from 'react-query';
import { ExportPanelProps } from '.';
import {
@ -18,7 +17,7 @@ import {
} from './styles';
import { getSelectOptions } from './utils';
function ExportPanel({ onExport }: ExportPanelProps): JSX.Element {
function ExportPanel({ isLoading, onExport }: ExportPanelProps): JSX.Element {
const { notifications } = useNotifications();
const { t } = useTranslation(['dashboard']);
@ -26,16 +25,18 @@ function ExportPanel({ onExport }: ExportPanelProps): JSX.Element {
null,
);
const { data, isLoading, refetch } = useQuery({
queryFn: getAll,
queryKey: REACT_QUERY_KEY.GET_ALL_DASHBOARDS,
});
const {
data,
isLoading: isAllDashboardsLoading,
refetch,
} = useGetAllDashboard();
const {
mutate: createNewDashboard,
isLoading: createDashboardLoading,
} = useMutation(createDashboard, {
onSuccess: () => {
onSuccess: (data) => {
onExport(data?.payload || null);
refetch();
},
onError: (error) => {
@ -73,6 +74,14 @@ function ExportPanel({ onExport }: ExportPanelProps): JSX.Element {
});
}, [t, createNewDashboard]);
const isDashboardLoading = isAllDashboardsLoading || createDashboardLoading;
const isDisabled =
isAllDashboardsLoading ||
!options?.length ||
!selectedDashboardId ||
isLoading;
return (
<Wrapper direction="vertical">
<Title>Export Panel</Title>
@ -81,14 +90,15 @@ function ExportPanel({ onExport }: ExportPanelProps): JSX.Element {
<DashboardSelect
placeholder="Select Dashboard"
options={options}
loading={isLoading || createDashboardLoading}
disabled={isLoading || createDashboardLoading}
loading={isDashboardLoading}
disabled={isDashboardLoading}
value={selectedDashboardId}
onSelect={handleSelect}
/>
<Button
type="primary"
disabled={isLoading || !options?.length || !selectedDashboardId}
loading={isLoading}
disabled={isDisabled}
onClick={handleExportClick}
>
Export

View File

@ -5,7 +5,7 @@ import { Dashboard } from 'types/api/dashboard/getAll';
import { MENU_KEY, MENU_LABEL } from './config';
import ExportPanelContainer from './ExportPanel';
function ExportPanel({ onExport }: ExportPanelProps): JSX.Element {
function ExportPanel({ isLoading, onExport }: ExportPanelProps): JSX.Element {
const [isExport, setIsExport] = useState<boolean>(false);
const onModalToggle = useCallback((value: boolean) => {
@ -48,22 +48,28 @@ function ExportPanel({ onExport }: ExportPanelProps): JSX.Element {
<Button>Actions</Button>
</Dropdown>
<Modal
footer={null}
onOk={onCancel(false)}
onCancel={onCancel(false)}
open={isExport}
centered
>
<ExportPanelContainer onExport={onExport} />
<ExportPanelContainer isLoading={isLoading} onExport={onExport} />
</Modal>
</>
);
}
ExportPanel.defaultProps = {
isLoading: false,
};
interface OnClickProps {
key: string;
}
export interface ExportPanelProps {
isLoading?: boolean;
onExport: (dashboard: Dashboard | null) => void;
}

View File

@ -0,0 +1,16 @@
import getAll from 'api/dashboard/getAll';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useQuery, UseQueryResult } from 'react-query';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/dashboard/getAll';
export const useGetAllDashboard = (): DashboardProps =>
useQuery({
queryFn: getAll,
queryKey: REACT_QUERY_KEY.GET_ALL_DASHBOARDS,
});
type DashboardProps = UseQueryResult<
SuccessResponse<PayloadProps> | ErrorResponse,
unknown
>;

View File

@ -0,0 +1,14 @@
import update from 'api/dashboard/update';
import { useMutation, UseMutationResult } from 'react-query';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { Dashboard } from 'types/api/dashboard/getAll';
import { Props } from 'types/api/dashboard/update';
export const useUpdateDashboard = (): UseUpdateDashboard => useMutation(update);
type UseUpdateDashboard = UseMutationResult<
SuccessResponse<Dashboard> | ErrorResponse,
unknown,
Props,
unknown
>;

View File

@ -0,0 +1,37 @@
import { PANEL_TYPES } from 'constants/queryBuilder';
import { Dashboard } from 'types/api/dashboard/getAll';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
export const addEmptyWidgetInDashboardJSONWithQuery = (
dashboard: Dashboard,
query: Query,
): Dashboard => ({
...dashboard,
data: {
...dashboard.data,
layout: [
{
i: 'empty',
w: 6,
x: 0,
h: 2,
y: 0,
},
...(dashboard?.data?.layout || []),
],
widgets: [
...(dashboard?.data?.widgets || []),
{
id: 'empty',
query,
description: '',
isStacked: false,
nullZeroValues: '',
opacity: '',
title: '',
timePreferance: 'GLOBAL_TIME',
panelTypes: PANEL_TYPES.TIME_SERIES,
},
],
},
});

View File

@ -1,28 +1,95 @@
import { Tabs } from 'antd';
import axios from 'axios';
import { QueryParams } from 'constants/query';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { PANEL_TYPES_QUERY } from 'constants/queryBuilderQueryNames';
import {
COMPOSITE_QUERY,
PANEL_TYPES_QUERY,
} from 'constants/queryBuilderQueryNames';
import ROUTES from 'constants/routes';
import ExportPanel from 'container/ExportPanel';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import QuerySection from 'container/TracesExplorer/QuerySection';
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
import { addEmptyWidgetInDashboardJSONWithQuery } from 'hooks/dashboard/utils';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
import { useNotifications } from 'hooks/useNotifications';
import history from 'lib/history';
import { useCallback, useMemo } from 'react';
import { generatePath } from 'react-router-dom';
import { Dashboard } from 'types/api/dashboard/getAll';
import { DataSource } from 'types/common/queryBuilder';
import { Container } from './styles';
import { ActionsWrapper, Container } from './styles';
import { getTabsItems } from './utils';
function TracesExplorer(): JSX.Element {
const { notifications } = useNotifications();
const {
currentQuery,
stagedQuery,
panelType,
updateAllQueriesOperators,
redirectWithQueryBuilderData,
currentQuery,
panelType,
} = useQueryBuilder();
const tabsItems = getTabsItems();
const currentTab = panelType || PANEL_TYPES.TIME_SERIES;
const defaultQuery = useMemo(
() =>
updateAllQueriesOperators(
initialQueriesMap.traces,
PANEL_TYPES.TIME_SERIES,
DataSource.TRACES,
),
[updateAllQueriesOperators],
);
const exportDefaultQuery = useMemo(
() =>
updateAllQueriesOperators(
stagedQuery || initialQueriesMap.traces,
PANEL_TYPES.TIME_SERIES,
DataSource.TRACES,
),
[stagedQuery, updateAllQueriesOperators],
);
const { mutate: updateDashboard, isLoading } = useUpdateDashboard();
const handleExport = useCallback(
(dashboard: Dashboard | null): void => {
if (!dashboard) return;
const updatedDashboard = addEmptyWidgetInDashboardJSONWithQuery(
dashboard,
exportDefaultQuery,
);
updateDashboard(updatedDashboard, {
onSuccess: (data) => {
const dashboardEditView = `${generatePath(ROUTES.DASHBOARD, {
dashboardId: data?.payload?.uuid,
})}/new?${QueryParams.graphType}=graph&${
QueryParams.widgetId
}=empty&${COMPOSITE_QUERY}=${JSON.stringify(exportDefaultQuery)}`;
history.push(dashboardEditView);
},
onError: (error) => {
if (axios.isAxiosError(error)) {
notifications.error({
message: error.message,
});
}
},
});
},
[exportDefaultQuery, notifications, updateDashboard],
);
const handleTabChange = useCallback(
(newPanelType: string): void => {
if (panelType === newPanelType) return;
@ -43,23 +110,17 @@ function TracesExplorer(): JSX.Element {
],
);
const defaultValue = useMemo(
() =>
updateAllQueriesOperators(
initialQueriesMap.traces,
PANEL_TYPES.TIME_SERIES,
DataSource.TRACES,
),
[updateAllQueriesOperators],
);
useShareBuilderUrl(defaultValue);
useShareBuilderUrl(defaultQuery);
return (
<>
<QuerySection />
<Container>
<ActionsWrapper>
<ExportPanel isLoading={isLoading} onExport={handleExport} />
</ActionsWrapper>
<Tabs
defaultActiveKey={currentTab}
activeKey={currentTab}

View File

@ -3,3 +3,8 @@ import styled from 'styled-components';
export const Container = styled.div`
margin: 1rem 0;
`;
export const ActionsWrapper = styled.div`
display: flex;
justify-content: flex-end;
`;