mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-15 17:35:53 +08:00
fix: step size is made dynamic (#2903)
* fix: step size is made dynamic * test: get step test is added * chore: alerts step is updated * chore: query is updated * chore: provider query is updated * fix: user input is being take care of * chore: query builder step interval is updated * test: lib/getStep is updated * test: test for getStep is updated * fix: step interval is taken care when we change from top nav * chore: while saving the dashboard query is updated * chore: updated when selected widget is present * chore: getStep is now multiple of 60 and test is updated accordingly * chore: user input is overriden from global step --------- Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
This commit is contained in:
parent
56402b0d40
commit
9b8f7a091c
@ -125,7 +125,7 @@ const initialQueryBuilderFormValues: IBuilderQuery = {
|
|||||||
}),
|
}),
|
||||||
disabled: false,
|
disabled: false,
|
||||||
having: [],
|
having: [],
|
||||||
stepInterval: 30,
|
stepInterval: 60,
|
||||||
limit: null,
|
limit: null,
|
||||||
orderBy: [],
|
orderBy: [],
|
||||||
groupBy: [],
|
groupBy: [],
|
||||||
|
@ -8,6 +8,7 @@ import QueryTypeTag from 'container/NewWidget/LeftContainer/QueryTypeTag';
|
|||||||
import PlotTag from 'container/NewWidget/LeftContainer/WidgetGraph/PlotTag';
|
import PlotTag from 'container/NewWidget/LeftContainer/WidgetGraph/PlotTag';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||||
|
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
|
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
@ -16,6 +17,8 @@ import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQu
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useQueryClient } from 'react-query';
|
import { useQueryClient } from 'react-query';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||||
import {
|
import {
|
||||||
AlertDef,
|
AlertDef,
|
||||||
@ -24,6 +27,7 @@ import {
|
|||||||
} from 'types/api/alerts/def';
|
} from 'types/api/alerts/def';
|
||||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
import BasicInfo from './BasicInfo';
|
import BasicInfo from './BasicInfo';
|
||||||
import ChartPreview from './ChartPreview';
|
import ChartPreview from './ChartPreview';
|
||||||
@ -48,6 +52,10 @@ function FormAlertRules({
|
|||||||
// init namespace for translations
|
// init namespace for translations
|
||||||
const { t } = useTranslation('alerts');
|
const { t } = useTranslation('alerts');
|
||||||
|
|
||||||
|
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
|
||||||
|
(state) => state.globalTime,
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
currentQuery,
|
currentQuery,
|
||||||
stagedQuery,
|
stagedQuery,
|
||||||
@ -76,10 +84,6 @@ function FormAlertRules({
|
|||||||
setAlertDef(initialValue);
|
setAlertDef(initialValue);
|
||||||
}, [initialValue]);
|
}, [initialValue]);
|
||||||
|
|
||||||
const onRunQuery = (): void => {
|
|
||||||
handleRunQuery();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCancelHandler = useCallback(() => {
|
const onCancelHandler = useCallback(() => {
|
||||||
history.replace(ROUTES.LIST_ALL_ALERT);
|
history.replace(ROUTES.LIST_ALL_ALERT);
|
||||||
}, []);
|
}, []);
|
||||||
@ -99,7 +103,7 @@ function FormAlertRules({
|
|||||||
}
|
}
|
||||||
const query: Query = { ...currentQuery, queryType: val };
|
const query: Query = { ...currentQuery, queryType: val };
|
||||||
|
|
||||||
redirectWithQueryBuilderData(query);
|
redirectWithQueryBuilderData(updateStepInterval(query, maxTime, minTime));
|
||||||
};
|
};
|
||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
|
|
||||||
@ -402,7 +406,7 @@ function FormAlertRules({
|
|||||||
queryCategory={currentQuery.queryType}
|
queryCategory={currentQuery.queryType}
|
||||||
setQueryCategory={onQueryCategoryChange}
|
setQueryCategory={onQueryCategoryChange}
|
||||||
alertType={alertType || AlertTypes.METRICS_BASED_ALERT}
|
alertType={alertType || AlertTypes.METRICS_BASED_ALERT}
|
||||||
runQuery={onRunQuery}
|
runQuery={handleRunQuery}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RuleOptions
|
<RuleOptions
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
timePreferance,
|
timePreferance,
|
||||||
} from 'container/NewWidget/RightContainer/timeItems';
|
} from 'container/NewWidget/RightContainer/timeItems';
|
||||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||||
|
import { useStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
||||||
import getChartData from 'lib/getChartData';
|
import getChartData from 'lib/getChartData';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
@ -48,11 +49,13 @@ function FullView({
|
|||||||
[selectedTime, globalSelectedTime, widget],
|
[selectedTime, globalSelectedTime, widget],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedQuery = useStepInterval(widget?.query);
|
||||||
|
|
||||||
const response = useGetQueryRange(
|
const response = useGetQueryRange(
|
||||||
{
|
{
|
||||||
selectedTime: selectedTime.enum,
|
selectedTime: selectedTime.enum,
|
||||||
graphType: widget.panelTypes,
|
graphType: widget.panelTypes,
|
||||||
query: widget.query,
|
query: updatedQuery,
|
||||||
globalSelectedInterval: globalSelectedTime,
|
globalSelectedInterval: globalSelectedTime,
|
||||||
variables: getDashboardVariables(),
|
variables: getDashboardVariables(),
|
||||||
},
|
},
|
||||||
@ -84,10 +87,8 @@ function FullView({
|
|||||||
{fullViewOptions && (
|
{fullViewOptions && (
|
||||||
<TimeContainer>
|
<TimeContainer>
|
||||||
<TimePreference
|
<TimePreference
|
||||||
{...{
|
selectedTime={selectedTime}
|
||||||
selectedTime,
|
setSelectedTime={setSelectedTime}
|
||||||
setSelectedTime,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onClick={(): void => {
|
onClick={(): void => {
|
||||||
|
@ -4,6 +4,7 @@ import Spinner from 'components/Spinner';
|
|||||||
import GridGraphComponent from 'container/GridGraphComponent';
|
import GridGraphComponent from 'container/GridGraphComponent';
|
||||||
import { UpdateDashboard } from 'container/GridGraphLayout/utils';
|
import { UpdateDashboard } from 'container/GridGraphLayout/utils';
|
||||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||||
|
import { useStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
import usePreviousValue from 'hooks/usePreviousValue';
|
import usePreviousValue from 'hooks/usePreviousValue';
|
||||||
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
||||||
@ -80,11 +81,13 @@ function GridCardGraph({
|
|||||||
const selectedData = selectedDashboard?.data;
|
const selectedData = selectedDashboard?.data;
|
||||||
const { variables } = selectedData;
|
const { variables } = selectedData;
|
||||||
|
|
||||||
|
const updatedQuery = useStepInterval(widget?.query);
|
||||||
|
|
||||||
const queryResponse = useGetQueryRange(
|
const queryResponse = useGetQueryRange(
|
||||||
{
|
{
|
||||||
selectedTime: widget?.timePreferance,
|
selectedTime: widget?.timePreferance,
|
||||||
graphType: widget?.panelTypes,
|
graphType: widget?.panelTypes,
|
||||||
query: widget?.query,
|
query: updatedQuery,
|
||||||
globalSelectedInterval,
|
globalSelectedInterval,
|
||||||
variables: getDashboardVariables(),
|
variables: getDashboardVariables(),
|
||||||
},
|
},
|
||||||
|
@ -2,6 +2,8 @@ import {
|
|||||||
initialFormulaBuilderFormValues,
|
initialFormulaBuilderFormValues,
|
||||||
initialQueryBuilderFormValuesMap,
|
initialQueryBuilderFormValuesMap,
|
||||||
} from 'constants/queryBuilder';
|
} from 'constants/queryBuilder';
|
||||||
|
import getStep from 'lib/getStep';
|
||||||
|
import store from 'store';
|
||||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import {
|
import {
|
||||||
@ -24,6 +26,11 @@ export const getQueryBuilderQueries = ({
|
|||||||
groupBy,
|
groupBy,
|
||||||
aggregateAttribute: metricName,
|
aggregateAttribute: metricName,
|
||||||
legend,
|
legend,
|
||||||
|
stepInterval: getStep({
|
||||||
|
end: store.getState().globalTime.maxTime,
|
||||||
|
inputFormat: 'ns',
|
||||||
|
start: store.getState().globalTime.minTime,
|
||||||
|
}),
|
||||||
reduceTo: 'sum',
|
reduceTo: 'sum',
|
||||||
filters: {
|
filters: {
|
||||||
items: itemsA,
|
items: itemsA,
|
||||||
@ -64,6 +71,11 @@ export const getQueryBuilderQuerieswithFormula = ({
|
|||||||
items: additionalItemsA,
|
items: additionalItemsA,
|
||||||
op: 'AND',
|
op: 'AND',
|
||||||
},
|
},
|
||||||
|
stepInterval: getStep({
|
||||||
|
end: store.getState().globalTime.maxTime,
|
||||||
|
inputFormat: 'ns',
|
||||||
|
start: store.getState().globalTime.minTime,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...initialQueryBuilderFormValuesMap.metrics,
|
...initialQueryBuilderFormValuesMap.metrics,
|
||||||
@ -79,6 +91,11 @@ export const getQueryBuilderQuerieswithFormula = ({
|
|||||||
items: additionalItemsB,
|
items: additionalItemsB,
|
||||||
op: 'AND',
|
op: 'AND',
|
||||||
},
|
},
|
||||||
|
stepInterval: getStep({
|
||||||
|
end: store.getState().globalTime.maxTime,
|
||||||
|
inputFormat: 'ns',
|
||||||
|
start: store.getState().globalTime.minTime,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -11,11 +11,11 @@ import {
|
|||||||
} from 'hooks/useResourceAttribute/utils';
|
} from 'hooks/useResourceAttribute/utils';
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
|
||||||
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
||||||
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
||||||
import { Button } from './styles';
|
import { Button } from './styles';
|
||||||
import {
|
import {
|
||||||
@ -25,7 +25,7 @@ import {
|
|||||||
onViewTracePopupClick,
|
onViewTracePopupClick,
|
||||||
} from './util';
|
} from './util';
|
||||||
|
|
||||||
function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element {
|
function DBCall(): JSX.Element {
|
||||||
const { servicename } = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<{ servicename?: string }>();
|
||||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||||
const { queries } = useResourceAttribute();
|
const { queries } = useResourceAttribute();
|
||||||
@ -59,7 +59,7 @@ function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
}),
|
}),
|
||||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
const databaseCallsAverageDurationWidget = useMemo(
|
const databaseCallsAverageDurationWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -73,7 +73,7 @@ function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
}),
|
}),
|
||||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -151,8 +151,4 @@ function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DBCallProps {
|
|
||||||
getWidgetQueryBuilder: (query: Widgets['query']) => Widgets;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DBCall;
|
export default DBCall;
|
||||||
|
@ -13,10 +13,10 @@ import {
|
|||||||
} from 'hooks/useResourceAttribute/utils';
|
} from 'hooks/useResourceAttribute/utils';
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
||||||
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
||||||
import { legend } from './constant';
|
import { legend } from './constant';
|
||||||
import { Button } from './styles';
|
import { Button } from './styles';
|
||||||
@ -26,7 +26,7 @@ import {
|
|||||||
onViewTracePopupClick,
|
onViewTracePopupClick,
|
||||||
} from './util';
|
} from './util';
|
||||||
|
|
||||||
function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
function External(): JSX.Element {
|
||||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||||
|
|
||||||
const { servicename } = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<{ servicename?: string }>();
|
||||||
@ -51,7 +51,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
}),
|
}),
|
||||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedTraceTags = useMemo(
|
const selectedTraceTags = useMemo(
|
||||||
@ -71,7 +71,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
}),
|
}),
|
||||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const externalCallRPSWidget = useMemo(
|
const externalCallRPSWidget = useMemo(
|
||||||
@ -87,7 +87,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
}),
|
}),
|
||||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const externalCallDurationAddressWidget = useMemo(
|
const externalCallDurationAddressWidget = useMemo(
|
||||||
@ -103,7 +103,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
}),
|
}),
|
||||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -261,8 +261,4 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExternalProps {
|
|
||||||
getWidgetQueryBuilder: (query: Widgets['query']) => Widgets;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default External;
|
export default External;
|
||||||
|
@ -18,11 +18,11 @@ import { useDispatch, useSelector } from 'react-redux';
|
|||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
import { UpdateTimeInterval } from 'store/actions';
|
import { UpdateTimeInterval } from 'store/actions';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import MetricReducer from 'types/reducer/metrics';
|
import MetricReducer from 'types/reducer/metrics';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
||||||
import {
|
import {
|
||||||
errorPercentage,
|
errorPercentage,
|
||||||
operationPerSec,
|
operationPerSec,
|
||||||
@ -36,7 +36,7 @@ import {
|
|||||||
onViewTracePopupClick,
|
onViewTracePopupClick,
|
||||||
} from './util';
|
} from './util';
|
||||||
|
|
||||||
function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
|
function Application(): JSX.Element {
|
||||||
const { servicename } = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<{ servicename?: string }>();
|
||||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||||
const { search } = useLocation();
|
const { search } = useLocation();
|
||||||
@ -94,7 +94,7 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
}),
|
}),
|
||||||
[getWidgetQueryBuilder, servicename, topLevelOperations, tagFilterItems],
|
[servicename, topLevelOperations, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const errorPercentageWidget = useMemo(
|
const errorPercentageWidget = useMemo(
|
||||||
@ -110,7 +110,7 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
}),
|
}),
|
||||||
[servicename, topLevelOperations, tagFilterItems, getWidgetQueryBuilder],
|
[servicename, topLevelOperations, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDragSelect = useCallback(
|
const onDragSelect = useCallback(
|
||||||
@ -289,10 +289,6 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DashboardProps {
|
|
||||||
getWidgetQueryBuilder: (query: Widgets['query']) => Widgets;
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClickHandlerType = (
|
type ClickHandlerType = (
|
||||||
ChartEvent: ChartEvent,
|
ChartEvent: ChartEvent,
|
||||||
activeElements: ActiveElement[],
|
activeElements: ActiveElement[],
|
||||||
|
@ -6,21 +6,20 @@ import { memo, useMemo } from 'react';
|
|||||||
import { generatePath, useParams } from 'react-router-dom';
|
import { generatePath, useParams } from 'react-router-dom';
|
||||||
import { useLocation } from 'react-use';
|
import { useLocation } from 'react-use';
|
||||||
|
|
||||||
import { getWidgetQueryBuilder } from './MetricsApplication.factory';
|
|
||||||
import DBCall from './Tabs/DBCall';
|
import DBCall from './Tabs/DBCall';
|
||||||
import External from './Tabs/External';
|
import External from './Tabs/External';
|
||||||
import Overview from './Tabs/Overview';
|
import Overview from './Tabs/Overview';
|
||||||
|
|
||||||
function OverViewTab(): JSX.Element {
|
function OverViewTab(): JSX.Element {
|
||||||
return <Overview getWidgetQueryBuilder={getWidgetQueryBuilder} />;
|
return <Overview />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DbCallTab(): JSX.Element {
|
function DbCallTab(): JSX.Element {
|
||||||
return <DBCall getWidgetQueryBuilder={getWidgetQueryBuilder} />;
|
return <DBCall />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ExternalTab(): JSX.Element {
|
function ExternalTab(): JSX.Element {
|
||||||
return <External getWidgetQueryBuilder={getWidgetQueryBuilder} />;
|
return <External />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ServiceMetrics(): JSX.Element {
|
function ServiceMetrics(): JSX.Element {
|
||||||
|
@ -6,6 +6,7 @@ import { QueryBuilder } from 'container/QueryBuilder';
|
|||||||
import { useGetWidgetQueryRange } from 'hooks/queryBuilder/useGetWidgetQueryRange';
|
import { useGetWidgetQueryRange } from 'hooks/queryBuilder/useGetWidgetQueryRange';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||||
|
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
import useUrlQuery from 'hooks/useUrlQuery';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { connect, useSelector } from 'react-redux';
|
import { connect, useSelector } from 'react-redux';
|
||||||
@ -22,6 +23,7 @@ import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
|||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
import DashboardReducer from 'types/reducer/dashboards';
|
import DashboardReducer from 'types/reducer/dashboards';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
import ClickHouseQueryContainer from './QueryBuilder/clickHouse';
|
import ClickHouseQueryContainer from './QueryBuilder/clickHouse';
|
||||||
import PromQLQueryContainer from './QueryBuilder/promQL';
|
import PromQLQueryContainer from './QueryBuilder/promQL';
|
||||||
@ -33,6 +35,11 @@ function QuerySection({
|
|||||||
}: QueryProps): JSX.Element {
|
}: QueryProps): JSX.Element {
|
||||||
const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder();
|
const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder();
|
||||||
const urlQuery = useUrlQuery();
|
const urlQuery = useUrlQuery();
|
||||||
|
|
||||||
|
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
|
||||||
|
(state) => state.globalTime,
|
||||||
|
);
|
||||||
|
|
||||||
const { featureResponse } = useSelector<AppState, AppReducer>(
|
const { featureResponse } = useSelector<AppState, AppReducer>(
|
||||||
(state) => state.app,
|
(state) => state.app,
|
||||||
);
|
);
|
||||||
@ -67,10 +74,19 @@ function QuerySection({
|
|||||||
yAxisUnit: selectedWidget.yAxisUnit,
|
yAxisUnit: selectedWidget.yAxisUnit,
|
||||||
});
|
});
|
||||||
|
|
||||||
redirectWithQueryBuilderData(updatedQuery);
|
redirectWithQueryBuilderData(
|
||||||
|
updateStepInterval(updatedQuery, maxTime, minTime),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
[urlQuery, selectedWidget, updateQuery, redirectWithQueryBuilderData],
|
[
|
||||||
|
updateQuery,
|
||||||
|
urlQuery,
|
||||||
|
selectedWidget.yAxisUnit,
|
||||||
|
redirectWithQueryBuilderData,
|
||||||
|
maxTime,
|
||||||
|
minTime,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleQueryCategoryChange = (qCategory: string): void => {
|
const handleQueryCategoryChange = (qCategory: string): void => {
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import { Input } from 'antd';
|
import { InputNumber, InputNumberProps } from 'antd';
|
||||||
import getStep from 'lib/getStep';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import { AppState } from 'store/reducers';
|
|
||||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
||||||
|
|
||||||
import { selectStyle } from '../QueryBuilderSearch/config';
|
import { selectStyle } from '../QueryBuilderSearch/config';
|
||||||
|
|
||||||
@ -13,49 +9,27 @@ function AggregateEveryFilter({
|
|||||||
onChange,
|
onChange,
|
||||||
query,
|
query,
|
||||||
}: AggregateEveryFilterProps): JSX.Element {
|
}: AggregateEveryFilterProps): JSX.Element {
|
||||||
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
|
||||||
(state) => state.globalTime,
|
|
||||||
);
|
|
||||||
|
|
||||||
const stepInterval = useMemo(
|
|
||||||
() =>
|
|
||||||
getStep({
|
|
||||||
start: minTime,
|
|
||||||
end: maxTime,
|
|
||||||
inputFormat: 'ns',
|
|
||||||
}),
|
|
||||||
[maxTime, minTime],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleKeyDown = (event: {
|
|
||||||
keyCode: number;
|
|
||||||
which: number;
|
|
||||||
preventDefault: () => void;
|
|
||||||
}): void => {
|
|
||||||
const keyCode = event.keyCode || event.which;
|
|
||||||
const isBackspace = keyCode === 8;
|
|
||||||
const isNumeric =
|
|
||||||
(keyCode >= 48 && keyCode <= 57) || (keyCode >= 96 && keyCode <= 105);
|
|
||||||
|
|
||||||
if (!isNumeric && !isBackspace) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const isMetricsDataSource = useMemo(
|
const isMetricsDataSource = useMemo(
|
||||||
() => query.dataSource === DataSource.METRICS,
|
() => query.dataSource === DataSource.METRICS,
|
||||||
[query.dataSource],
|
[query.dataSource],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onChangeHandler: InputNumberProps<number>['onChange'] = (event) => {
|
||||||
|
if (event && event >= 0) {
|
||||||
|
onChange(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isDisabled = isMetricsDataSource && !query.aggregateAttribute.key;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Input
|
<InputNumber
|
||||||
type="text"
|
|
||||||
placeholder="Enter in seconds"
|
placeholder="Enter in seconds"
|
||||||
disabled={isMetricsDataSource && !query.aggregateAttribute.key}
|
disabled={isDisabled}
|
||||||
style={selectStyle}
|
style={selectStyle}
|
||||||
defaultValue={query.stepInterval ?? stepInterval}
|
value={query.stepInterval}
|
||||||
onChange={(event): void => onChange(Number(event.target.value))}
|
onChange={onChangeHandler}
|
||||||
onKeyDown={handleKeyDown}
|
min={0}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@ import getLocalStorageKey from 'api/browser/localstorage/get';
|
|||||||
import setLocalStorageKey from 'api/browser/localstorage/set';
|
import setLocalStorageKey from 'api/browser/localstorage/set';
|
||||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||||
import dayjs, { Dayjs } from 'dayjs';
|
import dayjs, { Dayjs } from 'dayjs';
|
||||||
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
|
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
|
import GetMinMax from 'lib/getMinMax';
|
||||||
import getTimeString from 'lib/getTimeString';
|
import getTimeString from 'lib/getTimeString';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { connect, useSelector } from 'react-redux';
|
import { connect, useSelector } from 'react-redux';
|
||||||
@ -66,6 +69,8 @@ function DateTimeSelection({
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { stagedQuery, initQueryBuilderData } = useQueryBuilder();
|
||||||
|
|
||||||
const { maxTime, minTime, selectedTime } = useSelector<
|
const { maxTime, minTime, selectedTime } = useSelector<
|
||||||
AppState,
|
AppState,
|
||||||
GlobalReducer
|
GlobalReducer
|
||||||
@ -174,6 +179,14 @@ function DateTimeSelection({
|
|||||||
setRefreshButtonHidden(true);
|
setRefreshButtonHidden(true);
|
||||||
setCustomDTPickerVisible(true);
|
setCustomDTPickerVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!stagedQuery) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { maxTime, minTime } = GetMinMax(value, getTime());
|
||||||
|
|
||||||
|
initQueryBuilderData(updateStepInterval(stagedQuery, maxTime, minTime));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRefreshHandler = (): void => {
|
const onRefreshHandler = (): void => {
|
||||||
|
@ -9,8 +9,8 @@ import { SuccessResponse } from 'types/api';
|
|||||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
import { useGetCompositeQueryParam } from './useGetCompositeQueryParam';
|
|
||||||
import { useGetQueryRange } from './useGetQueryRange';
|
import { useGetQueryRange } from './useGetQueryRange';
|
||||||
|
import { useQueryBuilder } from './useQueryBuilder';
|
||||||
|
|
||||||
export const useGetWidgetQueryRange = (
|
export const useGetWidgetQueryRange = (
|
||||||
{
|
{
|
||||||
@ -24,24 +24,24 @@ export const useGetWidgetQueryRange = (
|
|||||||
GlobalReducer
|
GlobalReducer
|
||||||
>((state) => state.globalTime);
|
>((state) => state.globalTime);
|
||||||
|
|
||||||
const compositeQuery = useGetCompositeQueryParam();
|
const { stagedQuery } = useQueryBuilder();
|
||||||
|
|
||||||
return useGetQueryRange(
|
return useGetQueryRange(
|
||||||
{
|
{
|
||||||
graphType,
|
graphType,
|
||||||
selectedTime,
|
selectedTime,
|
||||||
globalSelectedInterval,
|
globalSelectedInterval,
|
||||||
query: compositeQuery || initialQueriesMap.metrics,
|
query: stagedQuery || initialQueriesMap.metrics,
|
||||||
variables: getDashboardVariables(),
|
variables: getDashboardVariables(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!compositeQuery,
|
enabled: !!stagedQuery,
|
||||||
retry: false,
|
retry: false,
|
||||||
queryKey: [
|
queryKey: [
|
||||||
REACT_QUERY_KEY.GET_QUERY_RANGE,
|
REACT_QUERY_KEY.GET_QUERY_RANGE,
|
||||||
selectedTime,
|
selectedTime,
|
||||||
globalSelectedInterval,
|
globalSelectedInterval,
|
||||||
compositeQuery,
|
stagedQuery,
|
||||||
],
|
],
|
||||||
...options,
|
...options,
|
||||||
},
|
},
|
||||||
|
37
frontend/src/hooks/queryBuilder/useStepInterval.ts
Normal file
37
frontend/src/hooks/queryBuilder/useStepInterval.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import getStep from 'lib/getStep';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
|
export const updateStepInterval = (
|
||||||
|
query: Widgets['query'],
|
||||||
|
maxTime: number,
|
||||||
|
minTime: number,
|
||||||
|
): Widgets['query'] => {
|
||||||
|
const stepInterval = getStep({
|
||||||
|
start: minTime,
|
||||||
|
end: maxTime,
|
||||||
|
inputFormat: 'ns',
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...query,
|
||||||
|
builder: {
|
||||||
|
...query?.builder,
|
||||||
|
queryData:
|
||||||
|
query?.builder?.queryData?.map((item) => ({
|
||||||
|
...item,
|
||||||
|
stepInterval,
|
||||||
|
})) || [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useStepInterval = (query: Widgets['query']): Widgets['query'] => {
|
||||||
|
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||||
|
(state) => state.globalTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
return updateStepInterval(query, maxTime, minTime);
|
||||||
|
};
|
@ -39,7 +39,12 @@ describe('lib/getStep', () => {
|
|||||||
const startUnix = start.valueOf();
|
const startUnix = start.valueOf();
|
||||||
const endUnix = end.valueOf();
|
const endUnix = end.valueOf();
|
||||||
|
|
||||||
const expectedStepSize = Math.floor(end.diff(start, 's') / MaxDataPoints);
|
let expectedStepSize = Math.max(
|
||||||
|
Math.floor(end.diff(start, 's') / MaxDataPoints),
|
||||||
|
DefaultStepSize,
|
||||||
|
);
|
||||||
|
|
||||||
|
expectedStepSize -= expectedStepSize % 60;
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
getStep({
|
getStep({
|
||||||
|
@ -7,7 +7,7 @@ export const getDashboardVariables = (): Record<string, unknown> => {
|
|||||||
globalTime,
|
globalTime,
|
||||||
dashboards: { dashboards },
|
dashboards: { dashboards },
|
||||||
} = store.getState();
|
} = store.getState();
|
||||||
const [selectedDashboard] = dashboards;
|
const [selectedDashboard] = dashboards || [];
|
||||||
const {
|
const {
|
||||||
data: { variables = {} },
|
data: { variables = {} },
|
||||||
} = selectedDashboard;
|
} = selectedDashboard;
|
||||||
|
137
frontend/src/lib/getStep.test.ts
Normal file
137
frontend/src/lib/getStep.test.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
import getStep, { DefaultStepSize, MaxDataPoints } from './getStep';
|
||||||
|
|
||||||
|
describe('get dynamic step size', () => {
|
||||||
|
test('should return default step size if diffSec is less than MaxDataPoints', () => {
|
||||||
|
const start = dayjs().subtract(1, 'minute').valueOf();
|
||||||
|
const end = dayjs().valueOf();
|
||||||
|
|
||||||
|
const step = getStep({
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
inputFormat: 'ms',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(step).toBe(DefaultStepSize);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return appropriate step size if diffSec is more than MaxDataPoints', () => {
|
||||||
|
const start = dayjs().subtract(4, 'hour').valueOf();
|
||||||
|
const end = dayjs().valueOf();
|
||||||
|
|
||||||
|
const step = getStep({
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
inputFormat: 'ms',
|
||||||
|
});
|
||||||
|
|
||||||
|
// the expected step size should be no less than DefaultStepSize
|
||||||
|
const diffSec = Math.abs(dayjs(end).diff(dayjs(start), 's'));
|
||||||
|
const expectedStep = Math.max(
|
||||||
|
Math.floor(diffSec / MaxDataPoints),
|
||||||
|
DefaultStepSize,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(step).toBe(expectedStep);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should correctly handle different input formats', () => {
|
||||||
|
const endSec = dayjs().unix();
|
||||||
|
const startSec = endSec - 4 * 3600; // 4 hours earlier
|
||||||
|
|
||||||
|
const stepSec = getStep({
|
||||||
|
start: startSec,
|
||||||
|
end: endSec,
|
||||||
|
inputFormat: 's',
|
||||||
|
});
|
||||||
|
|
||||||
|
const diffSec = Math.abs(dayjs.unix(endSec).diff(dayjs.unix(startSec), 's'));
|
||||||
|
const expectedStep = Math.max(
|
||||||
|
Math.floor(diffSec / MaxDataPoints),
|
||||||
|
DefaultStepSize,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(stepSec).toBe(expectedStep);
|
||||||
|
|
||||||
|
const startNs = startSec * 1e9; // convert to nanoseconds
|
||||||
|
const endNs = endSec * 1e9; // convert to nanoseconds
|
||||||
|
|
||||||
|
const stepNs = getStep({
|
||||||
|
start: startNs,
|
||||||
|
end: endNs,
|
||||||
|
inputFormat: 'ns',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(stepNs).toBe(expectedStep); // Expect the same result as 's' inputFormat
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should throw an error for invalid input format', () => {
|
||||||
|
const start = dayjs().valueOf();
|
||||||
|
const end = dayjs().valueOf();
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
getStep({
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
inputFormat: 'invalid' as never,
|
||||||
|
});
|
||||||
|
}).toThrow('invalid format');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return DefaultStepSize when start and end are the same', () => {
|
||||||
|
const start = dayjs().valueOf();
|
||||||
|
const end = start; // same as start
|
||||||
|
|
||||||
|
const step = getStep({
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
inputFormat: 'ms',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(step).toBe(DefaultStepSize);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return DefaultStepSize if diffSec is exactly MaxDataPoints', () => {
|
||||||
|
const endMs = dayjs().valueOf();
|
||||||
|
const startMs = endMs - MaxDataPoints * 1000; // exactly MaxDataPoints seconds earlier
|
||||||
|
|
||||||
|
const step = getStep({
|
||||||
|
start: startMs,
|
||||||
|
end: endMs,
|
||||||
|
inputFormat: 'ms',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(step).toBe(DefaultStepSize); // since calculated step size is less than DefaultStepSize, it should return DefaultStepSize
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return DefaultStepSize for future dates less than (MaxDataPoints * DefaultStepSize) seconds ahead', () => {
|
||||||
|
const start = dayjs().valueOf();
|
||||||
|
const end = start + MaxDataPoints * DefaultStepSize * 1000 - 1; // just one millisecond less than (MaxDataPoints * DefaultStepSize) seconds ahead
|
||||||
|
|
||||||
|
const step = getStep({
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
inputFormat: 'ms',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(step).toBe(DefaultStepSize);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle string inputs correctly for a time range greater than (MaxDataPoints * DefaultStepSize) seconds', () => {
|
||||||
|
const endMs = dayjs().valueOf();
|
||||||
|
const startMs = endMs - (MaxDataPoints * DefaultStepSize * 1000 + 1); // one millisecond more than (MaxDataPoints * DefaultStepSize) seconds earlier
|
||||||
|
|
||||||
|
const step = getStep({
|
||||||
|
start: startMs.toString(),
|
||||||
|
end: endMs.toString(),
|
||||||
|
inputFormat: 'ms',
|
||||||
|
});
|
||||||
|
|
||||||
|
const diffSec = Math.abs(
|
||||||
|
dayjs(Number(endMs)).diff(dayjs(Number(startMs)), 's'),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(step).toBe(Math.floor(diffSec / MaxDataPoints));
|
||||||
|
});
|
||||||
|
});
|
@ -30,7 +30,7 @@ const convertToMs = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const DefaultStepSize = 60;
|
export const DefaultStepSize = 60;
|
||||||
export const MaxDataPoints = 200;
|
export const MaxDataPoints = 300;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns relevant step size based on given start and end date.
|
* Returns relevant step size based on given start and end date.
|
||||||
@ -40,7 +40,13 @@ const getStep = ({ start, end, inputFormat = 'ms' }: GetStepInput): number => {
|
|||||||
const endDate = dayjs(convertToMs(Number(end), inputFormat));
|
const endDate = dayjs(convertToMs(Number(end), inputFormat));
|
||||||
const diffSec = Math.abs(endDate.diff(startDate, 's'));
|
const diffSec = Math.abs(endDate.diff(startDate, 's'));
|
||||||
|
|
||||||
return Math.max(Math.floor(diffSec / MaxDataPoints), DefaultStepSize);
|
let result =
|
||||||
|
Math.max(Math.floor(diffSec / MaxDataPoints), DefaultStepSize) ||
|
||||||
|
DefaultStepSize;
|
||||||
|
|
||||||
|
result -= result % 60;
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default getStep;
|
export default getStep;
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||||
import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
|
import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
|
||||||
|
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
import useUrlQuery from 'hooks/useUrlQuery';
|
||||||
import { createIdFromObjectFields } from 'lib/createIdFromObjectFields';
|
import { createIdFromObjectFields } from 'lib/createIdFromObjectFields';
|
||||||
import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName';
|
import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName';
|
||||||
@ -29,7 +30,9 @@ import {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
import { useHistory, useLocation } from 'react-router-dom';
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
// ** Types
|
// ** Types
|
||||||
import {
|
import {
|
||||||
IBuilderFormula,
|
IBuilderFormula,
|
||||||
@ -45,6 +48,7 @@ import {
|
|||||||
QueryBuilderContextType,
|
QueryBuilderContextType,
|
||||||
QueryBuilderData,
|
QueryBuilderData,
|
||||||
} from 'types/common/queryBuilder';
|
} from 'types/common/queryBuilder';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
||||||
@ -66,6 +70,7 @@ export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
|||||||
handleRunQuery: () => {},
|
handleRunQuery: () => {},
|
||||||
resetStagedQuery: () => {},
|
resetStagedQuery: () => {},
|
||||||
updateAllQueriesOperators: () => initialQueriesMap.metrics,
|
updateAllQueriesOperators: () => initialQueriesMap.metrics,
|
||||||
|
initQueryBuilderData: () => {},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function QueryBuilderProvider({
|
export function QueryBuilderProvider({
|
||||||
@ -74,6 +79,9 @@ export function QueryBuilderProvider({
|
|||||||
const urlQuery = useUrlQuery();
|
const urlQuery = useUrlQuery();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||||
|
(state) => state.globalTime,
|
||||||
|
);
|
||||||
|
|
||||||
const compositeQueryParam = useGetCompositeQueryParam();
|
const compositeQueryParam = useGetCompositeQueryParam();
|
||||||
const { queryType: queryTypeParam, ...queryState } =
|
const { queryType: queryTypeParam, ...queryState } =
|
||||||
@ -356,7 +364,6 @@ export function QueryBuilderProvider({
|
|||||||
) => T[] = useCallback(
|
) => T[] = useCallback(
|
||||||
(arr, index, newQueryItem) =>
|
(arr, index, newQueryItem) =>
|
||||||
arr.map((item, idx) => (index === idx ? newQueryItem : item)),
|
arr.map((item, idx) => (index === idx ? newQueryItem : item)),
|
||||||
|
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -465,7 +472,7 @@ export function QueryBuilderProvider({
|
|||||||
|
|
||||||
history.push(generatedUrl);
|
history.push(generatedUrl);
|
||||||
},
|
},
|
||||||
[history, location, urlQuery],
|
[history, location.pathname, urlQuery],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSetConfig = useCallback(
|
const handleSetConfig = useCallback(
|
||||||
@ -477,8 +484,24 @@ export function QueryBuilderProvider({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleRunQuery = useCallback(() => {
|
const handleRunQuery = useCallback(() => {
|
||||||
redirectWithQueryBuilderData({ ...currentQuery, queryType });
|
redirectWithQueryBuilderData({
|
||||||
}, [redirectWithQueryBuilderData, currentQuery, queryType]);
|
...{
|
||||||
|
...currentQuery,
|
||||||
|
...updateStepInterval(
|
||||||
|
{
|
||||||
|
builder: currentQuery.builder,
|
||||||
|
clickhouse_sql: currentQuery.clickhouse_sql,
|
||||||
|
promql: currentQuery.promql,
|
||||||
|
id: currentQuery.id,
|
||||||
|
queryType,
|
||||||
|
},
|
||||||
|
maxTime,
|
||||||
|
minTime,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
queryType,
|
||||||
|
});
|
||||||
|
}, [currentQuery, queryType, maxTime, minTime, redirectWithQueryBuilderData]);
|
||||||
|
|
||||||
const resetStagedQuery = useCallback(() => {
|
const resetStagedQuery = useCallback(() => {
|
||||||
setStagedQuery(null);
|
setStagedQuery(null);
|
||||||
@ -541,6 +564,7 @@ export function QueryBuilderProvider({
|
|||||||
handleRunQuery,
|
handleRunQuery,
|
||||||
resetStagedQuery,
|
resetStagedQuery,
|
||||||
updateAllQueriesOperators,
|
updateAllQueriesOperators,
|
||||||
|
initQueryBuilderData,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
query,
|
query,
|
||||||
@ -561,6 +585,7 @@ export function QueryBuilderProvider({
|
|||||||
handleRunQuery,
|
handleRunQuery,
|
||||||
resetStagedQuery,
|
resetStagedQuery,
|
||||||
updateAllQueriesOperators,
|
updateAllQueriesOperators,
|
||||||
|
initQueryBuilderData,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3,18 +3,19 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
import { getMetricsQueryRange } from 'api/metrics/getQueryRange';
|
import { getMetricsQueryRange } from 'api/metrics/getQueryRange';
|
||||||
|
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||||
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
|
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
|
||||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||||
|
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
|
||||||
import getStep from 'lib/getStep';
|
import getStep from 'lib/getStep';
|
||||||
|
import { convertNewDataToOld } from 'lib/newQueryBuilder/convertNewDataToOld';
|
||||||
import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi';
|
import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi';
|
||||||
import { isEmpty } from 'lodash-es';
|
import { isEmpty } from 'lodash-es';
|
||||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
import store from 'store';
|
||||||
import { SuccessResponse } from 'types/api';
|
import { SuccessResponse } from 'types/api';
|
||||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
|
||||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
|
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import { convertNewDataToOld } from 'lib/newQueryBuilder/convertNewDataToOld';
|
|
||||||
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
|
|
||||||
|
|
||||||
export async function GetMetricQueryRange({
|
export async function GetMetricQueryRange({
|
||||||
query,
|
query,
|
||||||
@ -89,7 +90,11 @@ export async function GetMetricQueryRange({
|
|||||||
const response = await getMetricsQueryRange({
|
const response = await getMetricsQueryRange({
|
||||||
start: parseInt(start, 10) * 1e3,
|
start: parseInt(start, 10) * 1e3,
|
||||||
end: parseInt(end, 10) * 1e3,
|
end: parseInt(end, 10) * 1e3,
|
||||||
step: getStep({ start, end, inputFormat: 'ms' }),
|
step: getStep({
|
||||||
|
start: store.getState().globalTime.minTime,
|
||||||
|
end: store.getState().globalTime.maxTime,
|
||||||
|
inputFormat: 'ns',
|
||||||
|
}),
|
||||||
variables,
|
variables,
|
||||||
...QueryPayload,
|
...QueryPayload,
|
||||||
...params,
|
...params,
|
||||||
|
@ -4,6 +4,7 @@ import { AxiosError } from 'axios';
|
|||||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import { ITEMS } from 'container/NewDashboard/ComponentsSlider/menuItems';
|
import { ITEMS } from 'container/NewDashboard/ComponentsSlider/menuItems';
|
||||||
|
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { Layout } from 'react-grid-layout';
|
import { Layout } from 'react-grid-layout';
|
||||||
import { generatePath } from 'react-router-dom';
|
import { generatePath } from 'react-router-dom';
|
||||||
@ -88,9 +89,10 @@ export const SaveDashboard = ({
|
|||||||
const allLayout = getAllLayout();
|
const allLayout = getAllLayout();
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
const compositeQuery = params.get(COMPOSITE_QUERY);
|
const compositeQuery = params.get(COMPOSITE_QUERY);
|
||||||
|
const { maxTime, minTime } = store.getState().globalTime;
|
||||||
const query = compositeQuery
|
const query = compositeQuery
|
||||||
? JSON.parse(compositeQuery)
|
? updateStepInterval(JSON.parse(compositeQuery), maxTime, minTime)
|
||||||
: selectedWidget.query;
|
: updateStepInterval(selectedWidget.query, maxTime, minTime);
|
||||||
|
|
||||||
const response = await updateDashboardApi({
|
const response = await updateDashboardApi({
|
||||||
data: {
|
data: {
|
||||||
|
@ -192,6 +192,7 @@ export type QueryBuilderContextType = {
|
|||||||
panelType: GRAPH_TYPES,
|
panelType: GRAPH_TYPES,
|
||||||
dataSource: DataSource,
|
dataSource: DataSource,
|
||||||
) => Query;
|
) => Query;
|
||||||
|
initQueryBuilderData: (query: Query) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type QueryAdditionalFilter = {
|
export type QueryAdditionalFilter = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user