mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-20 14:09:05 +08:00
Feat/extend query builder state (#2755)
* feat: extends query builder state * fix: correct import path for query type
This commit is contained in:
parent
1ded475b37
commit
818a984af3
@ -1,11 +0,0 @@
|
||||
export const PromQLQueryTemplate = {
|
||||
query: '',
|
||||
legend: '',
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
export const ClickHouseQueryTemplate = {
|
||||
rawQuery: '',
|
||||
legend: '',
|
||||
disabled: false,
|
||||
};
|
@ -6,7 +6,11 @@ import {
|
||||
HavingForm,
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
IClickHouseQuery,
|
||||
IPromQLQuery,
|
||||
QueryState,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import {
|
||||
BoolOperators,
|
||||
DataSource,
|
||||
@ -14,6 +18,7 @@ import {
|
||||
NumberOperators,
|
||||
PanelTypeKeys,
|
||||
QueryAdditionalFilter,
|
||||
QueryBuilderData,
|
||||
ReduceOperators,
|
||||
StringOperators,
|
||||
} from 'types/common/queryBuilder';
|
||||
@ -122,6 +127,37 @@ export const initialFormulaBuilderFormValues: IBuilderFormula = {
|
||||
legend: '',
|
||||
};
|
||||
|
||||
export const initialQueryPromQLData: IPromQLQuery = {
|
||||
name: createNewBuilderItemName({ existNames: [], sourceNames: alphabet }),
|
||||
query: '',
|
||||
legend: '',
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
export const initialClickHouseData: IClickHouseQuery = {
|
||||
name: createNewBuilderItemName({ existNames: [], sourceNames: alphabet }),
|
||||
rawQuery: '',
|
||||
legend: '',
|
||||
disabled: false,
|
||||
query: '',
|
||||
};
|
||||
|
||||
export const initialQueryBuilderData: QueryBuilderData = {
|
||||
queryData: [initialQueryBuilderFormValues],
|
||||
queryFormulas: [],
|
||||
};
|
||||
|
||||
export const initialSingleQueryMap: Record<
|
||||
EQueryType.PROM | EQueryType.CLICKHOUSE,
|
||||
IClickHouseQuery | IPromQLQuery
|
||||
> = { clickhouse_sql: initialClickHouseData, promql: initialQueryPromQLData };
|
||||
|
||||
export const initialQuery: QueryState = {
|
||||
builder: initialQueryBuilderData,
|
||||
clickhouse_sql: [initialClickHouseData],
|
||||
promql: [initialQueryPromQLData],
|
||||
};
|
||||
|
||||
export const operatorsByTypes: Record<LocalDataType, string[]> = {
|
||||
string: Object.values(StringOperators),
|
||||
number: Object.values(NumberOperators),
|
||||
|
@ -1,45 +1,17 @@
|
||||
import ClickHouseQueryBuilder from 'container/NewWidget/LeftContainer/QuerySection/QueryBuilder/clickHouse/query';
|
||||
import { IClickHouseQueryHandleChange } from 'container/NewWidget/LeftContainer/QuerySection/QueryBuilder/clickHouse/types';
|
||||
import { IChQueries } from 'types/api/alerts/compositeQuery';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
|
||||
import { rawQueryToIChQuery, toIClickHouseQuery } from './transform';
|
||||
|
||||
function ChQuerySection({
|
||||
chQueries,
|
||||
setChQueries,
|
||||
}: ChQuerySectionProps): JSX.Element {
|
||||
const handleChQueryChange = ({
|
||||
rawQuery,
|
||||
legend,
|
||||
toggleDelete,
|
||||
}: IClickHouseQueryHandleChange): void => {
|
||||
const chQuery = rawQueryToIChQuery(
|
||||
chQueries.A,
|
||||
rawQuery,
|
||||
legend,
|
||||
toggleDelete,
|
||||
);
|
||||
|
||||
setChQueries({
|
||||
A: {
|
||||
...chQuery,
|
||||
},
|
||||
});
|
||||
};
|
||||
function ChQuerySection(): JSX.Element {
|
||||
const { currentQuery } = useQueryBuilder();
|
||||
|
||||
return (
|
||||
<ClickHouseQueryBuilder
|
||||
key="A"
|
||||
queryIndex="A"
|
||||
queryData={toIClickHouseQuery(chQueries?.A)}
|
||||
handleQueryChange={handleChQueryChange}
|
||||
queryIndex={0}
|
||||
queryData={currentQuery.clickhouse_sql[0]}
|
||||
deletable={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface ChQuerySectionProps {
|
||||
chQueries: IChQueries;
|
||||
setChQueries: (q: IChQueries) => void;
|
||||
}
|
||||
|
||||
export default ChQuerySection;
|
||||
|
@ -1,39 +0,0 @@
|
||||
import { IChQuery } from 'types/api/alerts/compositeQuery';
|
||||
import { IClickHouseQuery } from 'types/api/dashboard/getAll';
|
||||
|
||||
// @description rawQueryToIChQuery transforms raw query (from ClickHouseQueryBuilder)
|
||||
// to alert specific IChQuery format
|
||||
export const rawQueryToIChQuery = (
|
||||
src: IChQuery,
|
||||
rawQuery: string | undefined,
|
||||
legend: string | undefined,
|
||||
toggleDelete: boolean | undefined,
|
||||
): IChQuery => {
|
||||
if (toggleDelete) {
|
||||
return {
|
||||
rawQuery: '',
|
||||
legend: '',
|
||||
name: 'A',
|
||||
disabled: false,
|
||||
query: '',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
rawQuery: rawQuery !== undefined ? rawQuery : src.query,
|
||||
query: rawQuery !== undefined ? rawQuery : src.query,
|
||||
legend: legend !== undefined ? legend : src.legend,
|
||||
name: 'A',
|
||||
disabled: false,
|
||||
};
|
||||
};
|
||||
|
||||
// @description toIClickHouseQuery transforms IChQuery (alert specific) to
|
||||
// ClickHouseQueryBuilder format. The main difference is
|
||||
// use of rawQuery (in ClickHouseQueryBuilder)
|
||||
// and query (in alert builder)
|
||||
export const toIClickHouseQuery = (src: IChQuery): IClickHouseQuery => ({
|
||||
...src,
|
||||
name: 'A',
|
||||
rawQuery: src.query,
|
||||
});
|
@ -11,7 +11,7 @@ import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery } from 'react-query';
|
||||
import { GetMetricQueryRange } from 'store/actions/dashboard/getQueryResults';
|
||||
import { Query } from 'types/api/dashboard/getAll';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
import { ChartContainer, FailedMessageContainer } from './styles';
|
||||
|
@ -1,48 +1,17 @@
|
||||
import PromQLQueryBuilder from 'container/NewWidget/LeftContainer/QuerySection/QueryBuilder/promQL/query';
|
||||
import { IPromQLQueryHandleChange } from 'container/NewWidget/LeftContainer/QuerySection/QueryBuilder/promQL/types';
|
||||
import { IPromQueries } from 'types/api/alerts/compositeQuery';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
|
||||
function PromqlSection({
|
||||
promQueries,
|
||||
setPromQueries,
|
||||
}: PromqlSectionProps): JSX.Element {
|
||||
const handlePromQLQueryChange = ({
|
||||
query,
|
||||
legend,
|
||||
toggleDelete,
|
||||
}: IPromQLQueryHandleChange): void => {
|
||||
let promQuery = promQueries.A;
|
||||
function PromqlSection(): JSX.Element {
|
||||
const { currentQuery } = useQueryBuilder();
|
||||
|
||||
// todo(amol): how to remove query, make it null?
|
||||
if (query) promQuery.query = query;
|
||||
if (legend) promQuery.legend = legend;
|
||||
if (toggleDelete) {
|
||||
promQuery = {
|
||||
query: '',
|
||||
legend: '',
|
||||
name: 'A',
|
||||
disabled: false,
|
||||
};
|
||||
}
|
||||
setPromQueries({
|
||||
A: {
|
||||
...promQuery,
|
||||
},
|
||||
});
|
||||
};
|
||||
return (
|
||||
<PromQLQueryBuilder
|
||||
key="A"
|
||||
queryIndex="A"
|
||||
queryData={{ ...promQueries?.A, name: 'A' }}
|
||||
handleQueryChange={handlePromQLQueryChange}
|
||||
queryIndex={0}
|
||||
queryData={currentQuery.promql[0]}
|
||||
deletable={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface PromqlSectionProps {
|
||||
promQueries: IPromQueries;
|
||||
setPromQueries: (p: IPromQueries) => void;
|
||||
}
|
||||
|
||||
export default PromqlSection;
|
||||
|
@ -5,7 +5,6 @@ import { QueryBuilder } from 'container/QueryBuilder';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
import { IChQueries, IPromQueries } from 'types/api/alerts/compositeQuery';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
import ChQuerySection from './ChQuerySection';
|
||||
@ -15,10 +14,6 @@ import { FormContainer, StepHeading } from './styles';
|
||||
function QuerySection({
|
||||
queryCategory,
|
||||
setQueryCategory,
|
||||
promQueries,
|
||||
setPromQueries,
|
||||
chQueries,
|
||||
setChQueries,
|
||||
alertType,
|
||||
runQuery,
|
||||
}: QuerySectionProps): JSX.Element {
|
||||
@ -26,45 +21,12 @@ function QuerySection({
|
||||
const { t } = useTranslation('alerts');
|
||||
|
||||
const handleQueryCategoryChange = (queryType: string): void => {
|
||||
if (
|
||||
queryType === EQueryType.PROM &&
|
||||
(!promQueries || Object.keys(promQueries).length === 0)
|
||||
) {
|
||||
setPromQueries({
|
||||
A: {
|
||||
query: '',
|
||||
stats: '',
|
||||
name: 'A',
|
||||
legend: '',
|
||||
disabled: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
queryType === EQueryType.CLICKHOUSE &&
|
||||
(!chQueries || Object.keys(chQueries).length === 0)
|
||||
) {
|
||||
setChQueries({
|
||||
A: {
|
||||
rawQuery: '',
|
||||
name: 'A',
|
||||
query: '',
|
||||
legend: '',
|
||||
disabled: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
setQueryCategory(queryType as EQueryType);
|
||||
};
|
||||
|
||||
const renderPromqlUI = (): JSX.Element => (
|
||||
<PromqlSection promQueries={promQueries} setPromQueries={setPromQueries} />
|
||||
);
|
||||
const renderPromqlUI = (): JSX.Element => <PromqlSection />;
|
||||
|
||||
const renderChQueryUI = (): JSX.Element => (
|
||||
<ChQuerySection chQueries={chQueries} setChQueries={setChQueries} />
|
||||
);
|
||||
const renderChQueryUI = (): JSX.Element => <ChQuerySection />;
|
||||
|
||||
const renderMetricUI = (): JSX.Element => (
|
||||
<QueryBuilder
|
||||
@ -169,10 +131,6 @@ function QuerySection({
|
||||
interface QuerySectionProps {
|
||||
queryCategory: EQueryType;
|
||||
setQueryCategory: (n: EQueryType) => void;
|
||||
promQueries: IPromQueries;
|
||||
setPromQueries: (p: IPromQueries) => void;
|
||||
chQueries: IChQueries;
|
||||
setChQueries: (q: IChQueries) => void;
|
||||
alertType: AlertTypes;
|
||||
runQuery: () => void;
|
||||
}
|
||||
|
@ -10,19 +10,17 @@ import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
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 { useTranslation } from 'react-i18next';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
import { IChQueries, IPromQueries } from 'types/api/alerts/compositeQuery';
|
||||
import {
|
||||
AlertDef,
|
||||
defaultEvalWindow,
|
||||
defaultMatchType,
|
||||
} from 'types/api/alerts/def';
|
||||
import { Query as StagedQuery } from 'types/api/dashboard/getAll';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
import BasicInfo from './BasicInfo';
|
||||
@ -48,7 +46,12 @@ function FormAlertRules({
|
||||
// init namespace for translations
|
||||
const { t } = useTranslation('alerts');
|
||||
|
||||
const { queryBuilderData, initQueryBuilderData } = useQueryBuilder();
|
||||
const {
|
||||
currentQuery,
|
||||
queryType,
|
||||
handleSetQueryType,
|
||||
initQueryBuilderData,
|
||||
} = useQueryBuilder();
|
||||
|
||||
// use query client
|
||||
const ruleCache = useQueryClient();
|
||||
@ -61,83 +64,35 @@ function FormAlertRules({
|
||||
// initQuery contains initial query when component was mounted
|
||||
const initQuery = initialValue.condition.compositeQuery;
|
||||
|
||||
const [queryCategory, setQueryCategory] = useState<EQueryType>(
|
||||
initQuery.queryType,
|
||||
);
|
||||
|
||||
// local state to handle promql queries
|
||||
const [promQueries, setPromQueries] = useState<IPromQueries>({
|
||||
...initQuery?.promQueries,
|
||||
});
|
||||
|
||||
// local state to handle promql queries
|
||||
const [chQueries, setChQueries] = useState<IChQueries>({
|
||||
...initQuery?.chQueries,
|
||||
});
|
||||
|
||||
// staged query is used to display chart preview. the query gets
|
||||
// auto refreshed when any of the params in query section change.
|
||||
// though this is the source of chart data, the final query used
|
||||
// by chart will be either debouncedStagedQuery or manualStagedQuery
|
||||
// depending on the run option (auto-run or use of run query button)
|
||||
const [stagedQuery, setStagedQuery] = useState<StagedQuery>();
|
||||
|
||||
// manualStagedQuery requires manual staging of query
|
||||
// when user clicks run query button. Useful for clickhouse tab where
|
||||
// run query button is provided.
|
||||
const [manualStagedQuery, setManualStagedQuery] = useState<StagedQuery>();
|
||||
const [manualStagedQuery, setManualStagedQuery] = useState<Query>();
|
||||
|
||||
// this use effect initiates staged query and
|
||||
// other queries based on server data.
|
||||
// useful when fetching of initial values (from api)
|
||||
// is delayed
|
||||
useEffect(() => {
|
||||
const initQuery = initialValue?.condition?.compositeQuery;
|
||||
const type = initQuery.queryType;
|
||||
|
||||
const builderData = mapQueryDataFromApi(
|
||||
initialValue?.condition?.compositeQuery?.builderQueries || {},
|
||||
);
|
||||
|
||||
// prepare staged query
|
||||
const sq = prepareStagedQuery(
|
||||
type,
|
||||
builderData.queryData,
|
||||
builderData.queryFormulas,
|
||||
initQuery?.builderQueries,
|
||||
initQuery?.promQueries,
|
||||
initQuery?.chQueries,
|
||||
);
|
||||
const pq = initQuery?.promQueries;
|
||||
const chq = initQuery?.chQueries;
|
||||
|
||||
setQueryCategory(type);
|
||||
initQueryBuilderData(builderData);
|
||||
setPromQueries(pq);
|
||||
setStagedQuery(sq);
|
||||
initQueryBuilderData(sq, type);
|
||||
|
||||
// also set manually staged query
|
||||
setManualStagedQuery(sq);
|
||||
|
||||
setChQueries(chq);
|
||||
setAlertDef(initialValue);
|
||||
}, [initialValue, initQueryBuilderData]);
|
||||
|
||||
// this useEffect updates staging query when
|
||||
// any of its sub-parameters changes
|
||||
useEffect(() => {
|
||||
// prepare staged query
|
||||
const sq: StagedQuery = prepareStagedQuery(
|
||||
queryCategory,
|
||||
queryBuilderData.queryData,
|
||||
queryBuilderData.queryFormulas,
|
||||
promQueries,
|
||||
chQueries,
|
||||
);
|
||||
setStagedQuery(sq);
|
||||
}, [queryCategory, chQueries, queryBuilderData, promQueries]);
|
||||
}, [initialValue, initQueryBuilderData, initQuery]);
|
||||
|
||||
const onRunQuery = (): void => {
|
||||
setManualStagedQuery(stagedQuery);
|
||||
setManualStagedQuery({ ...currentQuery, queryType });
|
||||
};
|
||||
|
||||
const onCancelHandler = useCallback(() => {
|
||||
@ -147,8 +102,7 @@ function FormAlertRules({
|
||||
// onQueryCategoryChange handles changes to query category
|
||||
// in state as well as sets additional defaults
|
||||
const onQueryCategoryChange = (val: EQueryType): void => {
|
||||
console.log('onQueryCategoryChange', val);
|
||||
setQueryCategory(val);
|
||||
handleSetQueryType(val);
|
||||
if (val === EQueryType.PROM) {
|
||||
setAlertDef({
|
||||
...alertDef,
|
||||
@ -160,22 +114,15 @@ function FormAlertRules({
|
||||
});
|
||||
}
|
||||
|
||||
const sq: StagedQuery = prepareStagedQuery(
|
||||
val,
|
||||
queryBuilderData.queryData,
|
||||
queryBuilderData.queryFormulas,
|
||||
promQueries,
|
||||
chQueries,
|
||||
);
|
||||
setManualStagedQuery(sq);
|
||||
setManualStagedQuery({ ...currentQuery, queryType: val });
|
||||
};
|
||||
const { notifications } = useNotifications();
|
||||
|
||||
const validatePromParams = useCallback((): boolean => {
|
||||
let retval = true;
|
||||
if (queryCategory !== EQueryType.PROM) return retval;
|
||||
if (queryType !== EQueryType.PROM) return retval;
|
||||
|
||||
if (!promQueries || Object.keys(promQueries).length === 0) {
|
||||
if (!currentQuery.promql || currentQuery.promql.length === 0) {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: t('promql_required'),
|
||||
@ -183,8 +130,8 @@ function FormAlertRules({
|
||||
return false;
|
||||
}
|
||||
|
||||
Object.keys(promQueries).forEach((key) => {
|
||||
if (promQueries[key].query === '') {
|
||||
currentQuery.promql.forEach((item) => {
|
||||
if (item.query === '') {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: t('promql_required'),
|
||||
@ -194,13 +141,16 @@ function FormAlertRules({
|
||||
});
|
||||
|
||||
return retval;
|
||||
}, [t, promQueries, queryCategory, notifications]);
|
||||
}, [t, currentQuery, queryType, notifications]);
|
||||
|
||||
const validateChQueryParams = useCallback((): boolean => {
|
||||
let retval = true;
|
||||
if (queryCategory !== EQueryType.CLICKHOUSE) return retval;
|
||||
if (queryType !== EQueryType.CLICKHOUSE) return retval;
|
||||
|
||||
if (!chQueries || Object.keys(chQueries).length === 0) {
|
||||
if (
|
||||
!currentQuery.clickhouse_sql ||
|
||||
currentQuery.clickhouse_sql.length === 0
|
||||
) {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: t('chquery_required'),
|
||||
@ -208,8 +158,8 @@ function FormAlertRules({
|
||||
return false;
|
||||
}
|
||||
|
||||
Object.keys(chQueries).forEach((key) => {
|
||||
if (chQueries[key].rawQuery === '') {
|
||||
currentQuery.clickhouse_sql.forEach((item) => {
|
||||
if (item.rawQuery === '') {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: t('chquery_required'),
|
||||
@ -219,12 +169,15 @@ function FormAlertRules({
|
||||
});
|
||||
|
||||
return retval;
|
||||
}, [t, chQueries, queryCategory, notifications]);
|
||||
}, [t, queryType, currentQuery, notifications]);
|
||||
|
||||
const validateQBParams = useCallback((): boolean => {
|
||||
if (queryCategory !== EQueryType.QUERY_BUILDER) return true;
|
||||
if (queryType !== EQueryType.QUERY_BUILDER) return true;
|
||||
|
||||
if (!queryBuilderData.queryData || queryBuilderData.queryData.length === 0) {
|
||||
if (
|
||||
!currentQuery.builder.queryData ||
|
||||
currentQuery.builder.queryData.length === 0
|
||||
) {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: t('condition_required'),
|
||||
@ -241,7 +194,7 @@ function FormAlertRules({
|
||||
}
|
||||
|
||||
return true;
|
||||
}, [t, alertDef, queryCategory, queryBuilderData, notifications]);
|
||||
}, [t, alertDef, queryType, currentQuery, notifications]);
|
||||
|
||||
const isFormValid = useCallback((): boolean => {
|
||||
if (!alertDef.alert || alertDef.alert === '') {
|
||||
@ -275,15 +228,18 @@ function FormAlertRules({
|
||||
...alertDef,
|
||||
alertType,
|
||||
source: window?.location.toString(),
|
||||
ruleType:
|
||||
queryCategory === EQueryType.PROM ? 'promql_rule' : 'threshold_rule',
|
||||
ruleType: queryType === EQueryType.PROM ? 'promql_rule' : 'threshold_rule',
|
||||
condition: {
|
||||
...alertDef.condition,
|
||||
compositeQuery: {
|
||||
builderQueries: mapQueryDataToApi(queryBuilderData).data,
|
||||
promQueries,
|
||||
chQueries,
|
||||
queryType: queryCategory,
|
||||
builderQueries: {
|
||||
...mapQueryDataToApi(currentQuery.builder.queryData, 'queryName').data,
|
||||
...mapQueryDataToApi(currentQuery.builder.queryFormulas, 'queryName')
|
||||
.data,
|
||||
},
|
||||
promQueries: mapQueryDataToApi(currentQuery.promql, 'name').data,
|
||||
chQueries: mapQueryDataToApi(currentQuery.clickhouse_sql, 'name').data,
|
||||
queryType,
|
||||
panelType: initQuery.panelType,
|
||||
},
|
||||
},
|
||||
@ -292,11 +248,9 @@ function FormAlertRules({
|
||||
};
|
||||
|
||||
const memoizedPreparePostData = useCallback(preparePostData, [
|
||||
queryCategory,
|
||||
queryType,
|
||||
currentQuery,
|
||||
alertDef,
|
||||
queryBuilderData,
|
||||
promQueries,
|
||||
chQueries,
|
||||
alertType,
|
||||
initQuery,
|
||||
]);
|
||||
@ -359,7 +313,7 @@ function FormAlertRules({
|
||||
const content = (
|
||||
<Typography.Text>
|
||||
{' '}
|
||||
{t('confirm_save_content_part1')} <QueryTypeTag queryType={queryCategory} />{' '}
|
||||
{t('confirm_save_content_part1')} <QueryTypeTag queryType={queryType} />{' '}
|
||||
{t('confirm_save_content_part2')}
|
||||
</Typography.Text>
|
||||
);
|
||||
@ -372,7 +326,7 @@ function FormAlertRules({
|
||||
saveRule();
|
||||
},
|
||||
});
|
||||
}, [t, saveRule, queryCategory]);
|
||||
}, [t, saveRule, queryType]);
|
||||
|
||||
const onTestRuleHandler = useCallback(async () => {
|
||||
if (!isFormValid()) {
|
||||
@ -418,7 +372,7 @@ function FormAlertRules({
|
||||
|
||||
const renderQBChartPreview = (): JSX.Element => (
|
||||
<ChartPreview
|
||||
headline={<PlotTag queryType={queryCategory} />}
|
||||
headline={<PlotTag queryType={queryType} />}
|
||||
name=""
|
||||
threshold={alertDef.condition?.target}
|
||||
query={manualStagedQuery}
|
||||
@ -428,7 +382,7 @@ function FormAlertRules({
|
||||
|
||||
const renderPromChartPreview = (): JSX.Element => (
|
||||
<ChartPreview
|
||||
headline={<PlotTag queryType={queryCategory} />}
|
||||
headline={<PlotTag queryType={queryType} />}
|
||||
name="Chart Preview"
|
||||
threshold={alertDef.condition?.target}
|
||||
query={manualStagedQuery}
|
||||
@ -437,7 +391,7 @@ function FormAlertRules({
|
||||
|
||||
const renderChQueryChartPreview = (): JSX.Element => (
|
||||
<ChartPreview
|
||||
headline={<PlotTag queryType={queryCategory} />}
|
||||
headline={<PlotTag queryType={queryType} />}
|
||||
name="Chart Preview"
|
||||
threshold={alertDef.condition?.target}
|
||||
query={manualStagedQuery}
|
||||
@ -448,7 +402,7 @@ function FormAlertRules({
|
||||
const isNewRule = ruleId === 0;
|
||||
|
||||
const isAlertAvialableToSave =
|
||||
isAlertAvialable && isNewRule && queryCategory === EQueryType.QUERY_BUILDER;
|
||||
isAlertAvialable && isNewRule && queryType === EQueryType.QUERY_BUILDER;
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -460,22 +414,18 @@ function FormAlertRules({
|
||||
layout="vertical"
|
||||
form={formInstance}
|
||||
>
|
||||
{queryCategory === EQueryType.QUERY_BUILDER && renderQBChartPreview()}
|
||||
{queryCategory === EQueryType.PROM && renderPromChartPreview()}
|
||||
{queryCategory === EQueryType.CLICKHOUSE && renderChQueryChartPreview()}
|
||||
{queryType === EQueryType.QUERY_BUILDER && renderQBChartPreview()}
|
||||
{queryType === EQueryType.PROM && renderPromChartPreview()}
|
||||
{queryType === EQueryType.CLICKHOUSE && renderChQueryChartPreview()}
|
||||
<QuerySection
|
||||
queryCategory={queryCategory}
|
||||
queryCategory={queryType}
|
||||
setQueryCategory={onQueryCategoryChange}
|
||||
promQueries={promQueries}
|
||||
setPromQueries={setPromQueries}
|
||||
chQueries={chQueries}
|
||||
setChQueries={setChQueries}
|
||||
alertType={alertType || AlertTypes.METRICS_BASED_ALERT}
|
||||
runQuery={onRunQuery}
|
||||
/>
|
||||
|
||||
<RuleOptions
|
||||
queryCategory={queryCategory}
|
||||
queryCategory={queryType}
|
||||
alertDef={alertDef}
|
||||
setAlertDef={setAlertDef}
|
||||
/>
|
||||
@ -514,7 +464,7 @@ function FormAlertRules({
|
||||
</MainFormContainer>
|
||||
</StyledLeftContainer>
|
||||
<Col flex="1 1 300px">
|
||||
<UserGuide queryType={queryCategory} />
|
||||
<UserGuide queryType={queryType} />
|
||||
</Col>
|
||||
</PanelContainer>
|
||||
</>
|
||||
|
@ -1,34 +1,30 @@
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
|
||||
import {
|
||||
IChQueries,
|
||||
IChQuery,
|
||||
IPromQueries,
|
||||
IPromQuery,
|
||||
} from 'types/api/alerts/compositeQuery';
|
||||
import { Query as IStagedQuery } from 'types/api/dashboard/getAll';
|
||||
import {
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
BuilderClickHouseResource,
|
||||
BuilderPromQLResource,
|
||||
BuilderQueryDataResourse,
|
||||
IClickHouseQuery,
|
||||
IPromQLQuery,
|
||||
Query,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
export const prepareStagedQuery = (
|
||||
t: EQueryType,
|
||||
m: IBuilderQuery[],
|
||||
f: IBuilderFormula[],
|
||||
p: IPromQueries,
|
||||
c: IChQueries,
|
||||
): IStagedQuery => {
|
||||
const promList: IPromQuery[] = [];
|
||||
const chQueryList: IChQuery[] = [];
|
||||
b: BuilderQueryDataResourse,
|
||||
p: BuilderPromQLResource,
|
||||
c: BuilderClickHouseResource,
|
||||
): Query => {
|
||||
const promList: IPromQLQuery[] = [];
|
||||
const chQueryList: IClickHouseQuery[] = [];
|
||||
|
||||
// convert map[string]IPromQuery to IPromQuery[]
|
||||
const builder = mapQueryDataFromApi(b);
|
||||
if (p) {
|
||||
Object.keys(p).forEach((key) => {
|
||||
promList.push({ ...p[key], name: key });
|
||||
});
|
||||
}
|
||||
// convert map[string]IChQuery to IChQuery[]
|
||||
if (c) {
|
||||
Object.keys(c).forEach((key) => {
|
||||
chQueryList.push({ ...c[key], name: key, rawQuery: c[key].query });
|
||||
@ -38,10 +34,7 @@ export const prepareStagedQuery = (
|
||||
return {
|
||||
queryType: t,
|
||||
promql: promList,
|
||||
builder: {
|
||||
queryFormulas: f,
|
||||
queryData: m,
|
||||
},
|
||||
builder,
|
||||
clickhouse_sql: chQueryList,
|
||||
};
|
||||
};
|
||||
|
@ -1,12 +1,11 @@
|
||||
import { NotificationInstance } from 'antd/es/notification/interface';
|
||||
import updateDashboardApi from 'api/dashboard/update';
|
||||
import {
|
||||
ClickHouseQueryTemplate,
|
||||
PromQLQueryTemplate,
|
||||
} from 'constants/dashboard';
|
||||
import { initialQueryBuilderFormValues } from 'constants/queryBuilder';
|
||||
initialClickHouseData,
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryPromQLData,
|
||||
} from 'constants/queryBuilder';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import GetQueryName from 'lib/query/GetQueryName';
|
||||
import { Layout } from 'react-grid-layout';
|
||||
import store from 'store';
|
||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
@ -42,18 +41,8 @@ export const UpdateDashboard = async (
|
||||
panelTypes: graphType,
|
||||
query: {
|
||||
queryType: EQueryType.QUERY_BUILDER,
|
||||
promql: [
|
||||
{
|
||||
name: GetQueryName([]) || '',
|
||||
...PromQLQueryTemplate,
|
||||
},
|
||||
],
|
||||
clickhouse_sql: [
|
||||
{
|
||||
name: GetQueryName([]) || '',
|
||||
...ClickHouseQueryTemplate,
|
||||
},
|
||||
],
|
||||
promql: [initialQueryPromQLData],
|
||||
clickhouse_sql: [initialClickHouseData],
|
||||
builder: {
|
||||
queryFormulas: [],
|
||||
queryData: [initialQueryBuilderFormValues],
|
||||
|
@ -14,6 +14,7 @@ interface IQueryHeaderProps {
|
||||
disabled: boolean;
|
||||
onDisable: VoidFunction;
|
||||
name: string;
|
||||
deletable: boolean;
|
||||
onDelete: VoidFunction;
|
||||
children: ReactNode;
|
||||
}
|
||||
@ -23,6 +24,7 @@ function QueryHeader({
|
||||
onDisable,
|
||||
name,
|
||||
onDelete,
|
||||
deletable,
|
||||
children,
|
||||
}: IQueryHeaderProps): JSX.Element {
|
||||
const [collapse, setCollapse] = useState(false);
|
||||
@ -44,7 +46,9 @@ function QueryHeader({
|
||||
/>
|
||||
</Row>
|
||||
|
||||
<Button type="ghost" danger icon={<DeleteOutlined />} onClick={onDelete} />
|
||||
{deletable && (
|
||||
<Button type="ghost" danger icon={<DeleteOutlined />} onClick={onDelete} />
|
||||
)}
|
||||
</Row>
|
||||
{!collapse && children}
|
||||
</QueryWrapper>
|
||||
|
@ -1,79 +1,24 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { ClickHouseQueryTemplate } from 'constants/dashboard';
|
||||
import GetQueryName from 'lib/query/GetQueryName';
|
||||
import { Query } from 'types/api/dashboard/getAll';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
import { QueryButton } from '../../styles';
|
||||
import { IHandleUpdatedQuery } from '../../types';
|
||||
import ClickHouseQueryBuilder from './query';
|
||||
import { IClickHouseQueryHandleChange } from './types';
|
||||
|
||||
interface IClickHouseQueryContainerProps {
|
||||
queryData: Query;
|
||||
updateQueryData: (args: IHandleUpdatedQuery) => void;
|
||||
clickHouseQueries: Query['clickhouse_sql'];
|
||||
}
|
||||
function ClickHouseQueryContainer({
|
||||
queryData,
|
||||
updateQueryData,
|
||||
clickHouseQueries,
|
||||
}: IClickHouseQueryContainerProps): JSX.Element | null {
|
||||
const handleClickHouseQueryChange = ({
|
||||
queryIndex,
|
||||
rawQuery,
|
||||
legend,
|
||||
toggleDisable,
|
||||
toggleDelete,
|
||||
}: IClickHouseQueryHandleChange): void => {
|
||||
// we must check if queryIndex is number type. because -
|
||||
// ClickHouseQueryBuilder.handleQueryChange has a queryIndex
|
||||
// parameter which supports both number and string formats.
|
||||
// it is because, the dashboard side of query builder has queryIndex as number
|
||||
// while the alert builder uses string format for query index (similar to backend)
|
||||
// hence, this method is only applies when queryIndex is in number format.
|
||||
|
||||
if (typeof queryIndex === 'number') {
|
||||
const allQueries = queryData[EQueryType.CLICKHOUSE];
|
||||
|
||||
const currentIndexQuery = allQueries[queryIndex];
|
||||
|
||||
if (rawQuery !== undefined) {
|
||||
currentIndexQuery.rawQuery = rawQuery;
|
||||
}
|
||||
|
||||
if (legend !== undefined) {
|
||||
currentIndexQuery.legend = legend;
|
||||
}
|
||||
|
||||
if (toggleDisable) {
|
||||
currentIndexQuery.disabled = !currentIndexQuery.disabled;
|
||||
}
|
||||
if (toggleDelete) {
|
||||
allQueries.splice(queryIndex, 1);
|
||||
}
|
||||
updateQueryData({ updatedQuery: { ...queryData } });
|
||||
}
|
||||
};
|
||||
function ClickHouseQueryContainer(): JSX.Element | null {
|
||||
const { currentQuery, addNewQueryItem } = useQueryBuilder();
|
||||
const addQueryHandler = (): void => {
|
||||
queryData[EQueryType.CLICKHOUSE].push({
|
||||
name: GetQueryName(queryData[EQueryType.CLICKHOUSE]) || '',
|
||||
...ClickHouseQueryTemplate,
|
||||
});
|
||||
updateQueryData({ updatedQuery: { ...queryData } });
|
||||
addNewQueryItem(EQueryType.CLICKHOUSE);
|
||||
};
|
||||
|
||||
if (!clickHouseQueries) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{clickHouseQueries.map((q, idx) => (
|
||||
{currentQuery.clickhouse_sql.map((q, idx) => (
|
||||
<ClickHouseQueryBuilder
|
||||
key={q.name}
|
||||
queryIndex={idx}
|
||||
deletable={currentQuery.clickhouse_sql.length > 1}
|
||||
queryData={q}
|
||||
handleQueryChange={handleClickHouseQueryChange}
|
||||
/>
|
||||
))}
|
||||
<QueryButton onClick={addQueryHandler} icon={<PlusOutlined />}>
|
||||
|
@ -1,42 +1,80 @@
|
||||
import { Input } from 'antd';
|
||||
import MonacoEditor from 'components/Editor';
|
||||
import { IClickHouseQuery } from 'types/api/dashboard/getAll';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { ChangeEvent, useCallback } from 'react';
|
||||
import { IClickHouseQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
import QueryHeader from '../QueryHeader';
|
||||
import { IClickHouseQueryHandleChange } from './types';
|
||||
|
||||
interface IClickHouseQueryBuilderProps {
|
||||
queryData: IClickHouseQuery;
|
||||
queryIndex: number | string;
|
||||
handleQueryChange: (args: IClickHouseQueryHandleChange) => void;
|
||||
queryIndex: number;
|
||||
deletable: boolean;
|
||||
}
|
||||
|
||||
function ClickHouseQueryBuilder({
|
||||
queryData,
|
||||
queryIndex,
|
||||
handleQueryChange,
|
||||
deletable,
|
||||
}: IClickHouseQueryBuilderProps): JSX.Element | null {
|
||||
if (queryData === undefined) {
|
||||
return null;
|
||||
}
|
||||
const {
|
||||
handleSetQueryItemData,
|
||||
removeQueryTypeItemByIndex,
|
||||
} = useQueryBuilder();
|
||||
|
||||
const handleRemoveQuery = useCallback(() => {
|
||||
removeQueryTypeItemByIndex(EQueryType.CLICKHOUSE, queryIndex);
|
||||
}, [queryIndex, removeQueryTypeItemByIndex]);
|
||||
|
||||
const handleUpdateQuery = useCallback(
|
||||
<Field extends keyof IClickHouseQuery, Value extends IClickHouseQuery[Field]>(
|
||||
field: keyof IClickHouseQuery,
|
||||
value: Value,
|
||||
) => {
|
||||
const newQuery: IClickHouseQuery = { ...queryData, [field]: value };
|
||||
|
||||
handleSetQueryItemData(queryIndex, EQueryType.CLICKHOUSE, newQuery);
|
||||
},
|
||||
[handleSetQueryItemData, queryIndex, queryData],
|
||||
);
|
||||
|
||||
const handleDisable = useCallback(() => {
|
||||
const newQuery: IClickHouseQuery = {
|
||||
...queryData,
|
||||
disabled: !queryData.disabled,
|
||||
};
|
||||
|
||||
handleSetQueryItemData(queryIndex, EQueryType.CLICKHOUSE, newQuery);
|
||||
}, [handleSetQueryItemData, queryData, queryIndex]);
|
||||
|
||||
const handleUpdateEditor = useCallback(
|
||||
(value: string) => {
|
||||
handleUpdateQuery('rawQuery', value);
|
||||
},
|
||||
[handleUpdateQuery],
|
||||
);
|
||||
|
||||
const handleUpdateInput = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target;
|
||||
handleUpdateQuery(name as keyof IClickHouseQuery, value);
|
||||
},
|
||||
[handleUpdateQuery],
|
||||
);
|
||||
|
||||
return (
|
||||
<QueryHeader
|
||||
name={queryData.name}
|
||||
disabled={queryData.disabled}
|
||||
onDisable={(): void =>
|
||||
handleQueryChange({ queryIndex, toggleDisable: true })
|
||||
}
|
||||
onDelete={(): void => {
|
||||
handleQueryChange({ queryIndex, toggleDelete: true });
|
||||
}}
|
||||
onDisable={handleDisable}
|
||||
onDelete={handleRemoveQuery}
|
||||
deletable={deletable}
|
||||
>
|
||||
<MonacoEditor
|
||||
language="sql"
|
||||
height="200px"
|
||||
onChange={(value): void =>
|
||||
handleQueryChange({ queryIndex, rawQuery: value })
|
||||
}
|
||||
onChange={handleUpdateEditor}
|
||||
value={queryData.rawQuery}
|
||||
options={{
|
||||
scrollbar: {
|
||||
@ -48,9 +86,8 @@ function ClickHouseQueryBuilder({
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
onChange={(event): void =>
|
||||
handleQueryChange({ queryIndex, legend: event.target.value })
|
||||
}
|
||||
onChange={handleUpdateInput}
|
||||
name="legend"
|
||||
size="middle"
|
||||
defaultValue={queryData.legend}
|
||||
value={queryData.legend}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IClickHouseQuery } from 'types/api/dashboard/getAll';
|
||||
import { IClickHouseQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
export interface IClickHouseQueryHandleChange {
|
||||
queryIndex: number | string;
|
||||
|
@ -1,65 +1,27 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { PromQLQueryTemplate } from 'constants/dashboard';
|
||||
import GetQueryName from 'lib/query/GetQueryName';
|
||||
import { IPromQLQuery, Query } from 'types/api/dashboard/getAll';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { IPromQLQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
import { QueryButton } from '../../styles';
|
||||
import { IHandleUpdatedQuery } from '../../types';
|
||||
import PromQLQueryBuilder from './query';
|
||||
import { IPromQLQueryHandleChange } from './types';
|
||||
|
||||
interface IPromQLQueryContainerProps {
|
||||
queryData: Query;
|
||||
updateQueryData: (args: IHandleUpdatedQuery) => void;
|
||||
promQLQueries: IPromQLQuery[];
|
||||
}
|
||||
function PromQLQueryContainer(): JSX.Element | null {
|
||||
const { addNewQueryItem, currentQuery } = useQueryBuilder();
|
||||
|
||||
function PromQLQueryContainer({
|
||||
queryData,
|
||||
updateQueryData,
|
||||
promQLQueries,
|
||||
}: IPromQLQueryContainerProps): JSX.Element | null {
|
||||
const handlePromQLQueryChange = ({
|
||||
queryIndex,
|
||||
query,
|
||||
legend,
|
||||
toggleDisable,
|
||||
toggleDelete,
|
||||
}: IPromQLQueryHandleChange): void => {
|
||||
const allQueries = queryData[EQueryType.PROM];
|
||||
const currentIndexQuery = allQueries[queryIndex as number];
|
||||
if (query !== undefined) currentIndexQuery.query = query;
|
||||
if (legend !== undefined) currentIndexQuery.legend = legend;
|
||||
|
||||
if (toggleDisable) {
|
||||
currentIndexQuery.disabled = !currentIndexQuery.disabled;
|
||||
}
|
||||
if (toggleDelete) {
|
||||
allQueries.splice(queryIndex as number, 1);
|
||||
}
|
||||
updateQueryData({ updatedQuery: { ...queryData } });
|
||||
};
|
||||
const addQueryHandler = (): void => {
|
||||
queryData[EQueryType.PROM].push({
|
||||
name: GetQueryName(queryData[EQueryType.PROM]) || '',
|
||||
...PromQLQueryTemplate,
|
||||
});
|
||||
updateQueryData({ updatedQuery: { ...queryData } });
|
||||
addNewQueryItem(EQueryType.PROM);
|
||||
};
|
||||
|
||||
if (!promQLQueries) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{promQLQueries.map(
|
||||
{currentQuery.promql.map(
|
||||
(q: IPromQLQuery, idx: number): JSX.Element => (
|
||||
<PromQLQueryBuilder
|
||||
key={q.name}
|
||||
deletable={currentQuery.promql.length > 1}
|
||||
queryIndex={idx}
|
||||
queryData={q}
|
||||
handleQueryChange={handlePromQLQueryChange}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
|
@ -1,46 +1,71 @@
|
||||
import { Input } from 'antd';
|
||||
import { IPromQLQuery } from 'types/api/dashboard/getAll';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { ChangeEvent, useCallback } from 'react';
|
||||
import { IPromQLQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
import QueryHeader from '../QueryHeader';
|
||||
import { IPromQLQueryHandleChange } from './types';
|
||||
|
||||
interface IPromQLQueryBuilderProps {
|
||||
queryData: IPromQLQuery;
|
||||
queryIndex: number | string;
|
||||
handleQueryChange: (args: IPromQLQueryHandleChange) => void;
|
||||
queryIndex: number;
|
||||
deletable: boolean;
|
||||
}
|
||||
|
||||
function PromQLQueryBuilder({
|
||||
queryData,
|
||||
queryIndex,
|
||||
handleQueryChange,
|
||||
deletable,
|
||||
}: IPromQLQueryBuilderProps): JSX.Element {
|
||||
const {
|
||||
handleSetQueryItemData,
|
||||
removeQueryTypeItemByIndex,
|
||||
} = useQueryBuilder();
|
||||
|
||||
const handleRemoveQuery = useCallback(() => {
|
||||
removeQueryTypeItemByIndex(EQueryType.PROM, queryIndex);
|
||||
}, [queryIndex, removeQueryTypeItemByIndex]);
|
||||
|
||||
const handleUpdateQuery = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target;
|
||||
const newQuery: IPromQLQuery = { ...queryData, [name]: value };
|
||||
|
||||
handleSetQueryItemData(queryIndex, EQueryType.PROM, newQuery);
|
||||
},
|
||||
[handleSetQueryItemData, queryIndex, queryData],
|
||||
);
|
||||
|
||||
const handleDisable = useCallback(() => {
|
||||
const newQuery: IPromQLQuery = {
|
||||
...queryData,
|
||||
disabled: !queryData.disabled,
|
||||
};
|
||||
|
||||
handleSetQueryItemData(queryIndex, EQueryType.PROM, newQuery);
|
||||
}, [handleSetQueryItemData, queryData, queryIndex]);
|
||||
|
||||
return (
|
||||
<QueryHeader
|
||||
name={queryData.name}
|
||||
disabled={queryData.disabled}
|
||||
onDisable={(): void =>
|
||||
handleQueryChange({ queryIndex, toggleDisable: true })
|
||||
}
|
||||
onDelete={(): void => {
|
||||
handleQueryChange({ queryIndex, toggleDelete: true });
|
||||
}}
|
||||
onDisable={handleDisable}
|
||||
onDelete={handleRemoveQuery}
|
||||
deletable={deletable}
|
||||
>
|
||||
<Input
|
||||
onChange={(event): void =>
|
||||
handleQueryChange({ queryIndex, query: event.target.value })
|
||||
}
|
||||
onChange={handleUpdateQuery}
|
||||
size="middle"
|
||||
name="query"
|
||||
defaultValue={queryData.query}
|
||||
addonBefore="PromQL Query"
|
||||
style={{ marginBottom: '0.5rem' }}
|
||||
/>
|
||||
|
||||
<Input
|
||||
onChange={(event): void =>
|
||||
handleQueryChange({ queryIndex, legend: event.target.value })
|
||||
}
|
||||
onChange={handleUpdateQuery}
|
||||
size="middle"
|
||||
name="legend"
|
||||
defaultValue={queryData.legend}
|
||||
addonBefore="Legend Format"
|
||||
style={{ marginBottom: '0.5rem' }}
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { IPromQLQuery } from 'types/api/dashboard/getAll';
|
||||
import { IPromQLQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
export interface IPromQLQueryHandleChange {
|
||||
queryIndex: number | string;
|
||||
query?: IPromQLQuery['query'];
|
||||
legend?: IPromQLQuery['legend'];
|
||||
toggleDisable?: IPromQLQuery['disabled'];
|
||||
toggleDelete?: boolean;
|
||||
query: IPromQLQuery;
|
||||
}
|
||||
|
@ -3,8 +3,7 @@ import TextToolTip from 'components/TextToolTip';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { QueryBuilder } from 'container/QueryBuilder';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
@ -15,25 +14,20 @@ import {
|
||||
} from 'store/actions/dashboard/updateQuery';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { Query, Widgets } from 'types/api/dashboard/getAll';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import DashboardReducer from 'types/reducer/dashboards';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import ClickHouseQueryContainer from './QueryBuilder/clickHouse';
|
||||
import PromQLQueryContainer from './QueryBuilder/promQL';
|
||||
import { IHandleUpdatedQuery } from './types';
|
||||
|
||||
function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
|
||||
const { queryBuilderData, initQueryBuilderData } = useQueryBuilder();
|
||||
const [localQueryChanges, setLocalQueryChanges] = useState<Query>({} as Query);
|
||||
const [rctTabKey, setRctTabKey] = useState<
|
||||
Record<keyof typeof EQueryType, string>
|
||||
>({
|
||||
QUERY_BUILDER: uuid(),
|
||||
CLICKHOUSE: uuid(),
|
||||
PROM: uuid(),
|
||||
});
|
||||
const {
|
||||
currentQuery,
|
||||
queryType,
|
||||
handleSetQueryType,
|
||||
initQueryBuilderData,
|
||||
} = useQueryBuilder();
|
||||
|
||||
const { dashboards, isLoadingQueryResult } = useSelector<
|
||||
AppState,
|
||||
@ -52,33 +46,18 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
|
||||
}, [widgets, urlQuery]);
|
||||
|
||||
const selectedWidget = getWidget() as Widgets;
|
||||
const [queryCategory, setQueryCategory] = useState<EQueryType>(
|
||||
selectedWidget.query.queryType,
|
||||
);
|
||||
|
||||
const { query } = selectedWidget || {};
|
||||
|
||||
useEffect(() => {
|
||||
initQueryBuilderData(query.builder);
|
||||
setLocalQueryChanges(cloneDeep(query) as Query);
|
||||
}, [query, initQueryBuilderData]);
|
||||
|
||||
const regenRctKeys = (): void => {
|
||||
setRctTabKey((prevState) => {
|
||||
const newState = prevState;
|
||||
Object.keys(newState).forEach((key) => {
|
||||
newState[key as keyof typeof EQueryType] = uuid();
|
||||
});
|
||||
|
||||
return cloneDeep(newState);
|
||||
});
|
||||
};
|
||||
initQueryBuilderData(query, selectedWidget.query.queryType);
|
||||
}, [query, initQueryBuilderData, selectedWidget]);
|
||||
|
||||
const handleStageQuery = (): void => {
|
||||
updateQuery({
|
||||
updatedQuery: {
|
||||
...localQueryChanges,
|
||||
builder: queryBuilderData,
|
||||
...currentQuery,
|
||||
queryType,
|
||||
},
|
||||
widgetId: urlQuery.get('widgetId') || '',
|
||||
yAxisUnit: selectedWidget.yAxisUnit,
|
||||
@ -86,26 +65,16 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
|
||||
};
|
||||
|
||||
const handleQueryCategoryChange = (qCategory: string): void => {
|
||||
setQueryCategory(qCategory as EQueryType);
|
||||
const newLocalQuery = {
|
||||
...cloneDeep(query),
|
||||
queryType: qCategory as EQueryType,
|
||||
};
|
||||
setLocalQueryChanges(newLocalQuery);
|
||||
regenRctKeys();
|
||||
const currentQueryType = qCategory as EQueryType;
|
||||
|
||||
handleSetQueryType(currentQueryType);
|
||||
updateQuery({
|
||||
updatedQuery: newLocalQuery,
|
||||
updatedQuery: { ...currentQuery, queryType: currentQueryType },
|
||||
widgetId: urlQuery.get('widgetId') || '',
|
||||
yAxisUnit: selectedWidget.yAxisUnit,
|
||||
});
|
||||
};
|
||||
|
||||
const handleLocalQueryUpdate = ({
|
||||
updatedQuery,
|
||||
}: IHandleUpdatedQuery): void => {
|
||||
setLocalQueryChanges(cloneDeep(updatedQuery));
|
||||
};
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: EQueryType.QUERY_BUILDER,
|
||||
@ -117,31 +86,13 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
|
||||
key: EQueryType.CLICKHOUSE,
|
||||
label: 'ClickHouse Query',
|
||||
tab: <Typography>ClickHouse Query</Typography>,
|
||||
children: (
|
||||
<ClickHouseQueryContainer
|
||||
key={rctTabKey.CLICKHOUSE}
|
||||
queryData={localQueryChanges}
|
||||
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
|
||||
handleLocalQueryUpdate({ updatedQuery });
|
||||
}}
|
||||
clickHouseQueries={localQueryChanges[EQueryType.CLICKHOUSE]}
|
||||
/>
|
||||
),
|
||||
children: <ClickHouseQueryContainer />,
|
||||
},
|
||||
{
|
||||
key: EQueryType.PROM,
|
||||
label: 'PromQL',
|
||||
tab: <Typography>PromQL</Typography>,
|
||||
children: (
|
||||
<PromQLQueryContainer
|
||||
key={rctTabKey.PROM}
|
||||
queryData={localQueryChanges}
|
||||
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
|
||||
handleLocalQueryUpdate({ updatedQuery });
|
||||
}}
|
||||
promQLQueries={localQueryChanges[EQueryType.PROM]}
|
||||
/>
|
||||
),
|
||||
children: <PromQLQueryContainer />,
|
||||
},
|
||||
];
|
||||
|
||||
@ -149,8 +100,8 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element {
|
||||
<Tabs
|
||||
type="card"
|
||||
style={{ width: '100%' }}
|
||||
defaultActiveKey={queryCategory}
|
||||
activeKey={queryCategory}
|
||||
defaultActiveKey={queryType}
|
||||
activeKey={queryType}
|
||||
onChange={handleQueryCategoryChange}
|
||||
tabBarExtraContent={
|
||||
<span style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
|
||||
|
@ -1,5 +0,0 @@
|
||||
import { Query } from 'types/api/dashboard/getAll';
|
||||
|
||||
export interface IHandleUpdatedQuery {
|
||||
updatedQuery: Query;
|
||||
}
|
@ -17,10 +17,10 @@ export const QueryBuilder = memo(function QueryBuilder({
|
||||
panelType,
|
||||
}: QueryBuilderProps): JSX.Element {
|
||||
const {
|
||||
queryBuilderData,
|
||||
currentQuery,
|
||||
setupInitialDataSource,
|
||||
resetQueryBuilderInfo,
|
||||
addNewQuery,
|
||||
addNewBuilderQuery,
|
||||
addNewFormula,
|
||||
handleSetPanelType,
|
||||
} = useQueryBuilder();
|
||||
@ -43,27 +43,27 @@ export const QueryBuilder = memo(function QueryBuilder({
|
||||
);
|
||||
|
||||
const isDisabledQueryButton = useMemo(
|
||||
() => queryBuilderData.queryData.length >= MAX_QUERIES,
|
||||
[queryBuilderData],
|
||||
() => currentQuery.builder.queryData.length >= MAX_QUERIES,
|
||||
[currentQuery],
|
||||
);
|
||||
|
||||
const isDisabledFormulaButton = useMemo(
|
||||
() => queryBuilderData.queryFormulas.length >= MAX_FORMULAS,
|
||||
[queryBuilderData],
|
||||
() => currentQuery.builder.queryFormulas.length >= MAX_FORMULAS,
|
||||
[currentQuery],
|
||||
);
|
||||
|
||||
const isAvailableToDisableQuery = useMemo(
|
||||
() =>
|
||||
queryBuilderData.queryData.length > 1 ||
|
||||
queryBuilderData.queryFormulas.length > 0,
|
||||
[queryBuilderData],
|
||||
currentQuery.builder.queryData.length > 1 ||
|
||||
currentQuery.builder.queryFormulas.length > 0,
|
||||
[currentQuery],
|
||||
);
|
||||
|
||||
return (
|
||||
<Row gutter={[0, 20]} justify="start">
|
||||
<Col span={24}>
|
||||
<Row gutter={[0, 50]}>
|
||||
{queryBuilderData.queryData.map((query, index) => (
|
||||
{currentQuery.builder.queryData.map((query, index) => (
|
||||
<Col key={query.queryName} span={24}>
|
||||
<Query
|
||||
index={index}
|
||||
@ -73,7 +73,7 @@ export const QueryBuilder = memo(function QueryBuilder({
|
||||
/>
|
||||
</Col>
|
||||
))}
|
||||
{queryBuilderData.queryFormulas.map((formula, index) => (
|
||||
{currentQuery.builder.queryFormulas.map((formula, index) => (
|
||||
<Col key={formula.queryName} span={24}>
|
||||
<Formula formula={formula} index={index} />
|
||||
</Col>
|
||||
@ -87,7 +87,7 @@ export const QueryBuilder = memo(function QueryBuilder({
|
||||
disabled={isDisabledQueryButton}
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={addNewQuery}
|
||||
onClick={addNewBuilderQuery}
|
||||
>
|
||||
Query
|
||||
</Button>
|
||||
|
@ -12,11 +12,14 @@ import { FormulaProps } from './Formula.interfaces';
|
||||
const { TextArea } = Input;
|
||||
|
||||
export function Formula({ index, formula }: FormulaProps): JSX.Element {
|
||||
const { removeEntityByIndex, handleSetFormulaData } = useQueryBuilder();
|
||||
const {
|
||||
removeQueryBuilderEntityByIndex,
|
||||
handleSetFormulaData,
|
||||
} = useQueryBuilder();
|
||||
|
||||
const handleDelete = useCallback(() => {
|
||||
removeEntityByIndex('queryFormulas', index);
|
||||
}, [index, removeEntityByIndex]);
|
||||
removeQueryBuilderEntityByIndex('queryFormulas', index);
|
||||
}, [index, removeQueryBuilderEntityByIndex]);
|
||||
|
||||
const handleToggleDisableFormula = useCallback((): void => {
|
||||
const newFormula: IBuilderFormula = {
|
||||
|
@ -19,7 +19,7 @@ import { SelectOption } from 'types/common/select';
|
||||
export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
|
||||
const {
|
||||
handleSetQueryData,
|
||||
removeEntityByIndex,
|
||||
removeQueryBuilderEntityByIndex,
|
||||
panelType,
|
||||
} = useQueryBuilder();
|
||||
const [operators, setOperators] = useState<SelectOption<string, string>[]>([]);
|
||||
@ -101,8 +101,8 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
|
||||
);
|
||||
|
||||
const handleDeleteQuery = useCallback(() => {
|
||||
removeEntityByIndex('queryData', index);
|
||||
}, [removeEntityByIndex, index]);
|
||||
removeQueryBuilderEntityByIndex('queryData', index);
|
||||
}, [removeQueryBuilderEntityByIndex, index]);
|
||||
|
||||
const handleChangeQueryData: HandleChangeQueryData = useCallback(
|
||||
(key, value) => {
|
||||
|
@ -1,14 +1,14 @@
|
||||
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 { QueryDataResourse } from 'types/common/queryBuilderMappers.types';
|
||||
|
||||
export const mapQueryDataFromApi = (
|
||||
data: QueryDataResourse,
|
||||
data: BuilderQueryDataResourse,
|
||||
): QueryBuilderData => {
|
||||
const queryData: QueryBuilderData['queryData'] = [];
|
||||
const queryFormulas: QueryBuilderData['queryFormulas'] = [];
|
||||
|
@ -1,49 +1,29 @@
|
||||
import { QueryBuilderData } from 'types/common/queryBuilder';
|
||||
import {
|
||||
MapFormula,
|
||||
MapQuery,
|
||||
MapData,
|
||||
MapQueryDataToApiResult,
|
||||
} from 'types/common/queryBuilderMappers.types';
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
export const mapQueryDataToApi = (
|
||||
data: QueryBuilderData,
|
||||
): MapQueryDataToApiResult => {
|
||||
export const mapQueryDataToApi = <Data extends MapData, Key extends keyof Data>(
|
||||
data: Data[],
|
||||
nameField: Key,
|
||||
): MapQueryDataToApiResult<Record<string, Data>> => {
|
||||
const newLegendMap: Record<string, string> = {};
|
||||
|
||||
const preparedQueryData: MapQuery = data.queryData.reduce<MapQuery>(
|
||||
(acc, query) => {
|
||||
const newResult: MapQuery = {
|
||||
...acc,
|
||||
[query.queryName]: {
|
||||
...query,
|
||||
},
|
||||
};
|
||||
const preparedResult = data.reduce<Record<string, Data>>((acc, query) => {
|
||||
const newResult: Record<string, Data> = {
|
||||
...acc,
|
||||
[query[nameField] as string]: {
|
||||
...query,
|
||||
},
|
||||
};
|
||||
|
||||
newLegendMap[query.queryName] = query.legend;
|
||||
newLegendMap[query[nameField] as string] = query.legend;
|
||||
|
||||
return newResult;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
const preparedFormulaData: MapFormula = data.queryFormulas.reduce<MapFormula>(
|
||||
(acc, formula) => {
|
||||
const newResult: MapFormula = {
|
||||
...acc,
|
||||
[formula.queryName]: {
|
||||
...formula,
|
||||
},
|
||||
};
|
||||
|
||||
newLegendMap[formula.queryName] = formula.legend;
|
||||
|
||||
return newResult;
|
||||
},
|
||||
{},
|
||||
);
|
||||
return newResult;
|
||||
}, {} as Record<string, Data>);
|
||||
|
||||
return {
|
||||
data: { ...preparedQueryData, ...preparedFormulaData },
|
||||
data: preparedResult,
|
||||
newLegendMap,
|
||||
};
|
||||
};
|
||||
|
@ -2,7 +2,9 @@ import {
|
||||
alphabet,
|
||||
formulasNames,
|
||||
initialFormulaBuilderFormValues,
|
||||
initialQuery,
|
||||
initialQueryBuilderFormValues,
|
||||
initialSingleQueryMap,
|
||||
MAX_FORMULAS,
|
||||
MAX_QUERIES,
|
||||
PANEL_TYPES,
|
||||
@ -21,7 +23,11 @@ import {
|
||||
import {
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
IClickHouseQuery,
|
||||
IPromQLQuery,
|
||||
QueryState,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import {
|
||||
DataSource,
|
||||
QueryBuilderContextType,
|
||||
@ -29,26 +35,26 @@ import {
|
||||
} from 'types/common/queryBuilder';
|
||||
|
||||
export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
||||
queryBuilderData: { queryData: [], queryFormulas: [] },
|
||||
currentQuery: initialQuery,
|
||||
queryType: EQueryType.QUERY_BUILDER,
|
||||
initialDataSource: null,
|
||||
panelType: PANEL_TYPES.TIME_SERIES,
|
||||
resetQueryBuilderData: () => {},
|
||||
resetQueryBuilderInfo: () => {},
|
||||
handleSetQueryData: () => {},
|
||||
handleSetFormulaData: () => {},
|
||||
handleSetQueryItemData: () => {},
|
||||
handleSetPanelType: () => {},
|
||||
handleSetQueryType: () => {},
|
||||
initQueryBuilderData: () => {},
|
||||
setupInitialDataSource: () => {},
|
||||
removeEntityByIndex: () => {},
|
||||
addNewQuery: () => {},
|
||||
removeQueryBuilderEntityByIndex: () => {},
|
||||
removeQueryTypeItemByIndex: () => {},
|
||||
addNewBuilderQuery: () => {},
|
||||
addNewFormula: () => {},
|
||||
addNewQueryItem: () => {},
|
||||
});
|
||||
|
||||
const initialQueryBuilderData: QueryBuilderData = {
|
||||
queryData: [],
|
||||
queryFormulas: [],
|
||||
};
|
||||
|
||||
export function QueryBuilderProvider({
|
||||
children,
|
||||
}: PropsWithChildren): JSX.Element {
|
||||
@ -60,10 +66,15 @@ export function QueryBuilderProvider({
|
||||
PANEL_TYPES.TIME_SERIES,
|
||||
);
|
||||
|
||||
const [queryBuilderData, setQueryBuilderData] = useState<QueryBuilderData>({
|
||||
queryData: [],
|
||||
queryFormulas: [],
|
||||
});
|
||||
const [currentQuery, setCurrentQuery] = useState<QueryState>(initialQuery);
|
||||
|
||||
const [queryType, setQueryType] = useState<EQueryType>(
|
||||
EQueryType.QUERY_BUILDER,
|
||||
);
|
||||
|
||||
const handleSetQueryType = useCallback((newQueryType: EQueryType) => {
|
||||
setQueryType(newQueryType);
|
||||
}, []);
|
||||
|
||||
const resetQueryBuilderInfo = useCallback((): void => {
|
||||
setInitialDataSource(null);
|
||||
@ -71,30 +82,48 @@ export function QueryBuilderProvider({
|
||||
}, []);
|
||||
|
||||
const resetQueryBuilderData = useCallback(() => {
|
||||
setQueryBuilderData(initialQueryBuilderData);
|
||||
setCurrentQuery(initialQuery);
|
||||
}, []);
|
||||
|
||||
const initQueryBuilderData = useCallback(
|
||||
(queryBuilderData: QueryBuilderData): void => {
|
||||
setQueryBuilderData(queryBuilderData);
|
||||
(query: QueryState, queryType: EQueryType): void => {
|
||||
setCurrentQuery(query);
|
||||
setQueryType(queryType);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const removeEntityByIndex = useCallback(
|
||||
const removeQueryBuilderEntityByIndex = useCallback(
|
||||
(type: keyof QueryBuilderData, index: number) => {
|
||||
setQueryBuilderData((prevState) => {
|
||||
const currentArray: (IBuilderQuery | IBuilderFormula)[] = prevState[type];
|
||||
setCurrentQuery((prevState) => {
|
||||
const currentArray: (IBuilderQuery | IBuilderFormula)[] =
|
||||
prevState.builder[type];
|
||||
return {
|
||||
...prevState,
|
||||
[type]: currentArray.filter((item, i) => index !== i),
|
||||
builder: {
|
||||
...prevState.builder,
|
||||
[type]: currentArray.filter((_, i) => index !== i),
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const createNewQuery = useCallback(
|
||||
const removeQueryTypeItemByIndex = useCallback(
|
||||
(type: EQueryType.PROM | EQueryType.CLICKHOUSE, index: number) => {
|
||||
setCurrentQuery((prevState) => {
|
||||
const targetArray: (IPromQLQuery | IClickHouseQuery)[] = prevState[type];
|
||||
return {
|
||||
...prevState,
|
||||
[type]: targetArray.filter((_, i) => index !== i),
|
||||
};
|
||||
});
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const createNewBuilderQuery = useCallback(
|
||||
(queries: IBuilderQuery[]): IBuilderQuery => {
|
||||
const existNames = queries.map((item) => item.queryName);
|
||||
|
||||
@ -121,7 +150,7 @@ export function QueryBuilderProvider({
|
||||
[initialDataSource, panelType],
|
||||
);
|
||||
|
||||
const createNewFormula = useCallback((formulas: IBuilderFormula[]) => {
|
||||
const createNewBuilderFormula = useCallback((formulas: IBuilderFormula[]) => {
|
||||
const existNames = formulas.map((item) => item.queryName);
|
||||
|
||||
const newFormula: IBuilderFormula = {
|
||||
@ -135,28 +164,73 @@ export function QueryBuilderProvider({
|
||||
return newFormula;
|
||||
}, []);
|
||||
|
||||
const addNewQuery = useCallback(() => {
|
||||
setQueryBuilderData((prevState) => {
|
||||
if (prevState.queryData.length >= MAX_QUERIES) return prevState;
|
||||
const createNewQueryTypeItem = useCallback(
|
||||
(
|
||||
itemArray: QueryState['clickhouse_sql'] | QueryState['promql'],
|
||||
type: EQueryType.CLICKHOUSE | EQueryType.PROM,
|
||||
): IPromQLQuery | IClickHouseQuery => {
|
||||
const existNames = itemArray.map((item) => item.name);
|
||||
|
||||
const newQuery = createNewQuery(prevState.queryData);
|
||||
const newItem: IPromQLQuery | IClickHouseQuery = {
|
||||
...initialSingleQueryMap[type],
|
||||
name: createNewBuilderItemName({
|
||||
existNames,
|
||||
sourceNames: alphabet,
|
||||
}),
|
||||
};
|
||||
|
||||
return { ...prevState, queryData: [...prevState.queryData, newQuery] };
|
||||
});
|
||||
}, [createNewQuery]);
|
||||
return newItem;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const addNewFormula = useCallback(() => {
|
||||
setQueryBuilderData((prevState) => {
|
||||
if (prevState.queryFormulas.length >= MAX_FORMULAS) return prevState;
|
||||
const addNewQueryItem = useCallback(
|
||||
(type: EQueryType.CLICKHOUSE | EQueryType.PROM) => {
|
||||
setCurrentQuery((prevState) => {
|
||||
if (prevState[type].length >= MAX_QUERIES) return prevState;
|
||||
|
||||
const newFormula = createNewFormula(prevState.queryFormulas);
|
||||
const newQuery = createNewQueryTypeItem(prevState[type], type);
|
||||
|
||||
return {
|
||||
...prevState,
|
||||
[type]: [...prevState[type], newQuery],
|
||||
};
|
||||
});
|
||||
},
|
||||
[createNewQueryTypeItem],
|
||||
);
|
||||
|
||||
const addNewBuilderQuery = useCallback(() => {
|
||||
setCurrentQuery((prevState) => {
|
||||
if (prevState.builder.queryData.length >= MAX_QUERIES) return prevState;
|
||||
|
||||
const newQuery = createNewBuilderQuery(prevState.builder.queryData);
|
||||
|
||||
return {
|
||||
...prevState,
|
||||
queryFormulas: [...prevState.queryFormulas, newFormula],
|
||||
builder: {
|
||||
...prevState.builder,
|
||||
queryData: [...prevState.builder.queryData, newQuery],
|
||||
},
|
||||
};
|
||||
});
|
||||
}, [createNewFormula]);
|
||||
}, [createNewBuilderQuery]);
|
||||
|
||||
const addNewFormula = useCallback(() => {
|
||||
setCurrentQuery((prevState) => {
|
||||
if (prevState.builder.queryFormulas.length >= MAX_FORMULAS) return prevState;
|
||||
|
||||
const newFormula = createNewBuilderFormula(prevState.builder.queryFormulas);
|
||||
|
||||
return {
|
||||
...prevState,
|
||||
builder: {
|
||||
...prevState.builder,
|
||||
queryFormulas: [...prevState.builder.queryFormulas, newFormula],
|
||||
},
|
||||
};
|
||||
});
|
||||
}, [createNewBuilderFormula]);
|
||||
|
||||
const setupInitialDataSource = useCallback(
|
||||
(newInitialDataSource: DataSource | null) =>
|
||||
@ -164,30 +238,54 @@ export function QueryBuilderProvider({
|
||||
[],
|
||||
);
|
||||
|
||||
const updateQueryBuilderData = useCallback(
|
||||
(queries: IBuilderQuery[], index: number, newQueryData: IBuilderQuery) =>
|
||||
queries.map((item, idx) => (index === idx ? newQueryData : item)),
|
||||
const updateQueryBuilderData: <T>(
|
||||
arr: T[],
|
||||
index: number,
|
||||
newQueryItem: T,
|
||||
) => T[] = useCallback(
|
||||
(arr, index, newQueryItem) =>
|
||||
arr.map((item, idx) => (index === idx ? newQueryItem : item)),
|
||||
|
||||
[],
|
||||
);
|
||||
|
||||
const updateFormulaBuilderData = useCallback(
|
||||
(formulas: IBuilderFormula[], index: number, newFormula: IBuilderFormula) =>
|
||||
formulas.map((item, idx) => (index === idx ? newFormula : item)),
|
||||
[],
|
||||
);
|
||||
|
||||
const handleSetQueryData = useCallback(
|
||||
(index: number, newQueryData: IBuilderQuery): void => {
|
||||
setQueryBuilderData((prevState) => {
|
||||
const handleSetQueryItemData = useCallback(
|
||||
(
|
||||
index: number,
|
||||
type: EQueryType.PROM | EQueryType.CLICKHOUSE,
|
||||
newQueryData: IPromQLQuery | IClickHouseQuery,
|
||||
) => {
|
||||
setCurrentQuery((prevState) => {
|
||||
const updatedQueryBuilderData = updateQueryBuilderData(
|
||||
prevState.queryData,
|
||||
prevState[type],
|
||||
index,
|
||||
newQueryData,
|
||||
);
|
||||
|
||||
return {
|
||||
...prevState,
|
||||
queryData: updatedQueryBuilderData,
|
||||
[type]: updatedQueryBuilderData,
|
||||
};
|
||||
});
|
||||
},
|
||||
[updateQueryBuilderData],
|
||||
);
|
||||
|
||||
const handleSetQueryData = useCallback(
|
||||
(index: number, newQueryData: IBuilderQuery): void => {
|
||||
setCurrentQuery((prevState) => {
|
||||
const updatedQueryBuilderData = updateQueryBuilderData(
|
||||
prevState.builder.queryData,
|
||||
index,
|
||||
newQueryData,
|
||||
);
|
||||
|
||||
return {
|
||||
...prevState,
|
||||
builder: {
|
||||
...prevState.builder,
|
||||
queryData: updatedQueryBuilderData,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
@ -195,20 +293,23 @@ export function QueryBuilderProvider({
|
||||
);
|
||||
const handleSetFormulaData = useCallback(
|
||||
(index: number, formulaData: IBuilderFormula): void => {
|
||||
setQueryBuilderData((prevState) => {
|
||||
const updatedFormulasBuilderData = updateFormulaBuilderData(
|
||||
prevState.queryFormulas,
|
||||
setCurrentQuery((prevState) => {
|
||||
const updatedFormulasBuilderData = updateQueryBuilderData(
|
||||
prevState.builder.queryFormulas,
|
||||
index,
|
||||
formulaData,
|
||||
);
|
||||
|
||||
return {
|
||||
...prevState,
|
||||
queryFormulas: updatedFormulasBuilderData,
|
||||
builder: {
|
||||
...prevState.builder,
|
||||
queryFormulas: updatedFormulasBuilderData,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
[updateFormulaBuilderData],
|
||||
[updateQueryBuilderData],
|
||||
);
|
||||
|
||||
const handleSetPanelType = useCallback((newPanelType: GRAPH_TYPES) => {
|
||||
@ -217,34 +318,44 @@ export function QueryBuilderProvider({
|
||||
|
||||
const contextValues: QueryBuilderContextType = useMemo(
|
||||
() => ({
|
||||
queryBuilderData,
|
||||
currentQuery,
|
||||
queryType,
|
||||
initialDataSource,
|
||||
panelType,
|
||||
resetQueryBuilderData,
|
||||
resetQueryBuilderInfo,
|
||||
handleSetQueryData,
|
||||
handleSetFormulaData,
|
||||
handleSetQueryItemData,
|
||||
handleSetPanelType,
|
||||
handleSetQueryType,
|
||||
initQueryBuilderData,
|
||||
setupInitialDataSource,
|
||||
removeEntityByIndex,
|
||||
addNewQuery,
|
||||
removeQueryBuilderEntityByIndex,
|
||||
removeQueryTypeItemByIndex,
|
||||
addNewBuilderQuery,
|
||||
addNewFormula,
|
||||
addNewQueryItem,
|
||||
}),
|
||||
[
|
||||
queryBuilderData,
|
||||
currentQuery,
|
||||
initialDataSource,
|
||||
panelType,
|
||||
queryType,
|
||||
resetQueryBuilderData,
|
||||
resetQueryBuilderInfo,
|
||||
handleSetQueryData,
|
||||
handleSetFormulaData,
|
||||
handleSetQueryItemData,
|
||||
handleSetPanelType,
|
||||
handleSetQueryType,
|
||||
initQueryBuilderData,
|
||||
setupInitialDataSource,
|
||||
removeEntityByIndex,
|
||||
addNewQuery,
|
||||
removeQueryBuilderEntityByIndex,
|
||||
removeQueryTypeItemByIndex,
|
||||
addNewBuilderQuery,
|
||||
addNewFormula,
|
||||
addNewQueryItem,
|
||||
],
|
||||
);
|
||||
|
||||
|
@ -1,14 +1,11 @@
|
||||
import getDashboard from 'api/dashboard/get';
|
||||
import {
|
||||
ClickHouseQueryTemplate,
|
||||
PromQLQueryTemplate,
|
||||
} from 'constants/dashboard';
|
||||
import {
|
||||
initialClickHouseData,
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryPromQLData,
|
||||
PANEL_TYPES,
|
||||
} from 'constants/queryBuilder';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import GetQueryName from 'lib/query/GetQueryName';
|
||||
import { Dispatch } from 'redux';
|
||||
import AppActions from 'types/actions';
|
||||
import { Props } from 'types/api/dashboard/get';
|
||||
@ -60,18 +57,8 @@ export const GetDashboard = ({
|
||||
},
|
||||
query: {
|
||||
queryType: EQueryType.QUERY_BUILDER,
|
||||
promql: [
|
||||
{
|
||||
name: GetQueryName([]) as string,
|
||||
...PromQLQueryTemplate,
|
||||
},
|
||||
],
|
||||
clickhouse_sql: [
|
||||
{
|
||||
name: GetQueryName([]) as string,
|
||||
...ClickHouseQueryTemplate,
|
||||
},
|
||||
],
|
||||
promql: [initialQueryPromQLData],
|
||||
clickhouse_sql: [initialClickHouseData],
|
||||
builder: {
|
||||
queryFormulas: [],
|
||||
queryData: [initialQueryBuilderFormValues],
|
||||
|
@ -18,7 +18,7 @@ import { Dispatch } from 'redux';
|
||||
import store from 'store';
|
||||
import AppActions from 'types/actions';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { Query } from 'types/api/dashboard/getAll';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
@ -50,13 +50,18 @@ export async function GetMetricQueryRange({
|
||||
switch (query.queryType) {
|
||||
case EQueryType.QUERY_BUILDER: {
|
||||
const { queryData: data, queryFormulas } = query.builder;
|
||||
const builderQueries = mapQueryDataToApi({
|
||||
queryData: data,
|
||||
queryFormulas,
|
||||
});
|
||||
legendMap = builderQueries.newLegendMap;
|
||||
const currentQueryData = mapQueryDataToApi(data, 'queryName');
|
||||
const currentFormulas = mapQueryDataToApi(queryFormulas, 'queryName');
|
||||
const builderQueries = {
|
||||
...currentQueryData.data,
|
||||
...currentFormulas.data,
|
||||
};
|
||||
legendMap = {
|
||||
...currentQueryData.newLegendMap,
|
||||
...currentFormulas.newLegendMap,
|
||||
};
|
||||
|
||||
QueryPayload.compositeQuery.builderQueries = builderQueries.data;
|
||||
QueryPayload.compositeQuery.builderQueries = builderQueries;
|
||||
break;
|
||||
}
|
||||
case EQueryType.CLICKHOUSE: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Dispatch } from 'redux';
|
||||
import AppActions from 'types/actions';
|
||||
import { Query } from 'types/api/dashboard/getAll';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
export const UpdateQuery = (
|
||||
props: UpdateQueryProps,
|
||||
@ -18,9 +18,6 @@ export const UpdateQuery = (
|
||||
};
|
||||
|
||||
export interface UpdateQueryProps {
|
||||
// query: string;
|
||||
// legend: string;
|
||||
// currentIndex: number;
|
||||
updatedQuery: Query;
|
||||
widgetId: string;
|
||||
yAxisUnit: string | undefined;
|
||||
|
@ -3,9 +3,9 @@ import { ApplySettingsToPanelProps } from 'store/actions/dashboard/applySettings
|
||||
import {
|
||||
Dashboard,
|
||||
IDashboardVariable,
|
||||
Query,
|
||||
Widgets,
|
||||
} from 'types/api/dashboard/getAll';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { QueryData } from 'types/api/widgets/getQuery';
|
||||
|
||||
export const GET_DASHBOARD = 'GET_DASHBOARD';
|
||||
|
@ -1,28 +1,15 @@
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { IClickHouseQuery, IPromQLQuery } from 'types/api/dashboard/getAll';
|
||||
import {
|
||||
BuilderClickHouseResource,
|
||||
BuilderPromQLResource,
|
||||
BuilderQueryDataResourse,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { QueryDataResourse } from 'types/common/queryBuilderMappers.types';
|
||||
|
||||
export interface ICompositeMetricQuery {
|
||||
builderQueries: QueryDataResourse;
|
||||
promQueries: IPromQueries;
|
||||
chQueries: IChQueries;
|
||||
builderQueries: BuilderQueryDataResourse;
|
||||
promQueries: BuilderPromQLResource;
|
||||
chQueries: BuilderClickHouseResource;
|
||||
queryType: EQueryType;
|
||||
panelType: GRAPH_TYPES;
|
||||
}
|
||||
|
||||
export interface IChQueries {
|
||||
[key: string]: IChQuery;
|
||||
}
|
||||
|
||||
export interface IChQuery extends IClickHouseQuery {
|
||||
query: string;
|
||||
}
|
||||
|
||||
export interface IPromQuery extends IPromQLQuery {
|
||||
stats?: '';
|
||||
}
|
||||
|
||||
export interface IPromQueries {
|
||||
[key: string]: IPromQuery;
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
|
||||
import { Layout } from 'react-grid-layout';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { QueryBuilderData } from 'types/common/queryBuilder';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import { QueryData } from '../widgets/getQuery';
|
||||
|
||||
@ -86,25 +85,6 @@ export interface Widgets extends IBaseWidget {
|
||||
export interface PromQLWidgets extends IBaseWidget {
|
||||
query: { query: string; legend: string }[];
|
||||
}
|
||||
export interface Query {
|
||||
queryType: EQueryType;
|
||||
promql: IPromQLQuery[];
|
||||
builder: QueryBuilderData;
|
||||
clickhouse_sql: IClickHouseQuery[];
|
||||
}
|
||||
|
||||
export interface IClickHouseQuery {
|
||||
name: string;
|
||||
rawQuery: string;
|
||||
legend: string;
|
||||
disabled: boolean;
|
||||
}
|
||||
export interface IPromQLQuery {
|
||||
query: string;
|
||||
legend: string;
|
||||
disabled: boolean;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface IQueryBuilderTagFilterItems {
|
||||
id: string;
|
||||
|
@ -1,4 +1,9 @@
|
||||
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import {
|
||||
DataSource,
|
||||
QueryBuilderData,
|
||||
ReduceOperators,
|
||||
} from 'types/common/queryBuilder';
|
||||
|
||||
import { BaseAutocompleteData } from './queryAutocompleteResponse';
|
||||
|
||||
@ -55,3 +60,46 @@ export type IBuilderQuery = {
|
||||
reduceTo: ReduceOperators;
|
||||
legend: string;
|
||||
};
|
||||
|
||||
export interface IClickHouseQuery {
|
||||
name: string;
|
||||
rawQuery: string;
|
||||
legend: string;
|
||||
disabled: boolean;
|
||||
query: string;
|
||||
}
|
||||
export interface IPromQLQuery {
|
||||
query: string;
|
||||
legend: string;
|
||||
disabled: boolean;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Query {
|
||||
queryType: EQueryType;
|
||||
promql: IPromQLQuery[];
|
||||
builder: QueryBuilderData;
|
||||
clickhouse_sql: IClickHouseQuery[];
|
||||
}
|
||||
|
||||
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<
|
||||
string,
|
||||
IBuilderQuery | IBuilderFormula
|
||||
>;
|
||||
|
||||
export type MapData =
|
||||
| IBuilderQuery
|
||||
| IBuilderFormula
|
||||
| IClickHouseQuery
|
||||
| IPromQLQuery;
|
||||
|
||||
export type MapQueryDataToApiResult<T> = {
|
||||
data: T;
|
||||
newLegendMap: Record<string, string>;
|
||||
};
|
||||
|
@ -2,8 +2,13 @@ import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import {
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
IClickHouseQuery,
|
||||
IPromQLQuery,
|
||||
QueryState,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import { EQueryType } from './dashboard';
|
||||
|
||||
export enum DataSource {
|
||||
METRICS = 'metrics',
|
||||
TRACES = 'traces',
|
||||
@ -148,19 +153,34 @@ export type QueryBuilderData = {
|
||||
};
|
||||
|
||||
export type QueryBuilderContextType = {
|
||||
queryBuilderData: QueryBuilderData;
|
||||
currentQuery: QueryState;
|
||||
queryType: EQueryType;
|
||||
initialDataSource: DataSource | null;
|
||||
panelType: GRAPH_TYPES;
|
||||
resetQueryBuilderData: () => void;
|
||||
resetQueryBuilderInfo: () => void;
|
||||
handleSetQueryData: (index: number, queryData: IBuilderQuery) => void;
|
||||
handleSetFormulaData: (index: number, formulaData: IBuilderFormula) => void;
|
||||
handleSetQueryItemData: (
|
||||
index: number,
|
||||
type: EQueryType.PROM | EQueryType.CLICKHOUSE,
|
||||
newQueryData: IPromQLQuery | IClickHouseQuery,
|
||||
) => void;
|
||||
handleSetPanelType: (newPanelType: GRAPH_TYPES) => void;
|
||||
initQueryBuilderData: (queryBuilderData: QueryBuilderData) => void;
|
||||
handleSetQueryType: (newQueryType: EQueryType) => void;
|
||||
initQueryBuilderData: (query: QueryState, queryType: EQueryType) => void;
|
||||
setupInitialDataSource: (newInitialDataSource: DataSource | null) => void;
|
||||
removeEntityByIndex: (type: keyof QueryBuilderData, index: number) => void;
|
||||
addNewQuery: () => void;
|
||||
removeQueryBuilderEntityByIndex: (
|
||||
type: keyof QueryBuilderData,
|
||||
index: number,
|
||||
) => void;
|
||||
removeQueryTypeItemByIndex: (
|
||||
type: EQueryType.PROM | EQueryType.CLICKHOUSE,
|
||||
index: number,
|
||||
) => void;
|
||||
addNewBuilderQuery: () => void;
|
||||
addNewFormula: () => void;
|
||||
addNewQueryItem: (type: EQueryType.PROM | EQueryType.CLICKHOUSE) => void;
|
||||
};
|
||||
|
||||
export type QueryAdditionalFilter = {
|
||||
|
@ -1,14 +0,0 @@
|
||||
import {
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
export type MapQuery = Record<string, IBuilderQuery>;
|
||||
export type MapFormula = Record<string, IBuilderFormula>;
|
||||
|
||||
export type QueryDataResourse = Record<string, IBuilderQuery | IBuilderFormula>;
|
||||
|
||||
export type MapQueryDataToApiResult = {
|
||||
data: QueryDataResourse;
|
||||
newLegendMap: Record<string, string>;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user