From 39b58a84e653a877d2be5ddde37385d845d25474 Mon Sep 17 00:00:00 2001 From: Damien de Lemeny Date: Wed, 7 Feb 2024 22:18:43 -0500 Subject: [PATCH] Debounce query editor changes, improve usability --- package-lock.json | 17 +++++++++++++++++ package.json | 1 + src/LogContext/components/LogContextUI.tsx | 2 +- src/components/LuceneQueryEditor.tsx | 21 +++++++++++++-------- src/components/QueryEditor/index.tsx | 16 ++-------------- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31fa5a5..7b2d959 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@reduxjs/toolkit": "^1.9.5", "@uiw/react-codemirror": "^4.21.21", "lucene": "^2.1.1", + "observable-hooks": "^4.2.3", "react": "17.0.2", "react-dom": "17.0.2", "tslib": "2.5.3" @@ -13500,6 +13501,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/observable-hooks": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/observable-hooks/-/observable-hooks-4.2.3.tgz", + "integrity": "sha512-d6fYTIU+9sg1V+CT0GhgoE/ntjIqcy9DGaYGE6ELGVP4ojaWIEsaLvL/05hLOM+AL7aySN4DCTLvj6dDF9T8XA==", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0", + "rxjs": ">=6.0.0" + } + }, "node_modules/ol": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/ol/-/ol-7.2.2.tgz", @@ -27897,6 +27908,12 @@ "es-abstract": "^1.20.4" } }, + "observable-hooks": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/observable-hooks/-/observable-hooks-4.2.3.tgz", + "integrity": "sha512-d6fYTIU+9sg1V+CT0GhgoE/ntjIqcy9DGaYGE6ELGVP4ojaWIEsaLvL/05hLOM+AL7aySN4DCTLvj6dDF9T8XA==", + "requires": {} + }, "ol": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/ol/-/ol-7.2.2.tgz", diff --git a/package.json b/package.json index 5af26a3..c78dae5 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "@reduxjs/toolkit": "^1.9.5", "@uiw/react-codemirror": "^4.21.21", "lucene": "^2.1.1", + "observable-hooks": "^4.2.3", "react": "17.0.2", "react-dom": "17.0.2", "tslib": "2.5.3" diff --git a/src/LogContext/components/LogContextUI.tsx b/src/LogContext/components/LogContextUI.tsx index e60fa0c..5c0cd14 100644 --- a/src/LogContext/components/LogContextUI.tsx +++ b/src/LogContext/components/LogContextUI.tsx @@ -64,7 +64,7 @@ export function LogContextUI(props: LogContextUIProps ){
{ActionBar} - +
diff --git a/src/components/LuceneQueryEditor.tsx b/src/components/LuceneQueryEditor.tsx index f0bb3c8..89d193c 100644 --- a/src/components/LuceneQueryEditor.tsx +++ b/src/components/LuceneQueryEditor.tsx @@ -1,16 +1,18 @@ import React, { useRef, useCallback } from "react"; +import { debounceTime } from 'rxjs'; +import { useObservableCallback, useSubscription } from 'observable-hooks' import { css } from "@emotion/css"; -import { LuceneQueryBuilder } from '@/QueryBuilder/lucene'; import CodeMirror, { ReactCodeMirrorRef } from '@uiw/react-codemirror'; import {linter, Diagnostic, lintGutter} from "@codemirror/lint" import {autocompletion, CompletionContext} from "@codemirror/autocomplete" +import { LuceneQuery } from "utils/lucene"; export type LuceneQueryEditorProps = { placeholder?: string, - builder: LuceneQueryBuilder, + value: string, autocompleter: (word: string) => any, onChange: (query: string) => void } @@ -20,8 +22,8 @@ export function LuceneQueryEditor(props: LuceneQueryEditorProps){ const queryLinter = linter( view => { let diagnostics: Diagnostic[] = []; - - const error = props.builder.parsedQuery?.parseError + const query = LuceneQuery.parse(view.state.doc.toString()) + const error = query.parseError if (error) { diagnostics.push({ severity: "error", @@ -33,7 +35,6 @@ export function LuceneQueryEditor(props: LuceneQueryEditorProps){ return diagnostics }) - const {autocompleter} = props; const datasourceCompletions = useCallback(async (context: CompletionContext)=>{ let word = context.matchBefore(/\S*/); @@ -43,19 +44,23 @@ export function LuceneQueryEditor(props: LuceneQueryEditorProps){ from: word.from + suggestions.from, options: suggestions.options } - },[autocompleter]) + }, [autocompleter]) const autocomplete = autocompletion({ override: [datasourceCompletions] }) + const [onChange, textChanged$] = useObservableCallback(event$ => event$.pipe(debounceTime(1000))) + + useSubscription(textChanged$, props.onChange) + return (); } diff --git a/src/components/QueryEditor/index.tsx b/src/components/QueryEditor/index.tsx index c503fe8..14a978c 100644 --- a/src/components/QueryEditor/index.tsx +++ b/src/components/QueryEditor/index.tsx @@ -1,6 +1,6 @@ import { css } from '@emotion/css'; -import React, { createContext, useCallback, useEffect } from 'react'; +import React, { createContext } from 'react'; import { CoreApp, Field, getDefaultTimeRange, GrafanaTheme2, QueryEditorProps } from '@grafana/data'; import { InlineLabel, useStyles2 } from '@grafana/ui'; @@ -18,7 +18,6 @@ import { changeQuery } from './state'; import { QuickwitOptions } from '../../quickwit'; import { QueryTypeSelector } from './QueryTypeSelector'; -import { useQueryBuilder } from '@/QueryBuilder/lucene'; import { getHook } from 'utils/context'; import { LuceneQueryEditor } from '@/components/LuceneQueryEditor'; import { useDatasourceFields } from 'datasource.utils'; @@ -59,23 +58,12 @@ interface Props { export const ElasticSearchQueryField = ({ value, onChange }: { value?: string; onChange: (v: string) => void }) => { const styles = useStyles2(getStyles); - const builder = useQueryBuilder(); - const {setQuery} = builder; const datasource = useDatasource() const { getSuggestions } = useDatasourceFields(datasource); - useEffect(()=>{ - setQuery(value || '') - }, [setQuery, value]) - - const onEditorChange = useCallback((query: string)=>{ - setQuery(query); - onChange(query) - },[setQuery, onChange]) - return (
- +
); };