Skip to content

Commit

Permalink
Debounce query editor changes, improve usability
Browse files Browse the repository at this point in the history
  • Loading branch information
ddelemeny committed Feb 8, 2024
1 parent 55f88c7 commit 39b58a8
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 23 deletions.
17 changes: 17 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion src/LogContext/components/LogContextUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function LogContextUI(props: LogContextUIProps ){
<LogContextQueryBuilderSidebar {...props} builder={builder} updateQuery={setParsedQuery} searchableFields={fields}/>
<div className={css`width:100%; display:flex; flex-direction:column; gap:0.5rem; min-width:0;`}>
{ActionBar}
<LuceneQueryEditor builder={builder} autocompleter={getSuggestions} onChange={builder.setQuery}/>
<LuceneQueryEditor value={builder.query} autocompleter={getSuggestions} onChange={builder.setQuery}/>
</div>
</DatasourceContext.Provider>
</div>
Expand Down
21 changes: 13 additions & 8 deletions src/components/LuceneQueryEditor.tsx
Original file line number Diff line number Diff line change
@@ -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
}
Expand All @@ -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",
Expand All @@ -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*/);
Expand All @@ -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<string>(event$ => event$.pipe(debounceTime(1000)))

useSubscription(textChanged$, props.onChange)

return (<CodeMirror
ref={editorRef}
className={css`height:100%`} // XXX : need to set height for both wrapper elements
height="100%"
theme={'dark'}
placeholder={props.placeholder}
value={props.builder.query}
onChange={props.onChange}
value={props.value}
onChange={onChange}
extensions={[queryLinter, lintGutter(), autocomplete]}
/>);
}
16 changes: 2 additions & 14 deletions src/components/QueryEditor/index.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';
Expand Down Expand Up @@ -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 (
<div className={styles.queryItem}>
<LuceneQueryEditor placeholder="Enter a lucene query" builder={builder} autocompleter={getSuggestions} onChange={onEditorChange}/>
<LuceneQueryEditor placeholder="Enter a lucene query" value={value || ''} autocompleter={getSuggestions} onChange={onChange}/>
</div>
);
};
Expand Down

0 comments on commit 39b58a8

Please sign in to comment.