mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-15 19:35:53 +08:00
feat: add share url (#2778)
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
parent
7fd27ec09d
commit
ad5a9dcd6a
@ -8,6 +8,7 @@ import {
|
||||
IBuilderQuery,
|
||||
IClickHouseQuery,
|
||||
IPromQLQuery,
|
||||
Query,
|
||||
QueryState,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
@ -158,6 +159,11 @@ export const initialQuery: QueryState = {
|
||||
promql: [initialQueryPromQLData],
|
||||
};
|
||||
|
||||
export const initialQueryWithType: Query = {
|
||||
...initialQuery,
|
||||
queryType: EQueryType.QUERY_BUILDER,
|
||||
};
|
||||
|
||||
export const operatorsByTypes: Record<LocalDataType, string[]> = {
|
||||
string: Object.values(StringOperators),
|
||||
number: Object.values(NumberOperators),
|
||||
|
1
frontend/src/constants/queryBuilderQueryNames.ts
Normal file
1
frontend/src/constants/queryBuilderQueryNames.ts
Normal file
@ -0,0 +1 @@
|
||||
export const COMPOSITE_QUERY = 'compositeQuery';
|
@ -1,5 +1,6 @@
|
||||
import {
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryPromQLData,
|
||||
PANEL_TYPES,
|
||||
} from 'constants/queryBuilder';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
@ -31,11 +32,9 @@ export const alertDefaults: AlertDef = {
|
||||
condition: {
|
||||
compositeQuery: {
|
||||
builderQueries: {
|
||||
A: {
|
||||
...initialQueryBuilderFormValues,
|
||||
A: initialQueryBuilderFormValues,
|
||||
},
|
||||
},
|
||||
promQueries: {},
|
||||
promQueries: { A: initialQueryPromQLData },
|
||||
chQueries: {
|
||||
A: {
|
||||
name: 'A',
|
||||
@ -69,7 +68,7 @@ export const logAlertDefaults: AlertDef = {
|
||||
dataSource: DataSource.LOGS,
|
||||
},
|
||||
},
|
||||
promQueries: {},
|
||||
promQueries: { A: initialQueryPromQLData },
|
||||
chQueries: {
|
||||
A: {
|
||||
name: 'A',
|
||||
@ -104,7 +103,7 @@ export const traceAlertDefaults: AlertDef = {
|
||||
dataSource: DataSource.TRACES,
|
||||
},
|
||||
},
|
||||
promQueries: {},
|
||||
promQueries: { A: initialQueryPromQLData },
|
||||
chQueries: {
|
||||
A: {
|
||||
name: 'A',
|
||||
@ -139,7 +138,7 @@ export const exceptionAlertDefaults: AlertDef = {
|
||||
dataSource: DataSource.TRACES,
|
||||
},
|
||||
},
|
||||
promQueries: {},
|
||||
promQueries: { A: initialQueryPromQLData },
|
||||
chQueries: {
|
||||
A: {
|
||||
name: 'A',
|
||||
@ -162,3 +161,10 @@ export const exceptionAlertDefaults: AlertDef = {
|
||||
annotations: defaultAnnotations,
|
||||
evalWindow: defaultEvalWindow,
|
||||
};
|
||||
|
||||
export const ALERTS_VALUES_MAP: Record<AlertTypes, AlertDef> = {
|
||||
[AlertTypes.METRICS_BASED_ALERT]: alertDefaults,
|
||||
[AlertTypes.LOGS_BASED_ALERT]: logAlertDefaults,
|
||||
[AlertTypes.TRACES_BASED_ALERT]: traceAlertDefaults,
|
||||
[AlertTypes.EXCEPTIONS_BASED_ALERT]: exceptionAlertDefaults,
|
||||
};
|
||||
|
@ -1,10 +1,16 @@
|
||||
import { Form, Row } from 'antd';
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import FormAlertRules from 'container/FormAlertRules';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
|
||||
import { useState } from 'react';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
import { AlertDef } from 'types/api/alerts/def';
|
||||
|
||||
import {
|
||||
alertDefaults,
|
||||
ALERTS_VALUES_MAP,
|
||||
exceptionAlertDefaults,
|
||||
logAlertDefaults,
|
||||
traceAlertDefaults,
|
||||
@ -12,13 +18,18 @@ import {
|
||||
import SelectAlertType from './SelectAlertType';
|
||||
|
||||
function CreateRules(): JSX.Element {
|
||||
const [initValues, setInitValues] = useState(alertDefaults);
|
||||
const [step, setStep] = useState(0);
|
||||
const [initValues, setInitValues] = useState<AlertDef>(alertDefaults);
|
||||
const [alertType, setAlertType] = useState<AlertTypes>(
|
||||
AlertTypes.METRICS_BASED_ALERT,
|
||||
);
|
||||
const [formInstance] = Form.useForm();
|
||||
|
||||
const urlQuery = useUrlQuery();
|
||||
|
||||
const compositeQuery = urlQuery.get(COMPOSITE_QUERY);
|
||||
|
||||
const { redirectWithQueryBuilderData } = useQueryBuilder();
|
||||
|
||||
const onSelectType = (typ: AlertTypes): void => {
|
||||
setAlertType(typ);
|
||||
switch (typ) {
|
||||
@ -34,16 +45,22 @@ function CreateRules(): JSX.Element {
|
||||
default:
|
||||
setInitValues(alertDefaults);
|
||||
}
|
||||
setStep(1);
|
||||
|
||||
const value = ALERTS_VALUES_MAP[typ].condition.compositeQuery;
|
||||
|
||||
const compositeQuery = mapQueryDataFromApi(value);
|
||||
|
||||
redirectWithQueryBuilderData(compositeQuery);
|
||||
};
|
||||
|
||||
if (step === 0) {
|
||||
if (!compositeQuery) {
|
||||
return (
|
||||
<Row wrap={false}>
|
||||
<SelectAlertType onSelect={onSelectType} />
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FormAlertRules
|
||||
alertType={alertType}
|
||||
|
@ -7,11 +7,13 @@ import ROUTES from 'constants/routes';
|
||||
import QueryTypeTag from 'container/NewWidget/LeftContainer/QueryTypeTag';
|
||||
import PlotTag from 'container/NewWidget/LeftContainer/WidgetGraph/PlotTag';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import history from 'lib/history';
|
||||
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
|
||||
import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
@ -35,7 +37,7 @@ import {
|
||||
StyledLeftContainer,
|
||||
} from './styles';
|
||||
import UserGuide from './UserGuide';
|
||||
import { prepareStagedQuery, toChartInterval } from './utils';
|
||||
import { toChartInterval } from './utils';
|
||||
|
||||
function FormAlertRules({
|
||||
alertType,
|
||||
@ -46,12 +48,7 @@ function FormAlertRules({
|
||||
// init namespace for translations
|
||||
const { t } = useTranslation('alerts');
|
||||
|
||||
const {
|
||||
currentQuery,
|
||||
queryType,
|
||||
handleSetQueryType,
|
||||
initQueryBuilderData,
|
||||
} = useQueryBuilder();
|
||||
const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder();
|
||||
|
||||
// use query client
|
||||
const ruleCache = useQueryClient();
|
||||
@ -62,7 +59,11 @@ function FormAlertRules({
|
||||
const [alertDef, setAlertDef] = useState<AlertDef>(initialValue);
|
||||
|
||||
// initQuery contains initial query when component was mounted
|
||||
const initQuery = initialValue.condition.compositeQuery;
|
||||
const initQuery = useMemo(() => initialValue.condition.compositeQuery, [
|
||||
initialValue,
|
||||
]);
|
||||
|
||||
const sq = useMemo(() => mapQueryDataFromApi(initQuery), [initQuery]);
|
||||
|
||||
// manualStagedQuery requires manual staging of query
|
||||
// when user clicks run query button. Useful for clickhouse tab where
|
||||
@ -73,26 +74,26 @@ function FormAlertRules({
|
||||
// other queries based on server data.
|
||||
// useful when fetching of initial values (from api)
|
||||
// is delayed
|
||||
|
||||
const { compositeQuery } = useShareBuilderUrl({ defaultValue: sq });
|
||||
|
||||
useEffect(() => {
|
||||
const type = initQuery.queryType;
|
||||
|
||||
// prepare staged query
|
||||
const sq = prepareStagedQuery(
|
||||
type,
|
||||
initQuery?.builderQueries,
|
||||
initQuery?.promQueries,
|
||||
initQuery?.chQueries,
|
||||
);
|
||||
|
||||
initQueryBuilderData(sq, type);
|
||||
|
||||
setManualStagedQuery(sq);
|
||||
|
||||
if (compositeQuery && !manualStagedQuery) {
|
||||
setManualStagedQuery(compositeQuery);
|
||||
}
|
||||
setAlertDef(initialValue);
|
||||
}, [initialValue, initQueryBuilderData, initQuery]);
|
||||
}, [
|
||||
initialValue,
|
||||
initQuery,
|
||||
redirectWithQueryBuilderData,
|
||||
currentQuery,
|
||||
manualStagedQuery,
|
||||
compositeQuery,
|
||||
]);
|
||||
|
||||
const onRunQuery = (): void => {
|
||||
setManualStagedQuery({ ...currentQuery, queryType });
|
||||
setManualStagedQuery(currentQuery);
|
||||
redirectWithQueryBuilderData(currentQuery);
|
||||
};
|
||||
|
||||
const onCancelHandler = useCallback(() => {
|
||||
@ -102,7 +103,6 @@ function FormAlertRules({
|
||||
// onQueryCategoryChange handles changes to query category
|
||||
// in state as well as sets additional defaults
|
||||
const onQueryCategoryChange = (val: EQueryType): void => {
|
||||
handleSetQueryType(val);
|
||||
if (val === EQueryType.PROM) {
|
||||
setAlertDef({
|
||||
...alertDef,
|
||||
@ -113,14 +113,17 @@ function FormAlertRules({
|
||||
evalWindow: defaultEvalWindow,
|
||||
});
|
||||
}
|
||||
const query: Query = { ...currentQuery, queryType: val };
|
||||
|
||||
setManualStagedQuery({ ...currentQuery, queryType: val });
|
||||
setManualStagedQuery(query);
|
||||
|
||||
redirectWithQueryBuilderData(query);
|
||||
};
|
||||
const { notifications } = useNotifications();
|
||||
|
||||
const validatePromParams = useCallback((): boolean => {
|
||||
let retval = true;
|
||||
if (queryType !== EQueryType.PROM) return retval;
|
||||
if (currentQuery.queryType !== EQueryType.PROM) return retval;
|
||||
|
||||
if (!currentQuery.promql || currentQuery.promql.length === 0) {
|
||||
notifications.error({
|
||||
@ -141,11 +144,11 @@ function FormAlertRules({
|
||||
});
|
||||
|
||||
return retval;
|
||||
}, [t, currentQuery, queryType, notifications]);
|
||||
}, [t, currentQuery, notifications]);
|
||||
|
||||
const validateChQueryParams = useCallback((): boolean => {
|
||||
let retval = true;
|
||||
if (queryType !== EQueryType.CLICKHOUSE) return retval;
|
||||
if (currentQuery.queryType !== EQueryType.CLICKHOUSE) return retval;
|
||||
|
||||
if (
|
||||
!currentQuery.clickhouse_sql ||
|
||||
@ -169,10 +172,10 @@ function FormAlertRules({
|
||||
});
|
||||
|
||||
return retval;
|
||||
}, [t, queryType, currentQuery, notifications]);
|
||||
}, [t, currentQuery, notifications]);
|
||||
|
||||
const validateQBParams = useCallback((): boolean => {
|
||||
if (queryType !== EQueryType.QUERY_BUILDER) return true;
|
||||
if (currentQuery.queryType !== EQueryType.QUERY_BUILDER) return true;
|
||||
|
||||
if (
|
||||
!currentQuery.builder.queryData ||
|
||||
@ -194,7 +197,7 @@ function FormAlertRules({
|
||||
}
|
||||
|
||||
return true;
|
||||
}, [t, alertDef, queryType, currentQuery, notifications]);
|
||||
}, [t, alertDef, currentQuery, notifications]);
|
||||
|
||||
const isFormValid = useCallback((): boolean => {
|
||||
if (!alertDef.alert || alertDef.alert === '') {
|
||||
@ -228,7 +231,10 @@ function FormAlertRules({
|
||||
...alertDef,
|
||||
alertType,
|
||||
source: window?.location.toString(),
|
||||
ruleType: queryType === EQueryType.PROM ? 'promql_rule' : 'threshold_rule',
|
||||
ruleType:
|
||||
currentQuery.queryType === EQueryType.PROM
|
||||
? 'promql_rule'
|
||||
: 'threshold_rule',
|
||||
condition: {
|
||||
...alertDef.condition,
|
||||
compositeQuery: {
|
||||
@ -239,7 +245,7 @@ function FormAlertRules({
|
||||
},
|
||||
promQueries: mapQueryDataToApi(currentQuery.promql, 'name').data,
|
||||
chQueries: mapQueryDataToApi(currentQuery.clickhouse_sql, 'name').data,
|
||||
queryType,
|
||||
queryType: currentQuery.queryType,
|
||||
panelType: initQuery.panelType,
|
||||
},
|
||||
},
|
||||
@ -248,7 +254,6 @@ function FormAlertRules({
|
||||
};
|
||||
|
||||
const memoizedPreparePostData = useCallback(preparePostData, [
|
||||
queryType,
|
||||
currentQuery,
|
||||
alertDef,
|
||||
alertType,
|
||||
@ -313,7 +318,8 @@ function FormAlertRules({
|
||||
const content = (
|
||||
<Typography.Text>
|
||||
{' '}
|
||||
{t('confirm_save_content_part1')} <QueryTypeTag queryType={queryType} />{' '}
|
||||
{t('confirm_save_content_part1')}{' '}
|
||||
<QueryTypeTag queryType={currentQuery.queryType} />{' '}
|
||||
{t('confirm_save_content_part2')}
|
||||
</Typography.Text>
|
||||
);
|
||||
@ -326,7 +332,7 @@ function FormAlertRules({
|
||||
saveRule();
|
||||
},
|
||||
});
|
||||
}, [t, saveRule, queryType]);
|
||||
}, [t, saveRule, currentQuery]);
|
||||
|
||||
const onTestRuleHandler = useCallback(async () => {
|
||||
if (!isFormValid()) {
|
||||
@ -372,7 +378,7 @@ function FormAlertRules({
|
||||
|
||||
const renderQBChartPreview = (): JSX.Element => (
|
||||
<ChartPreview
|
||||
headline={<PlotTag queryType={queryType} />}
|
||||
headline={<PlotTag queryType={currentQuery.queryType} />}
|
||||
name=""
|
||||
threshold={alertDef.condition?.target}
|
||||
query={manualStagedQuery}
|
||||
@ -382,7 +388,7 @@ function FormAlertRules({
|
||||
|
||||
const renderPromChartPreview = (): JSX.Element => (
|
||||
<ChartPreview
|
||||
headline={<PlotTag queryType={queryType} />}
|
||||
headline={<PlotTag queryType={currentQuery.queryType} />}
|
||||
name="Chart Preview"
|
||||
threshold={alertDef.condition?.target}
|
||||
query={manualStagedQuery}
|
||||
@ -391,7 +397,7 @@ function FormAlertRules({
|
||||
|
||||
const renderChQueryChartPreview = (): JSX.Element => (
|
||||
<ChartPreview
|
||||
headline={<PlotTag queryType={queryType} />}
|
||||
headline={<PlotTag queryType={currentQuery.queryType} />}
|
||||
name="Chart Preview"
|
||||
threshold={alertDef.condition?.target}
|
||||
query={manualStagedQuery}
|
||||
@ -402,7 +408,9 @@ function FormAlertRules({
|
||||
const isNewRule = ruleId === 0;
|
||||
|
||||
const isAlertAvialableToSave =
|
||||
isAlertAvialable && isNewRule && queryType === EQueryType.QUERY_BUILDER;
|
||||
isAlertAvialable &&
|
||||
isNewRule &&
|
||||
currentQuery.queryType === EQueryType.QUERY_BUILDER;
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -414,18 +422,20 @@ function FormAlertRules({
|
||||
layout="vertical"
|
||||
form={formInstance}
|
||||
>
|
||||
{queryType === EQueryType.QUERY_BUILDER && renderQBChartPreview()}
|
||||
{queryType === EQueryType.PROM && renderPromChartPreview()}
|
||||
{queryType === EQueryType.CLICKHOUSE && renderChQueryChartPreview()}
|
||||
{currentQuery.queryType === EQueryType.QUERY_BUILDER &&
|
||||
renderQBChartPreview()}
|
||||
{currentQuery.queryType === EQueryType.PROM && renderPromChartPreview()}
|
||||
{currentQuery.queryType === EQueryType.CLICKHOUSE &&
|
||||
renderChQueryChartPreview()}
|
||||
<QuerySection
|
||||
queryCategory={queryType}
|
||||
queryCategory={currentQuery.queryType}
|
||||
setQueryCategory={onQueryCategoryChange}
|
||||
alertType={alertType || AlertTypes.METRICS_BASED_ALERT}
|
||||
runQuery={onRunQuery}
|
||||
/>
|
||||
|
||||
<RuleOptions
|
||||
queryCategory={queryType}
|
||||
queryCategory={currentQuery.queryType}
|
||||
alertDef={alertDef}
|
||||
setAlertDef={setAlertDef}
|
||||
/>
|
||||
@ -464,7 +474,7 @@ function FormAlertRules({
|
||||
</MainFormContainer>
|
||||
</StyledLeftContainer>
|
||||
<Col flex="1 1 300px">
|
||||
<UserGuide queryType={queryType} />
|
||||
<UserGuide queryType={currentQuery.queryType} />
|
||||
</Col>
|
||||
</PanelContainer>
|
||||
</>
|
||||
|
@ -1,43 +1,4 @@
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
|
||||
import {
|
||||
BuilderClickHouseResource,
|
||||
BuilderPromQLResource,
|
||||
BuilderQueryDataResourse,
|
||||
IClickHouseQuery,
|
||||
IPromQLQuery,
|
||||
Query,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
export const prepareStagedQuery = (
|
||||
t: EQueryType,
|
||||
b: BuilderQueryDataResourse,
|
||||
p: BuilderPromQLResource,
|
||||
c: BuilderClickHouseResource,
|
||||
): Query => {
|
||||
const promList: IPromQLQuery[] = [];
|
||||
const chQueryList: IClickHouseQuery[] = [];
|
||||
|
||||
const builder = mapQueryDataFromApi(b);
|
||||
if (p) {
|
||||
Object.keys(p).forEach((key) => {
|
||||
promList.push({ ...p[key], name: key });
|
||||
});
|
||||
}
|
||||
if (c) {
|
||||
Object.keys(c).forEach((key) => {
|
||||
chQueryList.push({ ...c[key], name: key, rawQuery: c[key].query });
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
queryType: t,
|
||||
promql: promList,
|
||||
builder,
|
||||
clickhouse_sql: chQueryList,
|
||||
};
|
||||
};
|
||||
|
||||
// toChartInterval converts eval window to chart selection time interval
|
||||
export const toChartInterval = (evalWindow: string | undefined): Time => {
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
import { Dropdown, MenuProps, Tooltip, Typography } from 'antd';
|
||||
import { MenuItemType } from 'antd/es/menu/hooks/useItems';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import useComponentPermission from 'hooks/useComponentPermission';
|
||||
import history from 'lib/history';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
@ -58,9 +59,11 @@ function WidgetHeader({
|
||||
const onEditHandler = useCallback((): void => {
|
||||
const widgetId = widget.id;
|
||||
history.push(
|
||||
`${window.location.pathname}/new?widgetId=${widgetId}&graphType=${widget.panelTypes}`,
|
||||
`${window.location.pathname}/new?widgetId=${widgetId}&graphType=${
|
||||
widget.panelTypes
|
||||
}&${COMPOSITE_QUERY}=${JSON.stringify(widget.query)}`,
|
||||
);
|
||||
}, [widget.id, widget.panelTypes]);
|
||||
}, [widget.id, widget.panelTypes, widget.query]);
|
||||
|
||||
const keyMethodMapping: {
|
||||
[K in TWidgetOptions]: { key: TWidgetOptions; method: VoidFunction };
|
||||
|
@ -4,11 +4,13 @@ import { Typography } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import TextToolTip from 'components/TextToolTip';
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import ROUTES from 'constants/routes';
|
||||
import useComponentPermission from 'hooks/useComponentPermission';
|
||||
import useInterval from 'hooks/useInterval';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import history from 'lib/history';
|
||||
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { UseQueryResult } from 'react-query';
|
||||
@ -65,11 +67,19 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
.catch(handleError);
|
||||
}, [featureResponse, handleError]);
|
||||
|
||||
const onEditHandler = (id: string): void => {
|
||||
const onEditHandler = (record: GettableAlert): void => {
|
||||
featureResponse
|
||||
.refetch()
|
||||
.then(() => {
|
||||
history.push(`${ROUTES.EDIT_ALERTS}?ruleId=${id}`);
|
||||
const compositeQuery = mapQueryDataFromApi(record.condition.compositeQuery);
|
||||
|
||||
history.push(
|
||||
`${
|
||||
ROUTES.EDIT_ALERTS
|
||||
}?ruleId=${record.id.toString()}&${COMPOSITE_QUERY}=${JSON.stringify(
|
||||
compositeQuery,
|
||||
)}`,
|
||||
);
|
||||
})
|
||||
.catch(handleError);
|
||||
};
|
||||
@ -94,9 +104,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
(a.alert ? a.alert.charCodeAt(0) : 1000) -
|
||||
(b.alert ? b.alert.charCodeAt(0) : 1000),
|
||||
render: (value, record): JSX.Element => (
|
||||
<Typography.Link
|
||||
onClick={(): void => onEditHandler(record.id ? record.id.toString() : '')}
|
||||
>
|
||||
<Typography.Link onClick={(): void => onEditHandler(record)}>
|
||||
{value}
|
||||
</Typography.Link>
|
||||
),
|
||||
@ -154,10 +162,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
<>
|
||||
<ToggleAlertState disabled={record.disabled} setData={setData} id={id} />
|
||||
|
||||
<ColumnButton
|
||||
onClick={(): void => onEditHandler(id.toString())}
|
||||
type="link"
|
||||
>
|
||||
<ColumnButton onClick={(): void => onEditHandler(record)} type="link">
|
||||
Edit
|
||||
</ColumnButton>
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import { initialQueryWithType } from 'constants/queryBuilder';
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import history from 'lib/history';
|
||||
@ -43,7 +45,9 @@ function DashboardGraphSlider({ toggleAddWidget }: Props): JSX.Element {
|
||||
toggleAddWidget(false);
|
||||
|
||||
history.push(
|
||||
`${history.location.pathname}/new?graphType=${name}&widgetId=${emptyLayout.i}`,
|
||||
`${history.location.pathname}/new?graphType=${name}&widgetId=${
|
||||
emptyLayout.i
|
||||
}&${COMPOSITE_QUERY}=${JSON.stringify(initialQueryWithType)}`,
|
||||
);
|
||||
} catch (error) {
|
||||
notifications.error({
|
||||
|
@ -3,9 +3,10 @@ import TextToolTip from 'components/TextToolTip';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { QueryBuilder } from 'container/QueryBuilder';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import {
|
||||
@ -15,6 +16,7 @@ import {
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import DashboardReducer from 'types/reducer/dashboards';
|
||||
|
||||
@ -22,12 +24,10 @@ import ClickHouseQueryContainer from './QueryBuilder/clickHouse';
|
||||
import PromQLQueryContainer from './QueryBuilder/promQL';
|
||||
|
||||
function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
|
||||
const {
|
||||
currentQuery,
|
||||
queryType,
|
||||
handleSetQueryType,
|
||||
initQueryBuilderData,
|
||||
} = useQueryBuilder();
|
||||
const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder();
|
||||
const urlQuery = useUrlQuery();
|
||||
|
||||
const [isInit, setIsInit] = useState<boolean>(false);
|
||||
|
||||
const { dashboards, isLoadingQueryResult } = useSelector<
|
||||
AppState,
|
||||
@ -35,11 +35,8 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
|
||||
>((state) => state.dashboards);
|
||||
|
||||
const [selectedDashboards] = dashboards;
|
||||
const { search } = useLocation();
|
||||
const { widgets } = selectedDashboards.data;
|
||||
|
||||
const urlQuery = useMemo(() => new URLSearchParams(search), [search]);
|
||||
|
||||
const getWidget = useCallback(() => {
|
||||
const widgetId = urlQuery.get('widgetId');
|
||||
return widgets?.find((e) => e.id === widgetId);
|
||||
@ -47,32 +44,43 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
|
||||
|
||||
const selectedWidget = getWidget() as Widgets;
|
||||
|
||||
const { query } = selectedWidget || {};
|
||||
const { query } = selectedWidget;
|
||||
|
||||
const { compositeQuery } = useShareBuilderUrl({ defaultValue: query });
|
||||
|
||||
useEffect(() => {
|
||||
initQueryBuilderData(query, selectedWidget.query.queryType);
|
||||
}, [query, initQueryBuilderData, selectedWidget]);
|
||||
|
||||
const handleStageQuery = (): void => {
|
||||
if (!isInit && compositeQuery) {
|
||||
setIsInit(true);
|
||||
updateQuery({
|
||||
updatedQuery: {
|
||||
...currentQuery,
|
||||
queryType,
|
||||
},
|
||||
updatedQuery: compositeQuery,
|
||||
widgetId: urlQuery.get('widgetId') || '',
|
||||
yAxisUnit: selectedWidget.yAxisUnit,
|
||||
});
|
||||
};
|
||||
}
|
||||
}, [isInit, compositeQuery, selectedWidget, urlQuery, updateQuery]);
|
||||
|
||||
const handleStageQuery = useCallback(
|
||||
(updatedQuery: Query): void => {
|
||||
updateQuery({
|
||||
updatedQuery,
|
||||
widgetId: urlQuery.get('widgetId') || '',
|
||||
yAxisUnit: selectedWidget.yAxisUnit,
|
||||
});
|
||||
|
||||
redirectWithQueryBuilderData(updatedQuery);
|
||||
},
|
||||
|
||||
[urlQuery, selectedWidget, updateQuery, redirectWithQueryBuilderData],
|
||||
);
|
||||
|
||||
const handleQueryCategoryChange = (qCategory: string): void => {
|
||||
const currentQueryType = qCategory as EQueryType;
|
||||
|
||||
handleSetQueryType(currentQueryType);
|
||||
updateQuery({
|
||||
updatedQuery: { ...currentQuery, queryType: currentQueryType },
|
||||
widgetId: urlQuery.get('widgetId') || '',
|
||||
yAxisUnit: selectedWidget.yAxisUnit,
|
||||
});
|
||||
handleStageQuery({ ...currentQuery, queryType: currentQueryType });
|
||||
};
|
||||
|
||||
const handleRunQuery = (): void => {
|
||||
handleStageQuery(currentQuery);
|
||||
};
|
||||
|
||||
const items = [
|
||||
@ -100,8 +108,8 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
|
||||
<Tabs
|
||||
type="card"
|
||||
style={{ width: '100%' }}
|
||||
defaultActiveKey={queryType}
|
||||
activeKey={queryType}
|
||||
defaultActiveKey={currentQuery.queryType}
|
||||
activeKey={currentQuery.queryType}
|
||||
onChange={handleQueryCategoryChange}
|
||||
tabBarExtraContent={
|
||||
<span style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
|
||||
@ -109,7 +117,7 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
|
||||
<Button
|
||||
loading={isLoadingQueryResult}
|
||||
type="primary"
|
||||
onClick={handleStageQuery}
|
||||
onClick={handleRunQuery}
|
||||
>
|
||||
Stage & Run Query
|
||||
</Button>
|
||||
|
@ -1,11 +1,13 @@
|
||||
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 { 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';
|
||||
@ -47,6 +49,7 @@ function NewWidget({
|
||||
saveSettingOfPanel,
|
||||
getQueryResults,
|
||||
}: Props): JSX.Element {
|
||||
const urlQuery = useUrlQuery();
|
||||
const dispatch = useDispatch();
|
||||
const { dashboards } = useSelector<AppState, DashboardReducer>(
|
||||
(state) => state.dashboards,
|
||||
@ -159,9 +162,10 @@ function NewWidget({
|
||||
}, [dashboardId, dispatch]);
|
||||
|
||||
const getQueryResult = useCallback(() => {
|
||||
if (selectedWidget?.id.length !== 0 && selectedWidget?.query) {
|
||||
const compositeQuery = urlQuery.get(COMPOSITE_QUERY);
|
||||
if ((selectedWidget?.id.length !== 0 && compositeQuery) || compositeQuery) {
|
||||
getQueryResults({
|
||||
query: selectedWidget?.query,
|
||||
query: JSON.parse(compositeQuery),
|
||||
selectedTime: selectedTime.enum,
|
||||
widgetId: selectedWidget?.id || '',
|
||||
graphType,
|
||||
@ -170,12 +174,12 @@ function NewWidget({
|
||||
});
|
||||
}
|
||||
}, [
|
||||
selectedWidget?.query,
|
||||
selectedTime.enum,
|
||||
selectedWidget?.id,
|
||||
getQueryResults,
|
||||
globalSelectedInterval,
|
||||
graphType,
|
||||
urlQuery,
|
||||
]);
|
||||
|
||||
const setGraphHandler = (type: ITEMS): void => {
|
||||
|
33
frontend/src/hooks/queryBuilder/useShareBuilderUrl.ts
Normal file
33
frontend/src/hooks/queryBuilder/useShareBuilderUrl.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import { useQueryBuilder } from './useQueryBuilder';
|
||||
|
||||
type UseShareBuilderUrlParams = { defaultValue: Query };
|
||||
type UseShareBuilderUrlReturnType = { compositeQuery: Query | null };
|
||||
|
||||
export const useShareBuilderUrl = ({
|
||||
defaultValue,
|
||||
}: UseShareBuilderUrlParams): UseShareBuilderUrlReturnType => {
|
||||
const { redirectWithQueryBuilderData } = useQueryBuilder();
|
||||
const urlQuery = useUrlQuery();
|
||||
|
||||
const compositeQuery: Query | null = useMemo(() => {
|
||||
const query = urlQuery.get(COMPOSITE_QUERY);
|
||||
if (query) {
|
||||
return JSON.parse(query);
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [urlQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!compositeQuery) {
|
||||
redirectWithQueryBuilderData(defaultValue);
|
||||
}
|
||||
}, [defaultValue, urlQuery, redirectWithQueryBuilderData, compositeQuery]);
|
||||
|
||||
return { compositeQuery };
|
||||
};
|
@ -1,27 +1,35 @@
|
||||
import { initialQueryBuilderFormValues } from 'constants/queryBuilder';
|
||||
import { FORMULA_REGEXP } from 'constants/regExp';
|
||||
import {
|
||||
BuilderQueryDataResourse,
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { QueryBuilderData } from 'types/common/queryBuilder';
|
||||
import { initialQuery } from 'constants/queryBuilder';
|
||||
import { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import { transformQueryBuilderDataModel } from '../transformQueryBuilderDataModel';
|
||||
|
||||
export const mapQueryDataFromApi = (
|
||||
data: BuilderQueryDataResourse,
|
||||
): QueryBuilderData => {
|
||||
const queryData: QueryBuilderData['queryData'] = [];
|
||||
const queryFormulas: QueryBuilderData['queryFormulas'] = [];
|
||||
compositeQuery: ICompositeMetricQuery,
|
||||
): Query => {
|
||||
const builder = compositeQuery.builderQueries
|
||||
? transformQueryBuilderDataModel(compositeQuery.builderQueries)
|
||||
: initialQuery.builder;
|
||||
|
||||
Object.entries(data).forEach(([, value]) => {
|
||||
if (FORMULA_REGEXP.test(value.queryName)) {
|
||||
const formula = value as IBuilderFormula;
|
||||
queryFormulas.push(formula);
|
||||
} else {
|
||||
const query = value as IBuilderQuery;
|
||||
queryData.push({ ...initialQueryBuilderFormValues, ...query });
|
||||
}
|
||||
});
|
||||
const promql = compositeQuery.promQueries
|
||||
? Object.keys(compositeQuery.promQueries).map((key) => ({
|
||||
...compositeQuery.promQueries[key],
|
||||
name: key,
|
||||
}))
|
||||
: initialQuery.promql;
|
||||
|
||||
return { queryData, queryFormulas };
|
||||
const clickhouseSql = compositeQuery.chQueries
|
||||
? Object.keys(compositeQuery.chQueries).map((key) => ({
|
||||
...compositeQuery.chQueries[key],
|
||||
name: key,
|
||||
rawQuery: compositeQuery.chQueries[key].query,
|
||||
}))
|
||||
: initialQuery.clickhouse_sql;
|
||||
|
||||
return {
|
||||
builder,
|
||||
promql,
|
||||
clickhouse_sql: clickhouseSql,
|
||||
queryType: compositeQuery.queryType,
|
||||
};
|
||||
};
|
||||
|
@ -0,0 +1,30 @@
|
||||
import {
|
||||
initialFormulaBuilderFormValues,
|
||||
initialQueryBuilderFormValues,
|
||||
} from 'constants/queryBuilder';
|
||||
import { FORMULA_REGEXP } from 'constants/regExp';
|
||||
import {
|
||||
BuilderQueryDataResourse,
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { QueryBuilderData } from 'types/common/queryBuilder';
|
||||
|
||||
export const transformQueryBuilderDataModel = (
|
||||
data: BuilderQueryDataResourse,
|
||||
): QueryBuilderData => {
|
||||
const queryData: QueryBuilderData['queryData'] = [];
|
||||
const queryFormulas: QueryBuilderData['queryFormulas'] = [];
|
||||
|
||||
Object.entries(data).forEach(([, value]) => {
|
||||
if (FORMULA_REGEXP.test(value.queryName)) {
|
||||
const formula = value as IBuilderFormula;
|
||||
queryFormulas.push({ ...initialFormulaBuilderFormValues, ...formula });
|
||||
} else {
|
||||
const query = value as IBuilderQuery;
|
||||
queryData.push({ ...initialQueryBuilderFormValues, ...query });
|
||||
}
|
||||
});
|
||||
|
||||
return { queryData, queryFormulas };
|
||||
};
|
28
frontend/src/lib/replaceIncorrectObjectFields.ts
Normal file
28
frontend/src/lib/replaceIncorrectObjectFields.ts
Normal file
@ -0,0 +1,28 @@
|
||||
export function replaceIncorrectObjectFields<
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
TargetValue extends object,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
ResultValue extends object
|
||||
>(
|
||||
targetObject: TargetValue,
|
||||
defaultObject: ResultValue,
|
||||
): { isValid: boolean; validData: ResultValue } {
|
||||
const targetObjectKeys = Object.keys(targetObject);
|
||||
const defaultObjectKeys = Object.keys(defaultObject);
|
||||
|
||||
let isValid = true;
|
||||
|
||||
const result: ResultValue = { ...defaultObject };
|
||||
|
||||
defaultObjectKeys.forEach((key) => {
|
||||
if (targetObjectKeys.includes(key)) {
|
||||
result[key as keyof ResultValue] = (targetObject[
|
||||
key as keyof TargetValue
|
||||
] as unknown) as ResultValue[keyof ResultValue];
|
||||
} else {
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
return { isValid, validData: result };
|
||||
}
|
@ -1,30 +1,39 @@
|
||||
import {
|
||||
alphabet,
|
||||
formulasNames,
|
||||
initialClickHouseData,
|
||||
initialFormulaBuilderFormValues,
|
||||
initialQuery,
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryPromQLData,
|
||||
initialQueryWithType,
|
||||
initialSingleQueryMap,
|
||||
MAX_FORMULAS,
|
||||
MAX_QUERIES,
|
||||
PANEL_TYPES,
|
||||
} from 'constants/queryBuilder';
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName';
|
||||
import { getOperatorsBySourceAndPanelType } from 'lib/newQueryBuilder/getOperatorsBySourceAndPanelType';
|
||||
import { replaceIncorrectObjectFields } from 'lib/replaceIncorrectObjectFields';
|
||||
import {
|
||||
createContext,
|
||||
PropsWithChildren,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
// ** Types
|
||||
import {
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
IClickHouseQuery,
|
||||
IPromQLQuery,
|
||||
Query,
|
||||
QueryState,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
@ -35,8 +44,7 @@ import {
|
||||
} from 'types/common/queryBuilder';
|
||||
|
||||
export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
||||
currentQuery: initialQuery,
|
||||
queryType: EQueryType.QUERY_BUILDER,
|
||||
currentQuery: initialQueryWithType,
|
||||
initialDataSource: null,
|
||||
panelType: PANEL_TYPES.TIME_SERIES,
|
||||
resetQueryBuilderData: () => {},
|
||||
@ -53,11 +61,16 @@ export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
||||
addNewBuilderQuery: () => {},
|
||||
addNewFormula: () => {},
|
||||
addNewQueryItem: () => {},
|
||||
redirectWithQueryBuilderData: () => {},
|
||||
});
|
||||
|
||||
export function QueryBuilderProvider({
|
||||
children,
|
||||
}: PropsWithChildren): JSX.Element {
|
||||
const urlQuery = useUrlQuery();
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
|
||||
const [initialDataSource, setInitialDataSource] = useState<DataSource | null>(
|
||||
null,
|
||||
);
|
||||
@ -85,13 +98,41 @@ export function QueryBuilderProvider({
|
||||
setCurrentQuery(initialQuery);
|
||||
}, []);
|
||||
|
||||
const initQueryBuilderData = useCallback(
|
||||
(query: QueryState, queryType: EQueryType): void => {
|
||||
setCurrentQuery(query);
|
||||
setQueryType(queryType);
|
||||
},
|
||||
[],
|
||||
);
|
||||
const initQueryBuilderData = useCallback((query: Partial<Query>): void => {
|
||||
const { queryType, ...queryState } = query;
|
||||
const builder: QueryBuilderData = {
|
||||
queryData: queryState.builder
|
||||
? queryState.builder.queryData.map((item) => ({
|
||||
...initialQueryBuilderFormValues,
|
||||
...item,
|
||||
}))
|
||||
: initialQuery.builder.queryData,
|
||||
queryFormulas: queryState.builder
|
||||
? queryState.builder.queryFormulas.map((item) => ({
|
||||
...initialFormulaBuilderFormValues,
|
||||
...item,
|
||||
}))
|
||||
: initialQuery.builder.queryFormulas,
|
||||
};
|
||||
|
||||
const promql: IPromQLQuery[] = queryState.promql
|
||||
? queryState.promql.map((item) => ({
|
||||
...initialQueryPromQLData,
|
||||
...item,
|
||||
}))
|
||||
: initialQuery.promql;
|
||||
|
||||
const clickHouse: IClickHouseQuery[] = queryState.clickhouse_sql
|
||||
? queryState.clickhouse_sql.map((item) => ({
|
||||
...initialClickHouseData,
|
||||
...item,
|
||||
}))
|
||||
: initialQuery.clickhouse_sql;
|
||||
|
||||
setCurrentQuery({ builder, clickhouse_sql: clickHouse, promql });
|
||||
|
||||
setQueryType(queryType || EQueryType.QUERY_BUILDER);
|
||||
}, []);
|
||||
|
||||
const removeQueryBuilderEntityByIndex = useCallback(
|
||||
(type: keyof QueryBuilderData, index: number) => {
|
||||
@ -316,10 +357,62 @@ export function QueryBuilderProvider({
|
||||
setPanelType(newPanelType);
|
||||
}, []);
|
||||
|
||||
const redirectWithQueryBuilderData = useCallback(
|
||||
(query: Partial<Query>) => {
|
||||
const currentGeneratedQuery: Query = {
|
||||
queryType:
|
||||
!query.queryType || !Object.values(EQueryType).includes(query.queryType)
|
||||
? EQueryType.QUERY_BUILDER
|
||||
: query.queryType,
|
||||
builder:
|
||||
!query.builder || query.builder.queryData.length === 0
|
||||
? initialQuery.builder
|
||||
: query.builder,
|
||||
promql:
|
||||
!query.promql || query.promql.length === 0
|
||||
? initialQuery.promql
|
||||
: query.promql,
|
||||
clickhouse_sql:
|
||||
!query.clickhouse_sql || query.clickhouse_sql.length === 0
|
||||
? initialQuery.clickhouse_sql
|
||||
: query.clickhouse_sql,
|
||||
};
|
||||
|
||||
urlQuery.set(COMPOSITE_QUERY, JSON.stringify(currentGeneratedQuery));
|
||||
|
||||
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
||||
|
||||
history.push(generatedUrl);
|
||||
},
|
||||
[history, location, urlQuery],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const compositeQuery = urlQuery.get(COMPOSITE_QUERY);
|
||||
if (!compositeQuery) return;
|
||||
|
||||
const newQuery: Query = JSON.parse(compositeQuery);
|
||||
|
||||
const { isValid, validData } = replaceIncorrectObjectFields(
|
||||
newQuery,
|
||||
initialQueryWithType,
|
||||
);
|
||||
|
||||
if (!isValid) {
|
||||
redirectWithQueryBuilderData(validData);
|
||||
} else {
|
||||
initQueryBuilderData(newQuery);
|
||||
}
|
||||
}, [initQueryBuilderData, redirectWithQueryBuilderData, urlQuery]);
|
||||
|
||||
const query: Query = useMemo(() => ({ ...currentQuery, queryType }), [
|
||||
currentQuery,
|
||||
queryType,
|
||||
]);
|
||||
|
||||
const contextValues: QueryBuilderContextType = useMemo(
|
||||
() => ({
|
||||
currentQuery,
|
||||
queryType,
|
||||
currentQuery: query,
|
||||
initialDataSource,
|
||||
panelType,
|
||||
resetQueryBuilderData,
|
||||
@ -336,12 +429,12 @@ export function QueryBuilderProvider({
|
||||
addNewBuilderQuery,
|
||||
addNewFormula,
|
||||
addNewQueryItem,
|
||||
redirectWithQueryBuilderData,
|
||||
}),
|
||||
[
|
||||
currentQuery,
|
||||
query,
|
||||
initialDataSource,
|
||||
panelType,
|
||||
queryType,
|
||||
resetQueryBuilderData,
|
||||
resetQueryBuilderInfo,
|
||||
handleSetQueryData,
|
||||
@ -356,6 +449,7 @@ export function QueryBuilderProvider({
|
||||
addNewBuilderQuery,
|
||||
addNewFormula,
|
||||
addNewQueryItem,
|
||||
redirectWithQueryBuilderData,
|
||||
],
|
||||
);
|
||||
|
||||
|
@ -1,15 +1,9 @@
|
||||
import getDashboard from 'api/dashboard/get';
|
||||
import {
|
||||
initialClickHouseData,
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryPromQLData,
|
||||
PANEL_TYPES,
|
||||
} from 'constants/queryBuilder';
|
||||
import { initialQueryWithType, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { Dispatch } from 'redux';
|
||||
import AppActions from 'types/actions';
|
||||
import { Props } from 'types/api/dashboard/get';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
export const GetDashboard = ({
|
||||
uuid,
|
||||
@ -55,15 +49,7 @@ export const GetDashboard = ({
|
||||
errorMessage: '',
|
||||
loading: false,
|
||||
},
|
||||
query: {
|
||||
queryType: EQueryType.QUERY_BUILDER,
|
||||
promql: [initialQueryPromQLData],
|
||||
clickhouse_sql: [initialClickHouseData],
|
||||
builder: {
|
||||
queryFormulas: [],
|
||||
queryData: [initialQueryBuilderFormValues],
|
||||
},
|
||||
},
|
||||
query: initialQueryWithType,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -84,8 +84,6 @@ export interface Query {
|
||||
|
||||
export type QueryState = Omit<Query, 'queryType'>;
|
||||
|
||||
export type BuilderQueryResource = Record<string, IBuilderQuery>;
|
||||
export type BuilderFormulaResource = Record<string, IBuilderFormula>;
|
||||
export type BuilderClickHouseResource = Record<string, IClickHouseQuery>;
|
||||
export type BuilderPromQLResource = Record<string, IPromQLQuery>;
|
||||
export type BuilderQueryDataResourse = Record<
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
IBuilderQuery,
|
||||
IClickHouseQuery,
|
||||
IPromQLQuery,
|
||||
QueryState,
|
||||
Query,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import { EQueryType } from './dashboard';
|
||||
@ -153,8 +153,7 @@ export type QueryBuilderData = {
|
||||
};
|
||||
|
||||
export type QueryBuilderContextType = {
|
||||
currentQuery: QueryState;
|
||||
queryType: EQueryType;
|
||||
currentQuery: Query;
|
||||
initialDataSource: DataSource | null;
|
||||
panelType: GRAPH_TYPES;
|
||||
resetQueryBuilderData: () => void;
|
||||
@ -168,7 +167,7 @@ export type QueryBuilderContextType = {
|
||||
) => void;
|
||||
handleSetPanelType: (newPanelType: GRAPH_TYPES) => void;
|
||||
handleSetQueryType: (newQueryType: EQueryType) => void;
|
||||
initQueryBuilderData: (query: QueryState, queryType: EQueryType) => void;
|
||||
initQueryBuilderData: (query: Partial<Query>) => void;
|
||||
setupInitialDataSource: (newInitialDataSource: DataSource | null) => void;
|
||||
removeQueryBuilderEntityByIndex: (
|
||||
type: keyof QueryBuilderData,
|
||||
@ -181,6 +180,7 @@ export type QueryBuilderContextType = {
|
||||
addNewBuilderQuery: () => void;
|
||||
addNewFormula: () => void;
|
||||
addNewQueryItem: (type: EQueryType.PROM | EQueryType.CLICKHOUSE) => void;
|
||||
redirectWithQueryBuilderData: (query: Query) => void;
|
||||
};
|
||||
|
||||
export type QueryAdditionalFilter = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user