Explore: Fix label and history suggestions

- fork promql's tokenizer (need to specify that labels context can only follow beginning of line or whitespace)
- remove unneeded syntax features
- only present history items when field is empty
This commit is contained in:
David Kaltschmidt 2018-11-30 15:13:53 +01:00
parent 1052b17af8
commit a61c8d23d4
3 changed files with 64 additions and 14 deletions

View File

@ -8,9 +8,10 @@ describe('Language completion provider', () => {
};
describe('empty query suggestions', () => {
it('returns default suggestions on emtpty context', () => {
it('returns no suggestions on emtpty context', () => {
const instance = new LanguageProvider(datasource);
const result = instance.provideCompletionItems({ text: '', prefix: '', wrapperClasses: [] });
const value = Plain.deserialize('');
const result = instance.provideCompletionItems({ text: '', prefix: '', value, wrapperClasses: [] });
expect(result.context).toBeUndefined();
expect(result.refresher).toBeUndefined();
expect(result.suggestions.length).toEqual(0);
@ -38,6 +39,32 @@ describe('Language completion provider', () => {
},
]);
});
it('returns no suggestions within regexp', () => {
const instance = new LanguageProvider(datasource);
const value = Plain.deserialize('{} ()');
const range = value.selection.merge({
anchorOffset: 4,
});
const valueWithSelection = value.change().select(range).value;
const history = [
{
query: { refId: '1', expr: '{app="foo"}' },
},
];
const result = instance.provideCompletionItems(
{
text: '',
prefix: '',
value: valueWithSelection,
wrapperClasses: [],
},
{ history }
);
expect(result.context).toBeUndefined();
expect(result.refresher).toBeUndefined();
expect(result.suggestions.length).toEqual(0);
});
});
describe('label suggestions', () => {

View File

@ -10,7 +10,7 @@ import {
HistoryItem,
} from 'app/types/explore';
import { parseSelector, labelRegexp, selectorRegexp } from 'app/plugins/datasource/prometheus/language_utils';
import PromqlSyntax from 'app/plugins/datasource/prometheus/promql';
import syntax from './syntax';
import { DataQuery } from 'app/types';
const DEFAULT_KEYS = ['job', 'namespace'];
@ -55,7 +55,7 @@ export default class LoggingLanguageProvider extends LanguageProvider {
cleanText = s => s.replace(/[{}[\]="(),!~+\-*/^%]/g, '').trim();
getSyntax() {
return PromqlSyntax;
return syntax;
}
request = url => {
@ -70,19 +70,14 @@ export default class LoggingLanguageProvider extends LanguageProvider {
};
// Keep this DOM-free for testing
provideCompletionItems({ prefix, wrapperClasses, text }: TypeaheadInput, context?: any): TypeaheadOutput {
// Syntax spans have 3 classes by default. More indicate a recognized token
const tokenRecognized = wrapperClasses.length > 3;
provideCompletionItems({ prefix, wrapperClasses, text, value }: TypeaheadInput, context?: any): TypeaheadOutput {
// Local text properties
const empty = value.document.text.length === 0;
// Determine candidates by CSS context
if (_.includes(wrapperClasses, 'context-labels')) {
// Suggestions for metric{|} and metric{foo=|}, as well as metric-independent label queries like {|}
// Suggestions for {|} and {foo=|}
return this.getLabelCompletionItems.apply(this, arguments);
} else if (
// Show default suggestions in a couple of scenarios
(prefix && !tokenRecognized) || // Non-empty prefix, but not inside known token
(prefix === '' && !text.match(/^[\]})\s]+$/)) || // Empty prefix, but not following a closing brace
text.match(/[+\-*/^%]/) // Anything after binary operator
) {
} else if (empty) {
return this.getEmptyCompletionItems(context || {});
}

View File

@ -0,0 +1,28 @@
/* tslint:disable max-line-length */
const tokenizer = {
comment: {
pattern: /(^|[^\n])#.*/,
lookbehind: true,
},
'context-labels': {
pattern: /(^|\s)\{[^}]*(?=})/,
lookbehind: true,
inside: {
'label-key': {
pattern: /[a-z_]\w*(?=\s*(=|!=|=~|!~))/,
alias: 'attr-name',
},
'label-value': {
pattern: /"(?:\\.|[^\\"])*"/,
greedy: true,
alias: 'attr-value',
},
},
},
// number: /\b-?\d+((\.\d*)?([eE][+-]?\d+)?)?\b/,
operator: new RegExp(`/&&?|\\|?\\||!=?|<(?:=>?|<|>)?|>[>=]?`, 'i'),
punctuation: /[{}`,.]/,
};
export default tokenizer;