refactor: query data field for widgets (#2839)

* refactor: query data field for widgets

* fix: query key index

* fix: remove queryData fields

* fix: remove rest queryData field

* fix: remove queryData from services

* fix: remove queryData in another places

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
Yevhen Shevchenko 2023-06-07 15:27:33 +03:00 committed by GitHub
parent ef1bc0beec
commit 1770e6a157
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 248 additions and 474 deletions

View File

@ -1,3 +1,4 @@
export const REACT_QUERY_KEY = {
GET_ALL_LICENCES: 'GET_ALL_LICENCES',
GET_QUERY_RANGE: 'GET_QUERY_RANGE',
};

View File

@ -6,11 +6,10 @@ import GridGraphComponent from 'container/GridGraphComponent';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
import { Time } from 'container/TopNav/DateTimeSelection/config';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import getChartData from 'lib/getChartData';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery } from 'react-query';
import { GetMetricQueryRange } from 'store/actions/dashboard/getQueryResults';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
@ -26,9 +25,6 @@ export interface ChartPreviewProps {
threshold?: number | undefined;
userQueryKey?: string;
}
interface QueryResponseError {
message?: string;
}
function ChartPreview({
name,
@ -76,39 +72,38 @@ function ChartPreview({
}
}, [query]);
const queryResponse = useQuery({
queryKey: [
'chartPreview',
userQueryKey || JSON.stringify(query),
selectedInterval,
],
queryFn: () =>
GetMetricQueryRange({
query: query || {
queryType: EQueryType.QUERY_BUILDER,
promql: [],
builder: {
queryFormulas: [],
queryData: [],
},
clickhouse_sql: [],
const queryResponse = useGetQueryRange(
{
query: query || {
queryType: EQueryType.QUERY_BUILDER,
promql: [],
builder: {
queryFormulas: [],
queryData: [],
},
globalSelectedInterval: selectedInterval,
graphType,
selectedTime,
}),
retry: false,
enabled: canQuery,
});
clickhouse_sql: [],
},
globalSelectedInterval: selectedInterval,
graphType,
selectedTime,
},
{
queryKey: [
'chartPreview',
userQueryKey || JSON.stringify(query),
selectedInterval,
],
retry: false,
enabled: canQuery,
},
);
const chartDataSet = queryResponse.isError
? null
: getChartData({
queryData: [
{
queryData: queryResponse?.data?.payload?.data?.result
? queryResponse?.data?.payload?.data?.result
: [],
queryData: queryResponse?.data?.payload?.data?.result ?? [],
},
],
});
@ -119,8 +114,7 @@ function ChartPreview({
{(queryResponse?.isError || queryResponse?.error) && (
<FailedMessageContainer color="red" title="Failed to refresh the chart">
<InfoCircleOutlined />{' '}
{(queryResponse?.error as QueryResponseError).message ||
t('preview_chart_unexpected_error')}
{queryResponse.error.message || t('preview_chart_unexpected_error')}
</FailedMessageContainer>
)}
{queryResponse.isLoading && <Spinner size="large" tip="Loading..." />}

View File

@ -7,16 +7,13 @@ import {
timeItems,
timePreferance,
} from 'container/NewWidget/RightContainer/timeItems';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
import getChartData from 'lib/getChartData';
import { useCallback, useMemo, useState } from 'react';
import { useQuery } from 'react-query';
import { useSelector } from 'react-redux';
import { GetMetricQueryRange } from 'store/actions/dashboard/getQueryResults';
import { AppState } from 'store/reducers';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { Widgets } from 'types/api/dashboard/getAll';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { GlobalReducer } from 'types/reducer/globalTime';
import { TimeContainer } from './styles';
@ -44,18 +41,24 @@ function FullView({
name: getSelectedTime()?.name || '',
enum: widget?.timePreferance || 'GLOBAL_TIME',
});
const response = useQuery<
SuccessResponse<MetricRangePayloadProps> | ErrorResponse
>(
`FullViewGetMetricsQueryRange-${selectedTime.enum}-${globalSelectedTime}-${widget.id}`,
const queryKey = useMemo(
() =>
GetMetricQueryRange({
selectedTime: selectedTime.enum,
graphType: widget.panelTypes,
query: widget.query,
globalSelectedInterval: globalSelectedTime,
variables: getDashboardVariables(),
}),
`FullViewGetMetricsQueryRange-${selectedTime.enum}-${globalSelectedTime}-${widget.id}`,
[selectedTime, globalSelectedTime, widget],
);
const response = useGetQueryRange(
{
selectedTime: selectedTime.enum,
graphType: widget.panelTypes,
query: widget.query,
globalSelectedInterval: globalSelectedTime,
variables: getDashboardVariables(),
},
{
queryKey,
},
);
const chartDataSet = useMemo(

View File

@ -3,6 +3,7 @@ import { ChartData } from 'chart.js';
import Spinner from 'components/Spinner';
import GridGraphComponent from 'container/GridGraphComponent';
import { UpdateDashboard } from 'container/GridGraphLayout/utils';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import { useNotifications } from 'hooks/useNotifications';
import usePreviousValue from 'hooks/usePreviousValue';
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
@ -20,7 +21,6 @@ import {
import { Layout } from 'react-grid-layout';
import { useTranslation } from 'react-i18next';
import { useInView } from 'react-intersection-observer';
import { useQuery } from 'react-query';
import { connect, useSelector } from 'react-redux';
import { bindActionCreators } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
@ -28,7 +28,6 @@ import {
DeleteWidget,
DeleteWidgetProps,
} from 'store/actions/dashboard/deleteWidget';
import { GetMetricQueryRange } from 'store/actions/dashboard/getQueryResults';
import { AppState } from 'store/reducers';
import AppActions from 'types/actions';
import { Widgets } from 'types/api/dashboard/getAll';
@ -81,33 +80,28 @@ function GridCardGraph({
const selectedData = selectedDashboard?.data;
const { variables } = selectedData;
const queryResponse = useQuery(
[
`GetMetricsQueryRange-${widget?.timePreferance}-${globalSelectedInterval}-${widget.id}`,
{
const queryResponse = useGetQueryRange(
{
selectedTime: widget?.timePreferance,
graphType: widget.panelTypes,
query: widget.query,
globalSelectedInterval,
variables: getDashboardVariables(),
},
{
queryKey: [
`GetMetricsQueryRange-${widget?.timePreferance}-${globalSelectedInterval}-${widget.id}`,
widget,
maxTime,
minTime,
globalSelectedInterval,
variables,
},
],
() =>
GetMetricQueryRange({
selectedTime: widget?.timePreferance,
graphType: widget.panelTypes,
query: widget.query,
globalSelectedInterval,
variables: getDashboardVariables(),
}),
{
],
keepPreviousData: true,
enabled: isGraphVisible,
refetchOnMount: false,
onError: (error) => {
if (error instanceof Error) {
setErrorMessage(error.message);
}
setErrorMessage(error.message);
},
},
);

View File

@ -50,14 +50,6 @@ export const UpdateDashboard = async (
queryData: [initialQueryBuilderFormValues],
},
},
queryData: {
data: {
queryData: widgetData?.queryData.data.queryData || [],
},
error: false,
errorMessage: '',
loading: false,
},
timePreferance: widgetData?.timePreferance || 'GLOBAL_TIME',
title: widgetData ? copyTitle : '',
},

View File

@ -71,23 +71,8 @@ function ImportJSON({
setDashboardCreating(true);
const dashboardData = JSON.parse(editorValue) as DashboardData;
// removing the queryData
const parsedWidgets: DashboardData = {
...dashboardData,
widgets: dashboardData.widgets?.map((e) => ({
...e,
queryData: {
...e.queryData,
data: e.queryData.data,
error: false,
errorMessage: '',
loading: false,
},
})),
};
const response = await createDashboard({
...parsedWidgets,
...dashboardData,
uploadedGrafana,
});

View File

@ -10,12 +10,6 @@ export const getWidgetQueryBuilder = (query: Widgets['query']): Widgets => ({
opacity: '0',
panelTypes: PANEL_TYPES.TIME_SERIES,
query,
queryData: {
data: { queryData: [] },
error: false,
errorMessage: '',
loading: false,
},
timePreferance: 'GLOBAL_TIME',
title: '',
});

View File

@ -6,28 +6,14 @@ import { useTranslation } from 'react-i18next';
import { useCopyToClipboard } from 'react-use';
import { DashboardData } from 'types/api/dashboard/getAll';
import { cleardQueryData, downloadObjectAsJson } from './util';
import { downloadObjectAsJson } from './util';
function ShareModal({
isJSONModalVisible,
onToggleHandler,
selectedData,
}: ShareModalProps): JSX.Element {
const getParsedValue = (): string => {
const updatedData: DashboardData = {
...selectedData,
widgets: selectedData.widgets?.map((widget) => ({
...widget,
queryData: {
...widget.queryData,
loading: false,
error: false,
errorMessage: '',
},
})),
};
return JSON.stringify(updatedData, null, 2);
};
const getParsedValue = (): string => JSON.stringify(selectedData, null, 2);
const [jsonValue, setJSONValue] = useState<string>(getParsedValue());
const [isViewJSON, setIsViewJSON] = useState<boolean>(false);
@ -53,7 +39,6 @@ function ShareModal({
}
}, [state.error, state.value, t, notifications]);
const selectedDataCleaned = cleardQueryData(selectedData);
const GetFooterComponent = useMemo(() => {
if (!isViewJSON) {
return (
@ -69,7 +54,7 @@ function ShareModal({
<Button
type="primary"
onClick={(): void => {
downloadObjectAsJson(selectedDataCleaned, selectedData.title);
downloadObjectAsJson(selectedData, selectedData.title);
}}
>
{t('download_json')}
@ -82,7 +67,7 @@ function ShareModal({
{t('copy_to_clipboard')}
</Button>
);
}, [isViewJSON, jsonValue, selectedData, selectedDataCleaned, setCopy, t]);
}, [isViewJSON, jsonValue, selectedData, setCopy, t]);
return (
<Modal

View File

@ -1,5 +1,3 @@
import { DashboardData } from 'types/api/dashboard/getAll';
export function downloadObjectAsJson(
exportObj: unknown,
exportName: string,
@ -14,18 +12,3 @@ export function downloadObjectAsJson(
downloadAnchorNode.click();
downloadAnchorNode.remove();
}
export function cleardQueryData(param: DashboardData): DashboardData {
return {
...param,
widgets: param.widgets?.map((widget) => ({
...widget,
queryData: {
...widget.queryData,
data: {
queryData: [],
},
},
})),
};
}

View File

@ -1,11 +1,13 @@
import { Button, Tabs, Typography } from 'antd';
import TextToolTip from 'components/TextToolTip';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import { WidgetGraphProps } from 'container/NewWidget/types';
import { QueryBuilder } from 'container/QueryBuilder';
import { useGetWidgetQueryRange } from 'hooks/queryBuilder/useGetWidgetQueryRange';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
import useUrlQuery from 'hooks/useUrlQuery';
import { useCallback, useEffect, useState } from 'react';
import { useCallback } from 'react';
import { connect, useSelector } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
@ -23,16 +25,22 @@ import DashboardReducer from 'types/reducer/dashboards';
import ClickHouseQueryContainer from './QueryBuilder/clickHouse';
import PromQLQueryContainer from './QueryBuilder/promQL';
function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
function QuerySection({
updateQuery,
selectedGraph,
selectedTime,
}: QueryProps): JSX.Element {
const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder();
const urlQuery = useUrlQuery();
const [isInit, setIsInit] = useState<boolean>(false);
const { dashboards } = useSelector<AppState, DashboardReducer>(
(state) => state.dashboards,
);
const { dashboards, isLoadingQueryResult } = useSelector<
AppState,
DashboardReducer
>((state) => state.dashboards);
const getWidgetQueryRange = useGetWidgetQueryRange({
graphType: selectedGraph,
selectedTime: selectedTime.enum,
});
const [selectedDashboards] = dashboards;
const { widgets } = selectedDashboards.data;
@ -46,23 +54,11 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
const { query } = selectedWidget;
const { compositeQuery } = useShareBuilderUrl({ defaultValue: query });
useEffect(() => {
if (!isInit && compositeQuery) {
setIsInit(true);
updateQuery({
updatedQuery: compositeQuery,
widgetId: urlQuery.get('widgetId') || '',
yAxisUnit: selectedWidget.yAxisUnit,
});
}
}, [isInit, compositeQuery, selectedWidget, urlQuery, updateQuery]);
useShareBuilderUrl({ defaultValue: query });
const handleStageQuery = useCallback(
(updatedQuery: Query): void => {
updateQuery({
updatedQuery,
widgetId: urlQuery.get('widgetId') || '',
yAxisUnit: selectedWidget.yAxisUnit,
});
@ -115,7 +111,7 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
<span style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
<TextToolTip text="This will temporarily save the current query and graph state. This will persist across tab change" />
<Button
loading={isLoadingQueryResult}
loading={getWidgetQueryRange.isFetching}
type="primary"
onClick={handleRunQuery}
>
@ -142,6 +138,7 @@ const mapDispatchToProps = (
interface QueryProps extends DispatchProps {
selectedGraph: GRAPH_TYPES;
selectedTime: WidgetGraphProps['selectedTime'];
}
export default connect(null, mapDispatchToProps)(QuerySection);

View File

@ -1,6 +1,8 @@
import { Card, Typography } from 'antd';
import Spinner from 'components/Spinner';
import GridGraphComponent from 'container/GridGraphComponent';
import { NewWidgetProps } from 'container/NewWidget';
import { WidgetGraphProps } from 'container/NewWidget/types';
import { useGetWidgetQueryRange } from 'hooks/queryBuilder/useGetWidgetQueryRange';
import getChartData from 'lib/getChartData';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
@ -12,6 +14,7 @@ import { NotFoundContainer } from './styles';
function WidgetGraph({
selectedGraph,
yAxisUnit,
selectedTime,
}: WidgetGraphProps): JSX.Element {
const { dashboards } = useSelector<AppState, DashboardReducer>(
(state) => state.dashboards,
@ -27,20 +30,28 @@ function WidgetGraph({
const selectedWidget = widgets.find((e) => e.id === widgetId);
const getWidgetQueryRange = useGetWidgetQueryRange({
graphType: selectedGraph,
selectedTime: selectedTime.enum,
});
if (selectedWidget === undefined) {
return <Card>Invalid widget</Card>;
}
const { queryData, title, opacity, isStacked } = selectedWidget;
const { title, opacity, isStacked } = selectedWidget;
if (queryData.error) {
if (getWidgetQueryRange.error) {
return (
<NotFoundContainer>
<Typography>{queryData.errorMessage}</Typography>
<Typography>{getWidgetQueryRange.error.message}</Typography>
</NotFoundContainer>
);
}
if (queryData.data.queryData.length === 0) {
if (getWidgetQueryRange.isLoading) {
return <Spinner size="large" tip="Loading..." />;
}
if (getWidgetQueryRange.data?.payload.data.result.length === 0) {
return (
<NotFoundContainer>
<Typography>No Data</Typography>
@ -49,7 +60,9 @@ function WidgetGraph({
}
const chartDataSet = getChartData({
queryData: [queryData.data],
queryData: [
{ queryData: getWidgetQueryRange.data?.payload.data.result ?? [] },
],
});
return (
@ -65,6 +78,4 @@ function WidgetGraph({
);
}
type WidgetGraphProps = NewWidgetProps;
export default WidgetGraph;

View File

@ -1,24 +1,28 @@
import { InfoCircleOutlined } from '@ant-design/icons';
import { Typography } from 'antd';
import { Card } from 'container/GridGraphLayout/styles';
import { useGetWidgetQueryRange } from 'hooks/queryBuilder/useGetWidgetQueryRange';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { memo } from 'react';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { AppState } from 'store/reducers';
import DashboardReducer from 'types/reducer/dashboards';
import { NewWidgetProps } from '../../index';
import { WidgetGraphProps } from '../../types';
import PlotTag from './PlotTag';
import { AlertIconContainer, Container, NotFoundContainer } from './styles';
import { AlertIconContainer, Container } from './styles';
import WidgetGraphComponent from './WidgetGraph';
function WidgetGraph({
selectedGraph,
yAxisUnit,
selectedTime,
}: WidgetGraphProps): JSX.Element {
const { dashboards, isQueryFired } = useSelector<AppState, DashboardReducer>(
const { currentQuery } = useQueryBuilder();
const { dashboards } = useSelector<AppState, DashboardReducer>(
(state) => state.dashboards,
);
const [selectedDashboard] = dashboards;
const { search } = useLocation();
@ -31,33 +35,31 @@ function WidgetGraph({
const selectedWidget = widgets.find((e) => e.id === widgetId);
const getWidgetQueryRange = useGetWidgetQueryRange({
graphType: selectedGraph,
selectedTime: selectedTime.enum,
});
if (selectedWidget === undefined) {
return <Card>Invalid widget</Card>;
}
const { queryData } = selectedWidget;
return (
<Container>
<PlotTag queryType={selectedWidget.query.queryType} />
{queryData.error && (
<AlertIconContainer color="red" title={queryData.errorMessage}>
<PlotTag queryType={currentQuery.queryType} />
{getWidgetQueryRange.error && (
<AlertIconContainer color="red" title={getWidgetQueryRange.error.message}>
<InfoCircleOutlined />
</AlertIconContainer>
)}
{!isQueryFired && (
<NotFoundContainer>
<Typography>No Data</Typography>
</NotFoundContainer>
)}
{isQueryFired && (
<WidgetGraphComponent selectedGraph={selectedGraph} yAxisUnit={yAxisUnit} />
)}
<WidgetGraphComponent
selectedTime={selectedTime}
selectedGraph={selectedGraph}
yAxisUnit={yAxisUnit}
/>
</Container>
);
}
type WidgetGraphProps = NewWidgetProps;
export default memo(WidgetGraph);

View File

@ -1,6 +1,6 @@
import { memo } from 'react';
import { NewWidgetProps } from '../index';
import { WidgetGraphProps } from '../types';
import QuerySection from './QuerySection';
import { QueryContainer } from './styles';
import WidgetGraph from './WidgetGraph';
@ -8,12 +8,17 @@ import WidgetGraph from './WidgetGraph';
function LeftContainer({
selectedGraph,
yAxisUnit,
}: NewWidgetProps): JSX.Element {
selectedTime,
}: WidgetGraphProps): JSX.Element {
return (
<>
<WidgetGraph selectedGraph={selectedGraph} yAxisUnit={yAxisUnit} />
<WidgetGraph
selectedTime={selectedTime}
selectedGraph={selectedGraph}
yAxisUnit={yAxisUnit}
/>
<QueryContainer>
<QuerySection selectedGraph={selectedGraph} />
<QuerySection selectedTime={selectedTime} selectedGraph={selectedGraph} />
</QueryContainer>
</>
);

View File

@ -1,25 +1,18 @@
import { LockFilled } from '@ant-design/icons';
import { Button, Modal, Tooltip, Typography } from 'antd';
import { FeatureKeys } from 'constants/features';
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
import ROUTES from 'constants/routes';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import { ITEMS } from 'container/NewDashboard/ComponentsSlider/menuItems';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
import { useNotifications } from 'hooks/useNotifications';
import useUrlQuery from 'hooks/useUrlQuery';
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
import history from 'lib/history';
import { DashboardWidgetPageParams } from 'pages/DashboardWidget';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { connect, useDispatch, useSelector } from 'react-redux';
import { generatePath, useLocation, useParams } from 'react-router-dom';
import { bindActionCreators, Dispatch } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
import {
GetQueryResults,
GetQueryResultsProps,
} from 'store/actions/dashboard/getQueryResults';
import {
SaveDashboard,
SaveDashboardProps,
@ -27,10 +20,8 @@ import {
import { AppState } from 'store/reducers';
import AppActions from 'types/actions';
import { FLUSH_DASHBOARD } from 'types/actions/dashboard';
import { Widgets } from 'types/api/dashboard/getAll';
import AppReducer from 'types/reducer/app';
import DashboardReducer from 'types/reducer/dashboards';
import { GlobalReducer } from 'types/reducer/globalTime';
import LeftContainer from './LeftContainer';
import QueryTypeTag from './LeftContainer/QueryTypeTag';
@ -43,21 +34,15 @@ import {
PanelContainer,
RightContainerWrapper,
} from './styles';
import { NewWidgetProps } from './types';
function NewWidget({
selectedGraph,
saveSettingOfPanel,
getQueryResults,
}: Props): JSX.Element {
const urlQuery = useUrlQuery();
function NewWidget({ selectedGraph, saveSettingOfPanel }: Props): JSX.Element {
const dispatch = useDispatch();
const { dashboards } = useSelector<AppState, DashboardReducer>(
(state) => state.dashboards,
);
const { selectedTime: globalSelectedInterval } = useSelector<
AppState,
GlobalReducer
>((state) => state.globalTime);
const { currentQuery } = useQueryBuilder();
const { featureResponse } = useSelector<AppState, AppReducer>(
(state) => state.app,
@ -161,27 +146,6 @@ function NewWidget({
history.push(generatePath(ROUTES.DASHBOARD, { dashboardId }));
}, [dashboardId, dispatch]);
const getQueryResult = useCallback(() => {
const compositeQuery = urlQuery.get(COMPOSITE_QUERY);
if ((selectedWidget?.id.length !== 0 && compositeQuery) || compositeQuery) {
getQueryResults({
query: JSON.parse(compositeQuery),
selectedTime: selectedTime.enum,
widgetId: selectedWidget?.id || '',
graphType,
globalSelectedInterval,
variables: getDashboardVariables(),
});
}
}, [
selectedTime.enum,
selectedWidget?.id,
getQueryResults,
globalSelectedInterval,
graphType,
urlQuery,
]);
const setGraphHandler = (type: ITEMS): void => {
const params = new URLSearchParams(search);
params.set('graphType', type);
@ -189,10 +153,6 @@ function NewWidget({
setGraphType(type);
};
useEffect(() => {
getQueryResult();
}, [getQueryResult]);
const onSaveDashboard = useCallback((): void => {
setSaveModal(true);
}, []);
@ -231,7 +191,11 @@ function NewWidget({
<PanelContainer>
<LeftContainerWrapper flex={5}>
<LeftContainer selectedGraph={graphType} yAxisUnit={yAxisUnit} />
<LeftContainer
selectedTime={selectedTime}
selectedGraph={graphType}
yAxisUnit={yAxisUnit}
/>
</LeftContainerWrapper>
<RightContainerWrapper flex={1}>
@ -270,34 +234,24 @@ function NewWidget({
width={600}
>
<Typography>
Your graph built with{' '}
<QueryTypeTag queryType={selectedWidget?.query.queryType} /> query will be
saved. Press OK to confirm.
Your graph built with <QueryTypeTag queryType={currentQuery.queryType} />{' '}
query will be saved. Press OK to confirm.
</Typography>
</Modal>
</Container>
);
}
export interface NewWidgetProps {
selectedGraph: GRAPH_TYPES;
yAxisUnit: Widgets['yAxisUnit'];
}
interface DispatchProps {
saveSettingOfPanel: (
props: SaveDashboardProps,
) => (dispatch: Dispatch<AppActions>) => void;
getQueryResults: (
props: GetQueryResultsProps,
) => (dispatch: Dispatch<AppActions>) => void;
}
const mapDispatchToProps = (
dispatch: ThunkDispatch<unknown, unknown, AppActions>,
): DispatchProps => ({
saveSettingOfPanel: bindActionCreators(SaveDashboard, dispatch),
getQueryResults: bindActionCreators(GetQueryResults, dispatch),
});
type Props = DispatchProps & NewWidgetProps;

View File

@ -0,0 +1,13 @@
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import { Widgets } from 'types/api/dashboard/getAll';
import { timePreferance } from './RightContainer/timeItems';
export interface NewWidgetProps {
selectedGraph: GRAPH_TYPES;
yAxisUnit: Widgets['yAxisUnit'];
}
export interface WidgetGraphProps extends NewWidgetProps {
selectedTime: timePreferance;
}

View File

@ -0,0 +1,18 @@
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useQuery, UseQueryOptions, UseQueryResult } from 'react-query';
import {
GetMetricQueryRange,
GetQueryResultsProps,
} from 'store/actions/dashboard/getQueryResults';
import { SuccessResponse } from 'types/api';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
export const useGetQueryRange = (
requestData: GetQueryResultsProps,
options?: UseQueryOptions<SuccessResponse<MetricRangePayloadProps>, Error>,
): UseQueryResult<SuccessResponse<MetricRangePayloadProps>, Error> =>
useQuery<SuccessResponse<MetricRangePayloadProps>, Error>({
queryKey: [REACT_QUERY_KEY.GET_QUERY_RANGE, requestData],
queryFn: async () => GetMetricQueryRange(requestData),
...options,
});

View File

@ -0,0 +1,51 @@
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import useUrlQuery from 'hooks/useUrlQuery';
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
import { UseQueryOptions, UseQueryResult } from 'react-query';
import { useSelector } from 'react-redux';
import { GetQueryResultsProps } from 'store/actions/dashboard/getQueryResults';
import { AppState } from 'store/reducers';
import { SuccessResponse } from 'types/api';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { GlobalReducer } from 'types/reducer/globalTime';
import { useGetQueryRange } from './useGetQueryRange';
export const useGetWidgetQueryRange = (
{
graphType,
selectedTime,
}: Pick<GetQueryResultsProps, 'graphType' | 'selectedTime'>,
options?: UseQueryOptions<SuccessResponse<MetricRangePayloadProps>, Error>,
): UseQueryResult<SuccessResponse<MetricRangePayloadProps>, Error> => {
const urlQuery = useUrlQuery();
const { selectedTime: globalSelectedInterval } = useSelector<
AppState,
GlobalReducer
>((state) => state.globalTime);
const compositeQuery = urlQuery.get(COMPOSITE_QUERY);
return useGetQueryRange(
{
graphType,
selectedTime,
globalSelectedInterval,
query: JSON.parse(compositeQuery || ''),
variables: getDashboardVariables(),
},
{
enabled: !!compositeQuery,
retry: false,
queryKey: [
REACT_QUERY_KEY.GET_QUERY_RANGE,
selectedTime,
globalSelectedInterval,
compositeQuery,
],
...options,
},
);
};

View File

@ -1,6 +1,6 @@
import { ChartData } from 'chart.js';
import getLabelName from 'lib/getLabelName';
import { Widgets } from 'types/api/dashboard/getAll';
import { QueryData } from 'types/api/widgets/getQuery';
import convertIntoEpoc from './covertIntoEpoc';
import { colors } from './getRandomColor';
@ -77,7 +77,11 @@ const getChartData = ({ queryData }: GetChartDataProps): ChartData => {
};
interface GetChartDataProps {
queryData: Widgets['queryData']['data'][];
queryData: {
query?: string;
legend?: string;
queryData: QueryData[];
}[];
}
export default getChartData;

View File

@ -39,16 +39,6 @@ export const GetDashboard = ({
panelTypes: graphType || PANEL_TYPES.TIME_SERIES,
timePreferance: 'GLOBAL_TIME',
title: '',
queryType: 0,
queryData: {
data: {
queryData: [],
},
error: false,
errorMessage: '',
loading: false,
},
query: initialQueryWithType,
},
});

View File

@ -3,9 +3,6 @@
// @ts-nocheck
import { getMetricsQueryRange } from 'api/metrics/getQueryRange';
import { AxiosError } from 'axios';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import { ITEMS } from 'container/NewDashboard/ComponentsSlider/menuItems';
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
import { Time } from 'container/TopNav/DateTimeSelection/config';
import GetMaxMinTime from 'lib/getMaxMinTime';
@ -14,14 +11,11 @@ import GetStartAndEndTime from 'lib/getStartAndEndTime';
import getStep from 'lib/getStep';
import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi';
import { isEmpty } from 'lodash-es';
import { Dispatch } from 'redux';
import store from 'store';
import AppActions from 'types/actions';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { SuccessResponse } from 'types/api';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { EQueryType } from 'types/common/dashboard';
import { GlobalReducer } from 'types/reducer/globalTime';
import { convertNewDataToOld } from 'lib/newQueryBuilder/convertNewDataToOld';
export async function GetMetricQueryRange({
@ -30,13 +24,7 @@ export async function GetMetricQueryRange({
graphType,
selectedTime,
variables = {},
}: {
query: Query;
graphType: GRAPH_TYPES;
selectedTime: timePreferenceType;
globalSelectedInterval: Time;
variables?: Record<string, unknown>;
}): Promise<SuccessResponse<MetricRangePayloadProps> | ErrorResponse> {
}: GetQueryResultsProps): Promise<SuccessResponse<MetricRangePayloadProps>> {
const queryData = query[query.queryType];
let legendMap: Record<string, string> = {};
@ -153,66 +141,10 @@ export async function GetMetricQueryRange({
return response;
}
export const GetQueryResults = (
props: GetQueryResultsProps,
): ((dispatch: Dispatch<AppActions>) => void) => {
return async (dispatch: Dispatch<AppActions>): Promise<void> => {
try {
dispatch({
type: 'QUERY_ERROR',
payload: {
errorMessage: '',
widgetId: props.widgetId,
errorBoolean: false,
isLoadingQueryResult: true,
},
});
const response = await GetMetricQueryRange(props);
const isError = response.error;
if (isError != null) {
dispatch({
type: 'QUERY_ERROR',
payload: {
errorMessage: isError || '',
widgetId: props.widgetId,
isLoadingQueryResult: false,
},
});
return;
}
dispatch({
type: 'QUERY_SUCCESS',
payload: {
widgetId: props.widgetId,
data: {
queryData: response.payload?.data?.result
? response.payload?.data?.result
: [],
},
},
});
} catch (error) {
dispatch({
type: 'QUERY_ERROR',
payload: {
errorMessage: (error as AxiosError).toString(),
widgetId: props.widgetId,
errorBoolean: true,
isLoadingQueryResult: false,
},
});
}
};
};
export interface GetQueryResultsProps {
widgetId: string;
selectedTime: timePreferenceType;
query: Query;
graphType: ITEMS;
globalSelectedInterval: GlobalReducer['selectedTime'];
variables: Record<string, unknown>;
graphType: GRAPH_TYPES;
selectedTime: timePreferenceType;
globalSelectedInterval: Time;
variables?: Record<string, unknown>;
}

View File

@ -1,5 +1,6 @@
import updateDashboardApi from 'api/dashboard/update';
import { AxiosError } from 'axios';
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
import ROUTES from 'constants/routes';
import { ITEMS } from 'container/NewDashboard/ComponentsSlider/menuItems';
import history from 'lib/history';
@ -84,6 +85,12 @@ export const SaveDashboard = ({
];
};
const allLayout = getAllLayout();
const params = new URLSearchParams(window.location.search);
const compositeQuery = params.get(COMPOSITE_QUERY);
const query = compositeQuery
? JSON.parse(compositeQuery)
: selectedWidget.query;
const response = await updateDashboardApi({
data: {
...selectedDashboard.data,
@ -98,6 +105,7 @@ export const SaveDashboard = ({
...preWidget,
{
...selectedWidget,
query,
description: updatedDescription,
id: isEmptyWidget ? newWidgetId : widgetId,
isStacked: updatedisStacked,
@ -107,9 +115,6 @@ export const SaveDashboard = ({
timePreferance: updatedtimePreferance,
yAxisUnit: updatedYAxisUnit,
panelTypes: graphType,
queryData: {
...selectedWidget.queryData,
},
},
...afterWidget,
],

View File

@ -1,6 +1,5 @@
import { Dispatch } from 'redux';
import AppActions from 'types/actions';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
export const UpdateQuery = (
props: UpdateQueryProps,
@ -10,7 +9,6 @@ export const UpdateQuery = (
dispatch({
type: 'UPDATE_QUERY',
payload: {
query: props.updatedQuery,
widgetId: props.widgetId,
yAxisUnit: props.yAxisUnit,
},
@ -18,7 +16,6 @@ export const UpdateQuery = (
};
export interface UpdateQueryProps {
updatedQuery: Query;
widgetId: string;
yAxisUnit: string | undefined;
}

View File

@ -13,8 +13,6 @@ import {
GET_DASHBOARD_LOADING_START,
GET_DASHBOARD_SUCCESS,
IS_ADD_WIDGET,
QUERY_ERROR,
QUERY_SUCCESS,
SAVE_SETTING_TO_PANEL_SUCCESS,
TOGGLE_EDIT_MODE,
UPDATE_DASHBOARD,
@ -30,9 +28,7 @@ const InitialValue: InitialValueTypes = {
error: false,
errorMessage: '',
isEditMode: false,
isQueryFired: false,
isAddWidget: false,
isLoadingQueryResult: false,
};
const dashboard = (
@ -170,102 +166,6 @@ const dashboard = (
};
}
case QUERY_ERROR: {
const {
widgetId,
errorMessage,
errorBoolean = true,
isLoadingQueryResult = false,
} = action.payload;
const [selectedDashboard] = state.dashboards;
const { data } = selectedDashboard;
const selectedWidgetIndex = data.widgets?.findIndex(
(e) => e.id === widgetId,
);
const { widgets } = data;
const preWidget = data.widgets?.slice(0, selectedWidgetIndex);
const afterWidget = data.widgets?.slice(
(selectedWidgetIndex || 0) + 1, // this is never undefined
widgets?.length,
);
const selectedWidget =
(selectedDashboard.data.widgets || [])[selectedWidgetIndex || 0] || {};
return {
...state,
dashboards: [
{
...selectedDashboard,
data: {
...data,
widgets: [
...(preWidget || []),
{
...selectedWidget,
queryData: {
...selectedWidget.queryData,
error: errorBoolean,
errorMessage,
},
},
...(afterWidget || []),
],
},
},
],
isQueryFired: true,
isLoadingQueryResult,
};
}
case QUERY_SUCCESS: {
const { widgetId, data: queryDataResponse } = action.payload;
const { dashboards } = state;
const [selectedDashboard] = dashboards;
const { data } = selectedDashboard;
const { widgets = [] } = data;
const selectedWidgetIndex = widgets.findIndex((e) => e.id === widgetId) || 0;
const preWidget = widgets?.slice(0, selectedWidgetIndex) || [];
const afterWidget =
widgets.slice(
selectedWidgetIndex + 1, // this is never undefined
widgets.length,
) || [];
const selectedWidget = widgets[selectedWidgetIndex];
return {
...state,
dashboards: [
{
...selectedDashboard,
data: {
...data,
widgets: [
...preWidget,
{
...selectedWidget,
queryData: {
data: queryDataResponse,
error: selectedWidget.queryData.error,
errorMessage: selectedWidget.queryData.errorMessage,
loading: false,
},
},
...afterWidget,
],
},
},
],
isQueryFired: true,
isLoadingQueryResult: false,
};
}
case APPLY_SETTINGS_TO_PANEL: {
const { widgetId } = action.payload;
@ -367,7 +267,7 @@ const dashboard = (
}
case UPDATE_QUERY: {
const { query, widgetId, yAxisUnit } = action.payload;
const { widgetId, yAxisUnit } = action.payload;
const { dashboards } = state;
const [selectedDashboard] = dashboards;
const { data } = selectedDashboard;
@ -395,7 +295,6 @@ const dashboard = (
...preWidget,
{
...selectedWidget,
query,
yAxisUnit,
},
...afterWidget,

View File

@ -5,7 +5,6 @@ import {
IDashboardVariable,
Widgets,
} from 'types/api/dashboard/getAll';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { QueryData } from 'types/api/widgets/getQuery';
export const GET_DASHBOARD = 'GET_DASHBOARD';
@ -30,9 +29,6 @@ export const DELETE_DASHBOARD_ERROR = 'DELETE_DASHBOARD_ERROR';
export const CREATE_DEFAULT_WIDGET = 'CREATE_DEFAULT_WIDGET';
export const QUERY_SUCCESS = 'QUERY_SUCCESS';
export const QUERY_ERROR = 'QUERY_ERROR';
export const UPDATE_QUERY = 'UPDATE_QUERY';
export const APPLY_SETTINGS_TO_PANEL = 'APPLY_SETTINGS_TO_PANEL';
@ -132,30 +128,15 @@ export interface QuerySuccessPayload {
// query: string
};
}
interface QuerySuccess {
type: typeof QUERY_SUCCESS;
payload: QuerySuccessPayload;
}
interface UpdateQuery {
type: typeof UPDATE_QUERY;
payload: {
query: Query;
widgetId: string;
yAxisUnit: string | undefined;
};
}
interface QueryError {
type: typeof QUERY_ERROR;
payload: {
errorMessage: string;
widgetId: string;
errorBoolean?: boolean;
isLoadingQueryResult?: boolean;
};
}
interface SaveDashboardSuccess {
type: typeof SAVE_SETTING_TO_PANEL_SUCCESS;
payload: Dashboard;
@ -198,8 +179,6 @@ export type DashboardActions =
| UpdateDashboardTitle
| ToggleEditMode
| CreateDefaultWidget
| QuerySuccess
| QueryError
| ApplySettingsToPanel
| SaveDashboardSuccess
| WidgetDeleteSuccess

View File

@ -3,8 +3,6 @@ import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems
import { Layout } from 'react-grid-layout';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { QueryData } from '../widgets/getQuery';
export type PayloadProps = Dashboard[];
export const VariableQueryTypeArr = ['QUERY', 'TEXTBOX', 'CUSTOM'] as const;
@ -65,16 +63,6 @@ export interface IBaseWidget {
opacity: string;
nullZeroValues: string;
timePreferance: timePreferenceType;
queryData: {
loading: boolean;
error: boolean;
errorMessage: string;
data: {
query?: string;
legend?: string;
queryData: QueryData[];
};
};
stepSize?: number;
yAxisUnit?: string;
}

View File

@ -6,7 +6,5 @@ export default interface DashboardReducer {
error: boolean;
errorMessage: string;
isEditMode: boolean;
isQueryFired: boolean;
isAddWidget: boolean;
isLoadingQueryResult: boolean;
}