mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 02:40:26 -06:00
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:
parent
1052b17af8
commit
a61c8d23d4
@ -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', () => {
|
||||
|
@ -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 || {});
|
||||
}
|
||||
|
||||
|
28
public/app/plugins/datasource/logging/syntax.ts
Normal file
28
public/app/plugins/datasource/logging/syntax.ts
Normal 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;
|
Loading…
Reference in New Issue
Block a user