diff --git a/frontend/src/providers/QueryBuilder.tsx b/frontend/src/providers/QueryBuilder.tsx index 9bde92a49a90..32d76539b1ee 100644 --- a/frontend/src/providers/QueryBuilder.tsx +++ b/frontend/src/providers/QueryBuilder.tsx @@ -7,6 +7,7 @@ import { initialClickHouseData, initialFormulaBuilderFormValues, initialQueriesMap, + initialQueryBuilderFormTraceOperatorValues, initialQueryBuilderFormValuesMap, initialQueryPromQLData, initialQueryState, @@ -47,6 +48,7 @@ import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteRe import { IBuilderFormula, IBuilderQuery, + IBuilderTraceOperator, IClickHouseQuery, IPromQLQuery, Query, @@ -74,14 +76,18 @@ export const QueryBuilderContext = createContext({ panelType: PANEL_TYPES.TIME_SERIES, isEnabledQuery: false, handleSetQueryData: () => {}, + handleSetTraceOperatorData: () => {}, handleSetFormulaData: () => {}, handleSetQueryItemData: () => {}, handleSetConfig: () => {}, removeQueryBuilderEntityByIndex: () => {}, + removeAllQueryBuilderEntities: () => {}, removeQueryTypeItemByIndex: () => {}, addNewBuilderQuery: () => {}, cloneQuery: () => {}, addNewFormula: () => {}, + addTraceOperator: () => {}, + removeTraceOperator: () => {}, addNewQueryItem: () => {}, redirectWithQueryBuilderData: () => {}, handleRunQuery: () => {}, @@ -166,6 +172,10 @@ export function QueryBuilderProvider({ ...initialFormulaBuilderFormValues, ...item, })), + queryTraceOperator: query.builder.queryTraceOperator?.map((item) => ({ + ...initialQueryBuilderFormTraceOperatorValues, + ...item, + })), }; const setupedQueryData = builder.queryData.map((item) => { @@ -367,8 +377,11 @@ export function QueryBuilderProvider({ const removeQueryBuilderEntityByIndex = useCallback( (type: keyof QueryBuilderData, index: number) => { setCurrentQuery((prevState) => { - const currentArray: (IBuilderQuery | IBuilderFormula)[] = - prevState.builder[type]; + const currentArray: ( + | IBuilderQuery + | IBuilderFormula + | IBuilderTraceOperator + )[] = prevState.builder[type]; const filteredArray = currentArray.filter((_, i) => index !== i); @@ -382,8 +395,11 @@ export function QueryBuilderProvider({ }); // eslint-disable-next-line sonarjs/no-identical-functions setSupersetQuery((prevState) => { - const currentArray: (IBuilderQuery | IBuilderFormula)[] = - prevState.builder[type]; + const currentArray: ( + | IBuilderQuery + | IBuilderFormula + | IBuilderTraceOperator + )[] = prevState.builder[type]; const filteredArray = currentArray.filter((_, i) => index !== i); @@ -399,6 +415,20 @@ export function QueryBuilderProvider({ [], ); + const removeAllQueryBuilderEntities = useCallback( + (type: keyof QueryBuilderData) => { + setCurrentQuery((prevState) => ({ + ...prevState, + builder: { ...prevState.builder, [type]: [] }, + })); + setSupersetQuery((prevState) => ({ + ...prevState, + builder: { ...prevState.builder, [type]: [] }, + })); + }, + [setCurrentQuery, setSupersetQuery], + ); + const removeQueryTypeItemByIndex = useCallback( (type: EQueryType.PROM | EQueryType.CLICKHOUSE, index: number) => { setCurrentQuery((prevState) => { @@ -617,6 +647,72 @@ export function QueryBuilderProvider({ }); }, [createNewBuilderFormula]); + const addTraceOperator = useCallback((expression: string = '') => { + const trimmed = (expression || '').trim(); + + setCurrentQuery((prevState) => { + const existing = prevState.builder.queryTraceOperator[0]; + const updated: IBuilderTraceOperator = existing + ? { ...existing, expression: trimmed } + : { + ...initialQueryBuilderFormTraceOperatorValues, + queryName: 'T1', + expression: trimmed, + }; + + return { + ...prevState, + builder: { + ...prevState.builder, + // enforce single trace operator and replace only expression + queryTraceOperator: [updated], + }, + }; + }); + // eslint-disable-next-line sonarjs/no-identical-functions + setSupersetQuery((prevState) => { + const existing = prevState.builder.queryTraceOperator[0]; + const updated: IBuilderTraceOperator = existing + ? { ...existing, expression: trimmed } + : { + ...initialQueryBuilderFormTraceOperatorValues, + queryName: 'T1', + expression: trimmed, + }; + + return { + ...prevState, + builder: { + ...prevState.builder, + // enforce single trace operator and replace only expression + queryTraceOperator: [updated], + }, + }; + }); + }, []); + + const removeTraceOperator = useCallback(() => { + setCurrentQuery((prevState) => { + return { + ...prevState, + builder: { + ...prevState.builder, + queryTraceOperator: [], + }, + }; + }); + // eslint-disable-next-line sonarjs/no-identical-functions + setSupersetQuery((prevState) => { + return { + ...prevState, + builder: { + ...prevState.builder, + queryTraceOperator: [], + }, + }; + }); + }, []); + const updateQueryBuilderData: ( arr: T[], index: number, @@ -723,6 +819,44 @@ export function QueryBuilderProvider({ }, [updateQueryBuilderData, updateSuperSetQueryBuilderData], ); + + const handleSetTraceOperatorData = useCallback( + (index: number, traceOperatorData: IBuilderTraceOperator): void => { + setCurrentQuery((prevState) => { + const updatedTraceOperatorBuilderData = updateQueryBuilderData( + prevState.builder.queryTraceOperator, + index, + traceOperatorData, + ); + + return { + ...prevState, + builder: { + ...prevState.builder, + queryTraceOperator: updatedTraceOperatorBuilderData, + }, + }; + }); + // eslint-disable-next-line sonarjs/no-identical-functions + setSupersetQuery((prevState) => { + const updatedTraceOperatorBuilderData = updateQueryBuilderData( + prevState.builder.queryTraceOperator, + index, + traceOperatorData, + ); + + return { + ...prevState, + builder: { + ...prevState.builder, + queryTraceOperator: updatedTraceOperatorBuilderData, + }, + }; + }); + }, + [updateQueryBuilderData], + ); + const handleSetFormulaData = useCallback( (index: number, formulaData: IBuilderFormula): void => { setCurrentQuery((prevState) => { @@ -1009,14 +1143,18 @@ export function QueryBuilderProvider({ panelType, isEnabledQuery, handleSetQueryData, + handleSetTraceOperatorData, handleSetFormulaData, handleSetQueryItemData, handleSetConfig, removeQueryBuilderEntityByIndex, removeQueryTypeItemByIndex, + removeAllQueryBuilderEntities, cloneQuery, addNewBuilderQuery, addNewFormula, + addTraceOperator, + removeTraceOperator, addNewQueryItem, redirectWithQueryBuilderData, handleRunQuery, @@ -1037,14 +1175,18 @@ export function QueryBuilderProvider({ panelType, isEnabledQuery, handleSetQueryData, + handleSetTraceOperatorData, handleSetFormulaData, handleSetQueryItemData, handleSetConfig, removeQueryBuilderEntityByIndex, removeQueryTypeItemByIndex, + removeAllQueryBuilderEntities, cloneQuery, addNewBuilderQuery, addNewFormula, + addTraceOperator, + removeTraceOperator, addNewQueryItem, redirectWithQueryBuilderData, handleRunQuery, diff --git a/frontend/src/types/api/queryBuilder/queryBuilderData.ts b/frontend/src/types/api/queryBuilder/queryBuilderData.ts index 82a5aa820743..f2c8da199229 100644 --- a/frontend/src/types/api/queryBuilder/queryBuilderData.ts +++ b/frontend/src/types/api/queryBuilder/queryBuilderData.ts @@ -29,6 +29,13 @@ export interface IBuilderFormula { orderBy?: OrderByPayload[]; } +export type IBuilderTraceOperator = Omit< + IBuilderQuery, + 'dataSource' | 'filter' | 'filters' | 'disabled' | 'functions' +> & { + returnSpansFrom?: string; +}; + export interface TagFilterItem { id: string; key?: BaseAutocompleteData; @@ -124,6 +131,7 @@ export type BuilderQueryDataResourse = Record< export type MapData = | IBuilderQuery | IBuilderFormula + | IBuilderTraceOperator | IClickHouseQuery | IPromQLQuery; diff --git a/frontend/src/types/api/v5/queryRange.ts b/frontend/src/types/api/v5/queryRange.ts index bd56c8e5e521..5aed319ad5e5 100644 --- a/frontend/src/types/api/v5/queryRange.ts +++ b/frontend/src/types/api/v5/queryRange.ts @@ -14,6 +14,7 @@ export type RequestType = export type QueryType = | 'builder_query' + | 'builder_trace_operator' | 'builder_formula' | 'builder_sub_query' | 'builder_join' diff --git a/frontend/src/types/common/operations.types.ts b/frontend/src/types/common/operations.types.ts index 3994bfda401b..db0e292751e7 100644 --- a/frontend/src/types/common/operations.types.ts +++ b/frontend/src/types/common/operations.types.ts @@ -4,6 +4,7 @@ import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteRe import { IBuilderFormula, IBuilderQuery, + IBuilderTraceOperator, } from 'types/api/queryBuilder/queryBuilderData'; import { BaseBuilderQuery, @@ -32,6 +33,14 @@ export type HandleChangeQueryData = < value: Value, ) => void; +export type HandleChangeTraceOperatorData = < + Key extends keyof T, + Value extends T[Key] +>( + key: Key, + value: Value, +) => void; + // Legacy version for backward compatibility export type HandleChangeQueryDataLegacy = HandleChangeQueryData; @@ -66,3 +75,10 @@ export type UseQueryOperations = ( handleQueryFunctionsUpdates: (functions: QueryFunction[]) => void; listOfAdditionalFormulaFilters: string[]; }; + +export type UseTraceOperatorOperations = (params: { + index?: number; + query?: IBuilderTraceOperator; +}) => { + handleChangeTraceOperatorData: HandleChangeTraceOperatorData; +}; diff --git a/frontend/src/types/common/queryBuilder.ts b/frontend/src/types/common/queryBuilder.ts index 3a5c73502fec..9c90fc9ac580 100644 --- a/frontend/src/types/common/queryBuilder.ts +++ b/frontend/src/types/common/queryBuilder.ts @@ -6,6 +6,7 @@ import { Dispatch, SetStateAction } from 'react'; import { IBuilderFormula, IBuilderQuery, + IBuilderTraceOperator, IClickHouseQuery, IPromQLQuery, Query, @@ -222,6 +223,7 @@ export type ReduceOperators = 'last' | 'sum' | 'avg' | 'max' | 'min'; export type QueryBuilderData = { queryData: IBuilderQuery[]; queryFormulas: IBuilderFormula[]; + queryTraceOperator: IBuilderTraceOperator[]; }; export type QueryBuilderContextType = { @@ -235,6 +237,10 @@ export type QueryBuilderContextType = { panelType: PANEL_TYPES | null; isEnabledQuery: boolean; handleSetQueryData: (index: number, queryData: IBuilderQuery) => void; + handleSetTraceOperatorData: ( + index: number, + traceOperatorData: IBuilderTraceOperator, + ) => void; handleSetFormulaData: (index: number, formulaData: IBuilderFormula) => void; handleSetQueryItemData: ( index: number, @@ -249,12 +255,15 @@ export type QueryBuilderContextType = { type: keyof QueryBuilderData, index: number, ) => void; + removeAllQueryBuilderEntities: (type: keyof QueryBuilderData) => void; removeQueryTypeItemByIndex: ( type: EQueryType.PROM | EQueryType.CLICKHOUSE, index: number, ) => void; addNewBuilderQuery: () => void; addNewFormula: () => void; + removeTraceOperator: () => void; + addTraceOperator: (expression?: string) => void; cloneQuery: (type: string, query: IBuilderQuery) => void; addNewQueryItem: (type: EQueryType.PROM | EQueryType.CLICKHOUSE) => void; redirectWithQueryBuilderData: (