diff --git a/build_and_start.sh b/build_and_start.sh index efbdaf6..7bca097 100755 --- a/build_and_start.sh +++ b/build_and_start.sh @@ -3,4 +3,4 @@ npm install npm run build mage -v -docker-compose up --build --force-recreate +docker compose up --build --force-recreate diff --git a/src/components/LuceneQueryEditor.tsx b/src/components/LuceneQueryEditor.tsx index 3d4c3f8..99e3518 100644 --- a/src/components/LuceneQueryEditor.tsx +++ b/src/components/LuceneQueryEditor.tsx @@ -2,16 +2,15 @@ import React, { useRef, useCallback } from "react"; import { css } from "@emotion/css"; -import CodeMirror, { ReactCodeMirrorRef, keymap } from '@uiw/react-codemirror'; +import CodeMirror, { ReactCodeMirrorRef, keymap} from '@uiw/react-codemirror'; import {linter, Diagnostic, lintGutter} from "@codemirror/lint" -import {autocompletion, CompletionContext} from "@codemirror/autocomplete" +import {autocompletion, CompletionContext, CompletionResult} from "@codemirror/autocomplete" import { LuceneQuery } from "@/utils/lucene"; - export type LuceneQueryEditorProps = { placeholder?: string, value: string, - autocompleter: (word: string) => any, + autocompleter: (word: string) => CompletionResult, onChange: (query: string) => void onSubmit: (query: string) => void } @@ -39,8 +38,14 @@ export function LuceneQueryEditor(props: LuceneQueryEditorProps){ let suggestions; let word = context.matchBefore(/\S*/); if (!word){ return null } - suggestions = await autocompleter(word?.text); + suggestions = await autocompleter(word?.text); if (suggestions && suggestions.options.length > 0 ) { + // Fixes autocompletion inserting an extra quote when the cursor is before a quote + const cursorIsBeforeQuote = /^\s*"/.test(context.state.doc.toString().slice(context.pos)); + if (cursorIsBeforeQuote) { + suggestions.options = suggestions.options.map(o => ({...o, apply: `${o.label.replace(/"$/g, '')}`})); + } + return { from: word.from + suggestions.from, options: suggestions.options @@ -55,11 +60,11 @@ export function LuceneQueryEditor(props: LuceneQueryEditorProps){ activateOnTyping: false, }) - return ( @@ -199,7 +199,7 @@ export class BaseQuickwitDataSource .map(field_capability => { return { text: field_capability.field_name, - value: fieldTypeMap[field_capability.type], + value: fieldTypeMap[field_capability.type], } }); const uniquefieldCapabilities = fieldCapabilities.filter((field_capability, index, self) => @@ -223,9 +223,10 @@ export class BaseQuickwitDataSource /** * Get tag values for adhoc filters */ - getTagValues(options: any) { - const terms = this.getTerms({ field: options.key }, options.timeRange) - return lastValueFrom(terms, {defaultValue:[]}); + getTagValues(options: { key: string, fieldValue: string, timeRange: TimeRange }) { + const query = `${options.key}:${options.fieldValue}*` + const terms = this.getTerms({ field: options.key, query }, options.timeRange) + return lastValueFrom(terms, { defaultValue: [] }); } /** diff --git a/src/datasource/utils.ts b/src/datasource/utils.ts index e07ba7b..b5bac89 100644 --- a/src/datasource/utils.ts +++ b/src/datasource/utils.ts @@ -38,8 +38,8 @@ export function useDatasourceFields(datasource: BaseQuickwitDataSource, range: T const wordIsField = word.match(/([^:\s]+):"?([^"\s]*)"?/); if (wordIsField?.length) { - const [_match, fieldName, _fieldValue] = wordIsField; - const candidateValues = await datasource.getTagValues({ key: fieldName, timeRange: range }); + const [_match, fieldName, fieldValue] = wordIsField; + const candidateValues = await datasource.getTagValues({ key: fieldName, timeRange: range, fieldValue}); suggestions.from = fieldName.length + 1; // Replace only the value part suggestions.options = candidateValues.map(v => ({ type: 'text',