diff --git a/frontend/src/components/QueryBuilderV2/CodeMirrorWhereClause/CodeMirrorWhereClause.tsx b/frontend/src/components/QueryBuilderV2/CodeMirrorWhereClause/CodeMirrorWhereClause.tsx index 73169d9c6e93..9327dd2d984a 100644 --- a/frontend/src/components/QueryBuilderV2/CodeMirrorWhereClause/CodeMirrorWhereClause.tsx +++ b/frontend/src/components/QueryBuilderV2/CodeMirrorWhereClause/CodeMirrorWhereClause.tsx @@ -16,8 +16,11 @@ import { } from '@codemirror/autocomplete'; import CodeMirror, { EditorView } from '@uiw/react-codemirror'; import { Badge, Card, Divider, Space, Tooltip, Typography } from 'antd'; +import { useGetQueryKeySuggestions } from 'hooks/querySuggestions/useGetQueryKeySuggestions'; +// import { useGetQueryKeyValueSuggestions } from 'hooks/querySuggestions/useGetQueryKeyValueSuggestions'; import { useCallback, useEffect, useRef, useState } from 'react'; import { IQueryContext, IValidationResult } from 'types/antlrQueryTypes'; +import { QueryKeySuggestionsProps } from 'types/api/querySuggestions/types'; import { getQueryContextAtCursor, validateQuery } from 'utils/antlrQueryUtils'; const { Text, Title } = Typography; @@ -32,9 +35,58 @@ function CodeMirrorWhereClause(): JSX.Element { errors: [], }); + const [keySuggestions, setKeySuggestions] = useState< + QueryKeySuggestionsProps[] | null + >(null); + const [cursorPos, setCursorPos] = useState({ line: 0, ch: 0 }); const lastPosRef = useRef<{ line: number; ch: number }>({ line: 0, ch: 0 }); + const { + data: queryKeySuggestions, + // isLoading: queryKeySuggestionsLoading, + // isRefetching: queryKeySuggestionsRefetching, + // refetch: queryKeySuggestionsRefetch, + // error: queryKeySuggestionsError, + // isError: queryKeySuggestionsIsError, + } = useGetQueryKeySuggestions({ signal: 'traces' }); + + // const { + // data: queryKeyValuesSuggestions, + // isLoading: queryKeyValuesSuggestionsLoading, + // refetch: refetchQueryKeyValuesSuggestions, + // } = useGetQueryKeyValueSuggestions({ + // signal: 'traces', + // key: 'status', + // }); + + const generateOptions = (data: any): any[] => { + const options = Object.values(data.keys).flatMap((items: any) => + items.map(({ name, fieldDataType, fieldContext }: any) => ({ + label: name, + type: fieldDataType === 'string' ? 'keyword' : fieldDataType, + info: fieldContext, + details: '', + })), + ); + + console.log('options', options); + + return options; + }; + + useEffect(() => { + if (queryKeySuggestions) { + console.log('queryKeySuggestions', queryKeySuggestions); + + const options = generateOptions(queryKeySuggestions.data.data); + + setKeySuggestions(options); + } + }, [queryKeySuggestions]); + + console.log('keySuggestions', keySuggestions); + const handleUpdate = (viewUpdate: { view: EditorView }): void => { const selection = viewUpdate.view.state.selection.main; const pos = selection.head; @@ -145,18 +197,41 @@ function CodeMirrorWhereClause(): JSX.Element { }[] = []; if (queryContext.isInKey) { - options = [ - { label: 'status', type: 'keyword' }, - { label: 'service', type: 'keyword' }, - // Add more key options here - ]; + options = keySuggestions || []; } else if (queryContext.isInOperator) { options = [ - { label: '=', type: 'operator' }, - { label: '!=', type: 'operator' }, + { label: '=', type: 'operator', info: 'Equal to' }, + { label: '!=', type: 'operator', info: 'Not equal to' }, + { label: '>', type: 'operator', info: 'Greater than' }, + { label: '<', type: 'operator', info: 'Less than' }, + { label: '>=', type: 'operator', info: 'Greater than or equal to' }, + { label: '<=', type: 'operator', info: 'Less than or equal to' }, + { label: 'LIKE', type: 'operator', info: 'Like' }, + { label: 'ILIKE', type: 'operator', info: 'Case insensitive like' }, + { label: 'BETWEEN', type: 'operator', info: 'Between' }, + { label: 'EXISTS', type: 'operator', info: 'Exists' }, + { label: 'REGEXP', type: 'operator', info: 'Regular expression' }, + { label: 'CONTAINS', type: 'operator', info: 'Contains' }, + { label: 'IN', type: 'operator', info: 'In' }, + { label: 'NOT', type: 'operator', info: 'Not' }, // Add more operator options here ]; } else if (queryContext.isInValue) { + // refetchQueryKeyValuesSuggestions(); + + // Fetch values based on the key + const key = queryContext.currentToken; + // refetchQueryKeyValuesSuggestions({ key }).then((response) => { + // if (response && response.data && Array.isArray(response.data.values)) { + // options = response.data.values.map((value: string) => ({ + // label: value, + // type: 'value', + // })); + // } + // }); + + console.log('key', key, queryContext, query); + options = [ { label: 'error', type: 'value' }, { label: 'frontend', type: 'value' }, diff --git a/frontend/src/hooks/querySuggestions/useGetQueryKeySuggestions.ts b/frontend/src/hooks/querySuggestions/useGetQueryKeySuggestions.ts index 11da1e266c51..4bc6f0f15ac2 100644 --- a/frontend/src/hooks/querySuggestions/useGetQueryKeySuggestions.ts +++ b/frontend/src/hooks/querySuggestions/useGetQueryKeySuggestions.ts @@ -3,11 +3,15 @@ import { AxiosError, AxiosResponse } from 'axios'; import { useQuery, UseQueryResult } from 'react-query'; import { QueryKeySuggestionsResponseProps } from 'types/api/querySuggestions/types'; -export const useGetQueryKeySuggestions = (): UseQueryResult< +export const useGetQueryKeySuggestions = ({ + signal, +}: { + signal: string; +}): UseQueryResult< AxiosResponse, AxiosError > => useQuery, AxiosError>({ queryKey: ['queryKeySuggestions'], - queryFn: () => getKeySuggestions({ signal: 'trace' }), + queryFn: () => getKeySuggestions({ signal }), }); diff --git a/frontend/src/hooks/querySuggestions/useGetQueryKeyValueSuggestions.ts b/frontend/src/hooks/querySuggestions/useGetQueryKeyValueSuggestions.ts index ec92d1e0a82b..d53534d743cb 100644 --- a/frontend/src/hooks/querySuggestions/useGetQueryKeyValueSuggestions.ts +++ b/frontend/src/hooks/querySuggestions/useGetQueryKeyValueSuggestions.ts @@ -3,11 +3,17 @@ import { AxiosError, AxiosResponse } from 'axios'; import { useQuery, UseQueryResult } from 'react-query'; import { QueryKeyValueSuggestionsResponseProps } from 'types/api/querySuggestions/types'; -export const useGetQueryKeyValueSuggestions = (): UseQueryResult< +export const useGetQueryKeyValueSuggestions = ({ + key, + signal, +}: { + key: string; + signal: string; +}): UseQueryResult< AxiosResponse, AxiosError > => useQuery, AxiosError>({ - queryKey: ['queryKeyValueSuggestions'], - queryFn: () => getValueSuggestions({ signal: 'trace', key: 'trace' }), + queryKey: ['queryKeyValueSuggestions', key, signal], + queryFn: () => getValueSuggestions({ signal, key }), }); diff --git a/frontend/src/types/api/querySuggestions/types.ts b/frontend/src/types/api/querySuggestions/types.ts index 5ee34a21d363..a54300a7684b 100644 --- a/frontend/src/types/api/querySuggestions/types.ts +++ b/frontend/src/types/api/querySuggestions/types.ts @@ -1,6 +1,9 @@ export interface QueryKeySuggestionsProps { - id: string; - name: string; + label: string; + type: string; + info?: string; + apply?: string; + detail?: string; } export interface QueryKeySuggestionsResponseProps { diff --git a/frontend/src/utils/antlrQueryUtils.ts b/frontend/src/utils/antlrQueryUtils.ts index ae6000ff2aa9..d1b39a8eeccf 100644 --- a/frontend/src/utils/antlrQueryUtils.ts +++ b/frontend/src/utils/antlrQueryUtils.ts @@ -233,14 +233,6 @@ export function getQueryContextAtCursor( } } - console.log('Cursor context:', { - cursorIndex, - query, - exact: exactToken, - prev: previousToken, - next: nextToken, - }); - // Determine the context based on cursor position and surrounding tokens let currentToken: IToken | null = null; @@ -401,6 +393,21 @@ export function getQueryContextAtCursor( isInParenthesis: false, }; } + if (isInParenthesis && query[currentToken.stop + 1] === ' ') { + return { + tokenType: currentToken.type, + text: currentToken.text, + start: currentToken.start, + stop: currentToken.stop, + currentToken: currentToken.text, + isInValue: false, + isInKey: false, // Suggest keys + isInOperator: false, + isInFunction: false, + isInConjunction: true, // Suggest conjunctions + isInParenthesis: false, + }; + } return { tokenType: currentToken.type,