diff --git a/.betterer.results b/.betterer.results index 279604ebb018..e46196375b49 100644 --- a/.betterer.results +++ b/.betterer.results @@ -6818,9 +6818,7 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "15"], [0, 0, 0, "Unexpected any. Specify a different type.", "16"], [0, 0, 0, "Unexpected any. Specify a different type.", "17"], - [0, 0, 0, "Unexpected any. Specify a different type.", "18"], - [0, 0, 0, "Unexpected any. Specify a different type.", "19"], - [0, 0, 0, "Unexpected any. Specify a different type.", "20"] + [0, 0, 0, "Unexpected any. Specify a different type.", "18"] ], "public/app/plugins/datasource/tempo/traceql/autocomplete.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], diff --git a/public/app/plugins/datasource/tempo/traceql/autocomplete.test.ts b/public/app/plugins/datasource/tempo/traceql/autocomplete.test.ts index 29885de84deb..953cd297f9e8 100644 --- a/public/app/plugins/datasource/tempo/traceql/autocomplete.test.ts +++ b/public/app/plugins/datasource/tempo/traceql/autocomplete.test.ts @@ -82,6 +82,17 @@ describe('CompletionProvider', () => { ]); }); + it('only suggests tags after typing the global attribute scope', async () => { + const { provider, model } = setup('{.}', 2, defaultTags); + const result = await provider.provideCompletionItems( + model as unknown as monacoTypes.editor.ITextModel, + {} as monacoTypes.Position + ); + expect((result! as monacoTypes.languages.CompletionList).suggestions).toEqual( + defaultTags.map((s) => expect.objectContaining({ label: s, insertText: s })) + ); + }); + it('suggests operators after a space after the tag name', async () => { const { provider, model } = setup('{ foo }', 6, defaultTags); const result = await provider.provideCompletionItems(model as any, {} as any); @@ -92,11 +103,13 @@ describe('CompletionProvider', () => { it('suggests tags after a scope', async () => { const { provider, model } = setup('{ resource. }', 11, defaultTags); - const result = await provider.provideCompletionItems(model as any, {} as any); - expect((result! as monacoTypes.languages.CompletionList).suggestions).toEqual([ - ...CompletionProvider.intrinsics.map((s) => expect.objectContaining({ label: s, insertText: s })), - ...defaultTags.map((s) => expect.objectContaining({ label: s, insertText: s })), - ]); + const result = await provider.provideCompletionItems( + model as unknown as monacoTypes.editor.ITextModel, + {} as monacoTypes.Position + ); + expect((result! as monacoTypes.languages.CompletionList).suggestions).toEqual( + defaultTags.map((s) => expect.objectContaining({ label: s, insertText: s })) + ); }); it('suggests logical operators and close bracket after the value', async () => { diff --git a/public/app/plugins/datasource/tempo/traceql/autocomplete.ts b/public/app/plugins/datasource/tempo/traceql/autocomplete.ts index e715259c3137..6f0fc8e08210 100644 --- a/public/app/plugins/datasource/tempo/traceql/autocomplete.ts +++ b/public/app/plugins/datasource/tempo/traceql/autocomplete.ts @@ -120,10 +120,13 @@ export class CompletionProvider implements monacoTypes.languages.CompletionItemP } case 'SPANSET_EMPTY': return this.getScopesCompletions().concat(this.getIntrinsicsCompletions()).concat(this.getTagsCompletions('.')); + case 'SPANSET_ONLY_DOT': { + return this.getTagsCompletions(); + } case 'SPANSET_IN_NAME': return this.getScopesCompletions().concat(this.getIntrinsicsCompletions()).concat(this.getTagsCompletions()); case 'SPANSET_IN_NAME_SCOPE': - return this.getIntrinsicsCompletions().concat(this.getTagsCompletions()); + return this.getTagsCompletions(); case 'SPANSET_AFTER_NAME': return CompletionProvider.operators.map((key) => ({ label: key, @@ -223,6 +226,12 @@ export class CompletionProvider implements monacoTypes.languages.CompletionItemP }; } + if (nameFull === '.') { + return { + type: 'SPANSET_ONLY_DOT', + }; + } + const nameMatched = nameFull.match(/^(?\.)?(?\w[\w./-]*\w)(?\.)?$/); // We already have a (potentially partial) tag name so let's check if there's an operator declared @@ -344,6 +353,9 @@ export type Situation = | { type: 'SPANSET_EMPTY'; } + | { + type: 'SPANSET_ONLY_DOT'; + } | { type: 'SPANSET_AFTER_NAME'; }