Prometheus: Fix label value suggestion (#21294)

* Prometheus: Fix label value suggestion

- remove quotes from typeahead input to suggest correct label values
- fix acceptance of partial label values

* Disable mid-word suggestions

* Fix test
This commit is contained in:
David 2019-12-31 08:56:57 +01:00 committed by GitHub
parent 649fa6789e
commit 334b89f3ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 7 deletions

View File

@ -301,7 +301,7 @@ describe('Language completion provider', () => {
instance.lookupsDisabled = false;
const value = Plain.deserialize('{job!=}');
const ed = new SlateEditor({ value });
const valueWithSelection = ed.moveForward(8).value;
const valueWithSelection = ed.moveForward(6).value;
const result = await instance.provideCompletionItems({
text: '!=',
prefix: '',

View File

@ -88,7 +88,10 @@ export default class PromQlLanguageProvider extends LanguageProvider {
cleanText(s: string) {
const parts = s.split(PREFIX_DELIMITER_REGEX);
const last = parts.pop();
return last.trimLeft().replace(/"$/, '');
return last
.trimLeft()
.replace(/"$/, '')
.replace(/^"/, '');
}
get syntax() {
@ -297,8 +300,15 @@ export default class PromQlLanguageProvider extends LanguageProvider {
labelKey,
value,
}: TypeaheadInput): Promise<TypeaheadOutput> => {
const suggestions: CompletionItemGroup[] = [];
const line = value.anchorBlock.getText();
const cursorOffset = value.selection.anchor.offset;
const nextChar = line[cursorOffset];
const isValueContext = wrapperClasses.includes('attr-value');
if (!nextChar.match(/["}]/)) {
// Don't suggest anything inside a value
return { suggestions };
}
// Get normalized selector
let selector;
@ -313,7 +323,6 @@ export default class PromQlLanguageProvider extends LanguageProvider {
const containsMetric = selector.includes('__name__=');
const existingKeys = parsedSelector ? parsedSelector.labelKeys : [];
const suggestions: CompletionItemGroup[] = [];
let labelValues;
// Query labels for selector
if (selector) {
@ -326,7 +335,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
}
let context: string;
if ((text && text.match(/^!?=~?/)) || wrapperClasses.includes('attr-value')) {
if ((text && text.match(/^!?=~?/)) || isValueContext) {
// Label values
if (labelKey && labelValues[labelKey]) {
context = 'context-label-values';

View File

@ -31,6 +31,13 @@ describe('parseSelector()', () => {
parsed = parseSelector('{foo="bar",baz="}');
expect(parsed.selector).toBe('{foo="bar"}');
// Cursor in value area counts as incomplete
parsed = parseSelector('{foo="bar",baz=""}', 16);
expect(parsed.selector).toBe('{foo="bar"}');
parsed = parseSelector('{foo="bar",baz="4"}', 17);
expect(parsed.selector).toBe('{foo="bar"}');
});
it('throws if not inside a selector', () => {
@ -55,7 +62,7 @@ describe('parseSelector()', () => {
parsed = parseSelector('bar{foo}', 4);
expect(parsed.selector).toBe('{__name__="bar"}');
parsed = parseSelector('baz{foo="bar"}', 12);
parsed = parseSelector('baz{foo="bar"}', 13);
expect(parsed.selector).toBe('{__name__="baz",foo="bar"}');
parsed = parseSelector('bar:metric:1m{}', 14);

View File

@ -79,8 +79,14 @@ export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any
// Extract clean labels to form clean selector, incomplete labels are dropped
const selector = query.slice(prefixOpen, suffixClose);
const labels: { [key: string]: { value: string; operator: string } } = {};
selector.replace(labelRegexp, (_, key, operator, value) => {
labels[key] = { value, operator };
selector.replace(labelRegexp, (label, key, operator, value) => {
const labelOffset = query.indexOf(label);
const valueStart = labelOffset + key.length + operator.length + 1;
const valueEnd = labelOffset + key.length + operator.length + value.length - 1;
// Skip label if cursor is in value
if (cursorOffset < valueStart || cursorOffset > valueEnd) {
labels[key] = { value, operator };
}
return '';
});