Compare commits
10 Commits
main
...
fix/issue-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca30fad405 | ||
|
|
2bd9ee3647 | ||
|
|
d6050cda81 | ||
|
|
f6c98cad6c | ||
|
|
ed2d4c84f0 | ||
|
|
32ae61af6d | ||
|
|
fafa13fb52 | ||
|
|
5b9269769d | ||
|
|
af2f36adfa | ||
|
|
471d15945c |
@@ -89,7 +89,7 @@ function QuerySearch({
|
||||
hardcodedAttributeKeys,
|
||||
}: {
|
||||
placeholder?: string;
|
||||
onChange: (value: string) => void;
|
||||
onChange: (value: string, syncExpression?: boolean) => void;
|
||||
queryData: IBuilderQuery;
|
||||
dataSource: DataSource;
|
||||
signalSource?: string;
|
||||
@@ -97,7 +97,7 @@ function QuerySearch({
|
||||
onRun?: (query: string) => void;
|
||||
}): JSX.Element {
|
||||
const isDarkMode = useIsDarkMode();
|
||||
const [query, setQuery] = useState<string>(queryData.filter?.expression || '');
|
||||
const [query, setQuery] = useState<string>('');
|
||||
const [valueSuggestions, setValueSuggestions] = useState<any[]>([]);
|
||||
const [activeKey, setActiveKey] = useState<string>('');
|
||||
const [isLoadingSuggestions, setIsLoadingSuggestions] = useState(false);
|
||||
@@ -108,6 +108,10 @@ function QuerySearch({
|
||||
errors: [],
|
||||
});
|
||||
|
||||
const [cursorPos, setCursorPos] = useState({ line: 0, ch: 0 });
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const [hasInteractedWithQB, setHasInteractedWithQB] = useState(false);
|
||||
|
||||
const handleQueryValidation = (newQuery: string): void => {
|
||||
try {
|
||||
const validationResponse = validateQuery(newQuery);
|
||||
@@ -127,13 +131,28 @@ function QuerySearch({
|
||||
|
||||
useEffect(() => {
|
||||
const newQuery = queryData.filter?.expression || '';
|
||||
// Only mark as external change if the query actually changed from external source
|
||||
// Only update query from external source when editor is not focused
|
||||
// When focused, just update the lastExternalQuery to track changes
|
||||
if (newQuery !== lastExternalQuery) {
|
||||
setQuery(newQuery);
|
||||
setIsExternalQueryChange(true);
|
||||
setLastExternalQuery(newQuery);
|
||||
}
|
||||
}, [queryData.filter?.expression, lastExternalQuery]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [queryData.filter?.expression]);
|
||||
|
||||
useEffect(() => {
|
||||
// Update the query when the editor is blurred and the query has changed
|
||||
// Only call onChange if the editor has been focused before (not on initial mount)
|
||||
if (
|
||||
!isFocused &&
|
||||
hasInteractedWithQB &&
|
||||
query !== queryData.filter?.expression
|
||||
) {
|
||||
onChange(query, true);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isFocused]);
|
||||
|
||||
// Validate query when it changes externally (from queryData)
|
||||
useEffect(() => {
|
||||
@@ -149,9 +168,6 @@ function QuerySearch({
|
||||
|
||||
const [showExamples] = useState(false);
|
||||
|
||||
const [cursorPos, setCursorPos] = useState({ line: 0, ch: 0 });
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
const [
|
||||
isFetchingCompleteValuesList,
|
||||
setIsFetchingCompleteValuesList,
|
||||
@@ -1352,8 +1368,13 @@ function QuerySearch({
|
||||
}}
|
||||
onFocus={(): void => {
|
||||
setIsFocused(true);
|
||||
setHasInteractedWithQB(true);
|
||||
}}
|
||||
onBlur={handleBlur}
|
||||
onCreateEditor={(view: EditorView): EditorView => {
|
||||
editorRef.current = view;
|
||||
return view;
|
||||
}}
|
||||
/>
|
||||
|
||||
{query && validation.isValid === false && !isFocused && (
|
||||
|
||||
@@ -34,7 +34,11 @@ export const QueryV2 = memo(function QueryV2({
|
||||
signalSource = '',
|
||||
isMultiQueryAllowed = false,
|
||||
}: QueryProps & { ref: React.RefObject<HTMLDivElement> }): JSX.Element {
|
||||
const { cloneQuery, panelType } = useQueryBuilder();
|
||||
const {
|
||||
cloneQuery,
|
||||
panelType,
|
||||
handleSetCurrentFilterExpression,
|
||||
} = useQueryBuilder();
|
||||
|
||||
const showFunctions = query?.functions?.length > 0;
|
||||
const { dataSource } = query;
|
||||
@@ -96,12 +100,16 @@ export const QueryV2 = memo(function QueryV2({
|
||||
);
|
||||
|
||||
const handleSearchChange = useCallback(
|
||||
(value: string) => {
|
||||
(handleChangeQueryData as HandleChangeQueryDataV5)('filter', {
|
||||
expression: value,
|
||||
});
|
||||
(value: string, syncExpression = false) => {
|
||||
handleSetCurrentFilterExpression(value, query.queryName);
|
||||
if (syncExpression) {
|
||||
(handleChangeQueryData as HandleChangeQueryDataV5)('filter', {
|
||||
expression: value,
|
||||
});
|
||||
}
|
||||
},
|
||||
[handleChangeQueryData],
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[handleSetCurrentFilterExpression, handleChangeQueryData],
|
||||
);
|
||||
|
||||
const handleChangeAggregation = useCallback(
|
||||
|
||||
@@ -61,6 +61,8 @@ export const logsQueryRangeSuccessNewFormatResponse = {
|
||||
};
|
||||
|
||||
export const mockQueryBuilderContextValue = {
|
||||
currentFilterExpression: {},
|
||||
handleSetCurrentFilterExpression: noop,
|
||||
isDefaultQuery: (): boolean => false,
|
||||
currentQuery: {
|
||||
...initialQueriesMap.logs,
|
||||
|
||||
@@ -183,6 +183,8 @@ describe('Logs Explorer Tests', () => {
|
||||
>
|
||||
<QueryBuilderContext.Provider
|
||||
value={{
|
||||
currentFilterExpression: {},
|
||||
handleSetCurrentFilterExpression: noop,
|
||||
isDefaultQuery: (): boolean => false,
|
||||
currentQuery: {
|
||||
...initialQueriesMap.metrics,
|
||||
|
||||
@@ -65,6 +65,7 @@ import { sanitizeOrderByForExplorer } from 'utils/sanitizeOrderBy';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
||||
currentFilterExpression: {},
|
||||
currentQuery: initialQueriesMap.metrics,
|
||||
supersetQuery: initialQueriesMap.metrics,
|
||||
lastUsedQuery: null,
|
||||
@@ -74,6 +75,7 @@ export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
||||
initialDataSource: null,
|
||||
panelType: PANEL_TYPES.TIME_SERIES,
|
||||
isEnabledQuery: false,
|
||||
handleSetCurrentFilterExpression: () => {},
|
||||
handleSetQueryData: () => {},
|
||||
handleSetTraceOperatorData: () => {},
|
||||
handleSetFormulaData: () => {},
|
||||
@@ -133,6 +135,9 @@ export function QueryBuilderProvider({
|
||||
const [supersetQuery, setSupersetQuery] = useState<QueryState>(queryState);
|
||||
const [lastUsedQuery, setLastUsedQuery] = useState<number | null>(0);
|
||||
const [stagedQuery, setStagedQuery] = useState<Query | null>(null);
|
||||
const [currentFilterExpression, setCurrentFilterExpression] = useState<
|
||||
Record<string, string | undefined>
|
||||
>({});
|
||||
|
||||
const [queryType, setQueryType] = useState<EQueryType>(queryTypeParam);
|
||||
|
||||
@@ -257,6 +262,7 @@ export function QueryBuilderProvider({
|
||||
|
||||
setStagedQuery(nextQuery);
|
||||
setCurrentQuery(newQueryState);
|
||||
setCurrentFilterExpression({});
|
||||
setQueryType(type);
|
||||
},
|
||||
[prepareQueryBuilderData],
|
||||
@@ -386,6 +392,16 @@ export function QueryBuilderProvider({
|
||||
[],
|
||||
);
|
||||
|
||||
const handleSetCurrentFilterExpression = useCallback(
|
||||
(expression: string, queryName: string) => {
|
||||
setCurrentFilterExpression((prevState) => ({
|
||||
...prevState,
|
||||
[queryName]: expression,
|
||||
}));
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const removeQueryBuilderEntityByIndex = useCallback(
|
||||
(type: keyof QueryBuilderData, index: number) => {
|
||||
setCurrentQuery((prevState) => {
|
||||
@@ -1027,9 +1043,10 @@ export function QueryBuilderProvider({
|
||||
filter: {
|
||||
...item.filter,
|
||||
expression:
|
||||
item.filter?.expression.trim() === ''
|
||||
currentFilterExpression[item.queryName] ??
|
||||
(item.filter?.expression?.trim() === ''
|
||||
? ''
|
||||
: item.filter?.expression ?? '',
|
||||
: item.filter?.expression ?? ''),
|
||||
},
|
||||
filters: {
|
||||
items: [],
|
||||
@@ -1053,7 +1070,13 @@ export function QueryBuilderProvider({
|
||||
},
|
||||
queryType,
|
||||
});
|
||||
}, [currentQuery, location.pathname, queryType, redirectWithQueryBuilderData]);
|
||||
}, [
|
||||
currentQuery,
|
||||
location.pathname,
|
||||
queryType,
|
||||
redirectWithQueryBuilderData,
|
||||
currentFilterExpression,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (location.pathname !== currentPathnameRef.current) {
|
||||
@@ -1141,6 +1164,7 @@ export function QueryBuilderProvider({
|
||||
|
||||
const contextValues: QueryBuilderContextType = useMemo(
|
||||
() => ({
|
||||
currentFilterExpression,
|
||||
currentQuery: query,
|
||||
supersetQuery: superQuery,
|
||||
lastUsedQuery,
|
||||
@@ -1150,6 +1174,7 @@ export function QueryBuilderProvider({
|
||||
initialDataSource,
|
||||
panelType,
|
||||
isEnabledQuery,
|
||||
handleSetCurrentFilterExpression,
|
||||
handleSetQueryData,
|
||||
handleSetTraceOperatorData,
|
||||
handleSetFormulaData,
|
||||
@@ -1175,6 +1200,7 @@ export function QueryBuilderProvider({
|
||||
isStagedQueryUpdated,
|
||||
}),
|
||||
[
|
||||
currentFilterExpression,
|
||||
query,
|
||||
superQuery,
|
||||
lastUsedQuery,
|
||||
@@ -1182,6 +1208,7 @@ export function QueryBuilderProvider({
|
||||
initialDataSource,
|
||||
panelType,
|
||||
isEnabledQuery,
|
||||
handleSetCurrentFilterExpression,
|
||||
handleSetQueryData,
|
||||
handleSetTraceOperatorData,
|
||||
handleSetFormulaData,
|
||||
|
||||
@@ -227,6 +227,7 @@ export type QueryBuilderData = {
|
||||
};
|
||||
|
||||
export type QueryBuilderContextType = {
|
||||
currentFilterExpression: Record<string, string | undefined>;
|
||||
currentQuery: Query;
|
||||
stagedQuery: Query | null;
|
||||
lastUsedQuery: number | null;
|
||||
@@ -241,6 +242,10 @@ export type QueryBuilderContextType = {
|
||||
index: number,
|
||||
traceOperatorData: IBuilderTraceOperator,
|
||||
) => void;
|
||||
handleSetCurrentFilterExpression: (
|
||||
expression: string,
|
||||
queryName: string,
|
||||
) => void;
|
||||
handleSetFormulaData: (index: number, formulaData: IBuilderFormula) => void;
|
||||
handleSetQueryItemData: (
|
||||
index: number,
|
||||
|
||||
Reference in New Issue
Block a user