diff --git a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts index dc67d7c9d52..1eb7330ff92 100644 --- a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts +++ b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts @@ -1,4 +1,4 @@ -import type { Intent, Label } from './intent'; +import type { Situation, Label } from './situation'; import { NeverCaseError } from './util'; // FIXME: we should not load this from the "outside", but we cannot do that while we have the "old" query-field too import { FUNCTIONS } from '../../../promql'; @@ -139,28 +139,33 @@ async function getLabelValuesForMetricCompletions( })); } -export async function getCompletions(intent: Intent, dataProvider: DataProvider): Promise { - switch (intent.type) { - case 'ALL_DURATIONS': +export async function getCompletions(situation: Situation, dataProvider: DataProvider): Promise { + switch (situation.type) { + case 'IN_DURATION': return DURATION_COMPLETIONS; - case 'ALL_METRIC_NAMES': + case 'IN_FUNCTION': return getAllMetricNamesCompletions(dataProvider); - case 'FUNCTIONS_AND_ALL_METRIC_NAMES': { + case 'AT_ROOT': { const metricNames = await getAllMetricNamesCompletions(dataProvider); return [...FUNCTION_COMPLETIONS, ...metricNames]; } - case 'HISTORY_AND_FUNCTIONS_AND_ALL_METRIC_NAMES': { + case 'EMPTY': { const metricNames = await getAllMetricNamesCompletions(dataProvider); const historyCompletions = await getAllHistoryCompletions(dataProvider); return [...historyCompletions, ...FUNCTION_COMPLETIONS, ...metricNames]; } - case 'LABEL_NAMES_FOR_SELECTOR': - return getLabelNamesForSelectorCompletions(intent.metricName, intent.otherLabels, dataProvider); - case 'LABEL_NAMES_FOR_BY': - return getLabelNamesForByCompletions(intent.metricName, intent.otherLabels, dataProvider); - case 'LABEL_VALUES': - return getLabelValuesForMetricCompletions(intent.metricName, intent.labelName, intent.otherLabels, dataProvider); + case 'IN_LABEL_SELECTOR_NO_LABEL_NAME': + return getLabelNamesForSelectorCompletions(situation.metricName, situation.otherLabels, dataProvider); + case 'IN_GROUPING': + return getLabelNamesForByCompletions(situation.metricName, situation.otherLabels, dataProvider); + case 'IN_LABEL_SELECTOR_WITH_LABEL_NAME': + return getLabelValuesForMetricCompletions( + situation.metricName, + situation.labelName, + situation.otherLabels, + dataProvider + ); default: - throw new NeverCaseError(intent); + throw new NeverCaseError(situation); } } diff --git a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/index.ts b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/index.ts index 6c5f96ebe97..e9ceecbc3fa 100644 --- a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/index.ts +++ b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/index.ts @@ -1,6 +1,6 @@ import type { Monaco, monacoTypes } from '@grafana/ui'; -import { getIntent } from './intent'; +import { getSituation } from './situation'; import { getCompletions, DataProvider, CompletionType } from './completions'; import { NeverCaseError } from './util'; @@ -47,8 +47,8 @@ export function getCompletionProvider( lineNumber: position.lineNumber, }; const offset = model.getOffsetAt(positionClone); - const intent = getIntent(model.getValue(), offset); - const completionsPromise = intent != null ? getCompletions(intent, dataProvider) : Promise.resolve([]); + const situation = getSituation(model.getValue(), offset); + const completionsPromise = situation != null ? getCompletions(situation, dataProvider) : Promise.resolve([]); return completionsPromise.then((items) => { // monaco by-default alphabetically orders the items. // to stop it, we use a number-as-string sortkey, diff --git a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/intent.test.ts b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.test.ts similarity index 52% rename from public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/intent.test.ts rename to public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.test.ts index f8232eb56b0..299e363a273 100644 --- a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/intent.test.ts +++ b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.test.ts @@ -1,7 +1,7 @@ -import { getIntent, Intent } from './intent'; +import { getSituation, Situation } from './situation'; // we use the `^` character as the cursor-marker in the string. -function assertIntent(situation: string, expectedIntent: Intent | null) { +function assertSituation(situation: string, expectedSituation: Situation | null) { // first we find the cursor-position const pos = situation.indexOf('^'); if (pos === -1) { @@ -16,61 +16,61 @@ function assertIntent(situation: string, expectedIntent: Intent | null) { throw new Error('multiple cursors'); } - const result = getIntent(text, pos); + const result = getSituation(text, pos); - if (expectedIntent === null) { + if (expectedSituation === null) { expect(result).toStrictEqual(null); } else { - expect(result).toMatchObject(expectedIntent); + expect(result).toMatchObject(expectedSituation); } } -describe('intent', () => { +describe('situation', () => { it('handles things', () => { - assertIntent('^', { - type: 'HISTORY_AND_FUNCTIONS_AND_ALL_METRIC_NAMES', + assertSituation('^', { + type: 'EMPTY', }); - assertIntent('sum(one) / ^', { - type: 'FUNCTIONS_AND_ALL_METRIC_NAMES', + assertSituation('sum(one) / ^', { + type: 'AT_ROOT', }); - assertIntent('sum(^)', { - type: 'ALL_METRIC_NAMES', + assertSituation('sum(^)', { + type: 'IN_FUNCTION', }); - assertIntent('sum(one) / sum(^)', { - type: 'ALL_METRIC_NAMES', + assertSituation('sum(one) / sum(^)', { + type: 'IN_FUNCTION', }); - assertIntent('something{}[^]', { - type: 'ALL_DURATIONS', + assertSituation('something{}[^]', { + type: 'IN_DURATION', }); - assertIntent('something{label~^}', null); + assertSituation('something{label~^}', null); }); it('handles label names', () => { - assertIntent('something{^}', { - type: 'LABEL_NAMES_FOR_SELECTOR', + assertSituation('something{^}', { + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', metricName: 'something', otherLabels: [], }); - assertIntent('sum(something) by (^)', { - type: 'LABEL_NAMES_FOR_BY', + assertSituation('sum(something) by (^)', { + type: 'IN_GROUPING', metricName: 'something', otherLabels: [], }); - assertIntent('sum by (^) (something)', { - type: 'LABEL_NAMES_FOR_BY', + assertSituation('sum by (^) (something)', { + type: 'IN_GROUPING', metricName: 'something', otherLabels: [], }); - assertIntent('something{one="val1",two!="val2",three=~"val3",four!~"val4",^}', { - type: 'LABEL_NAMES_FOR_SELECTOR', + assertSituation('something{one="val1",two!="val2",three=~"val3",four!~"val4",^}', { + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', metricName: 'something', otherLabels: [ { name: 'one', value: 'val1', op: '=' }, @@ -80,61 +80,61 @@ describe('intent', () => { ], }); - assertIntent('{^}', { - type: 'LABEL_NAMES_FOR_SELECTOR', + assertSituation('{^}', { + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', otherLabels: [], }); - assertIntent('{one="val1",^}', { - type: 'LABEL_NAMES_FOR_SELECTOR', + assertSituation('{one="val1",^}', { + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', otherLabels: [{ name: 'one', value: 'val1', op: '=' }], }); }); it('handles label values', () => { - assertIntent('something{job=^}', { - type: 'LABEL_VALUES', + assertSituation('something{job=^}', { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', metricName: 'something', labelName: 'job', otherLabels: [], }); - assertIntent('something{job!=^}', { - type: 'LABEL_VALUES', + assertSituation('something{job!=^}', { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', metricName: 'something', labelName: 'job', otherLabels: [], }); - assertIntent('something{job=~^}', { - type: 'LABEL_VALUES', + assertSituation('something{job=~^}', { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', metricName: 'something', labelName: 'job', otherLabels: [], }); - assertIntent('something{job!~^}', { - type: 'LABEL_VALUES', + assertSituation('something{job!~^}', { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', metricName: 'something', labelName: 'job', otherLabels: [], }); - assertIntent('something{job=^,host="h1"}', { - type: 'LABEL_VALUES', + assertSituation('something{job=^,host="h1"}', { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', metricName: 'something', labelName: 'job', otherLabels: [{ name: 'host', value: 'h1', op: '=' }], }); - assertIntent('{job=^,host="h1"}', { - type: 'LABEL_VALUES', + assertSituation('{job=^,host="h1"}', { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', labelName: 'job', otherLabels: [{ name: 'host', value: 'h1', op: '=' }], }); - assertIntent('something{one="val1",two!="val2",three=^,four=~"val4",five!~"val5"}', { - type: 'LABEL_VALUES', + assertSituation('something{one="val1",two!="val2",three=^,four=~"val4",five!~"val5"}', { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', metricName: 'something', labelName: 'three', otherLabels: [ diff --git a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/intent.ts b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.ts similarity index 92% rename from public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/intent.ts rename to public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.ts index d37497a9509..74eabeaec44 100644 --- a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/intent.ts +++ b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.ts @@ -84,31 +84,31 @@ export type Label = { op: LabelOperator; }; -export type Intent = +export type Situation = | { - type: 'ALL_METRIC_NAMES'; + type: 'IN_FUNCTION'; } | { - type: 'FUNCTIONS_AND_ALL_METRIC_NAMES'; + type: 'AT_ROOT'; } | { - type: 'HISTORY_AND_FUNCTIONS_AND_ALL_METRIC_NAMES'; + type: 'EMPTY'; } | { - type: 'ALL_DURATIONS'; + type: 'IN_DURATION'; } | { - type: 'LABEL_NAMES_FOR_SELECTOR'; + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME'; metricName?: string; otherLabels: Label[]; } | { - type: 'LABEL_NAMES_FOR_BY'; + type: 'IN_GROUPING'; metricName: string; otherLabels: Label[]; } | { - type: 'LABEL_VALUES'; + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME'; metricName?: string; labelName: string; otherLabels: Label[]; @@ -116,7 +116,7 @@ export type Intent = type Resolver = { path: NodeTypeName[]; - fun: (node: SyntaxNode, text: string, pos: number) => Intent | null; + fun: (node: SyntaxNode, text: string, pos: number) => Situation | null; }; function isPathMatch(resolverPath: string[], cursorPath: string[]): boolean { @@ -259,7 +259,7 @@ function getNodeInSubtree(node: SyntaxNode, typeName: NodeTypeName): SyntaxNode return null; } -function resolveLabelsForGrouping(node: SyntaxNode, text: string, pos: number): Intent | null { +function resolveLabelsForGrouping(node: SyntaxNode, text: string, pos: number): Situation | null { const aggrExpNode = walk(node, [ ['parent', 'AggregateModifier'], ['parent', 'AggregateExpr'], @@ -284,13 +284,13 @@ function resolveLabelsForGrouping(node: SyntaxNode, text: string, pos: number): const metricName = getNodeText(idNode, text); return { - type: 'LABEL_NAMES_FOR_BY', + type: 'IN_GROUPING', metricName, otherLabels: [], }; } -function resolveLabelMatcherError(node: SyntaxNode, text: string, pos: number): Intent | null { +function resolveLabelMatcherError(node: SyntaxNode, text: string, pos: number): Situation | null { // we are probably in the scenario where the user is before entering the // label-value, like `{job=^}` (^ marks the cursor) const parent = walk(node, [['parent', 'LabelMatcher']]); @@ -355,7 +355,7 @@ function resolveLabelMatcherError(node: SyntaxNode, text: string, pos: number): if (metricNameNode === null) { // we are probably in a situation without a metric name return { - type: 'LABEL_VALUES', + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', labelName, otherLabels, }; @@ -364,28 +364,28 @@ function resolveLabelMatcherError(node: SyntaxNode, text: string, pos: number): const metricName = getNodeText(metricNameNode, text); return { - type: 'LABEL_VALUES', + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', metricName, labelName, otherLabels, }; } -function resolveTopLevel(node: SyntaxNode, text: string, pos: number): Intent { +function resolveTopLevel(node: SyntaxNode, text: string, pos: number): Situation { return { - type: 'FUNCTIONS_AND_ALL_METRIC_NAMES', + type: 'AT_ROOT', }; } -function resolveInFunction(node: SyntaxNode, text: string, pos: number): Intent { +function resolveInFunction(node: SyntaxNode, text: string, pos: number): Situation { return { - type: 'ALL_METRIC_NAMES', + type: 'IN_FUNCTION', }; } -function resolveDurations(node: SyntaxNode, text: string, pos: number): Intent { +function resolveDurations(node: SyntaxNode, text: string, pos: number): Situation { return { - type: 'ALL_DURATIONS', + type: 'IN_DURATION', }; } @@ -393,7 +393,7 @@ function subTreeHasError(node: SyntaxNode): boolean { return getNodeInSubtree(node, ERROR_NODE_NAME) !== null; } -function resolveLabelKeysWithEquals(node: SyntaxNode, text: string, pos: number): Intent | null { +function resolveLabelKeysWithEquals(node: SyntaxNode, text: string, pos: number): Situation | null { // for example `something{^}` // there are some false positives that can end up in this situation, that we want @@ -414,7 +414,7 @@ function resolveLabelKeysWithEquals(node: SyntaxNode, text: string, pos: number) if (metricNameNode === null) { // we are probably in a situation without a metric name. return { - type: 'LABEL_NAMES_FOR_SELECTOR', + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', otherLabels, }; } @@ -422,7 +422,7 @@ function resolveLabelKeysWithEquals(node: SyntaxNode, text: string, pos: number) const metricName = getNodeText(metricNameNode, text); return { - type: 'LABEL_NAMES_FOR_SELECTOR', + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', metricName, otherLabels, }; @@ -451,13 +451,13 @@ function getErrorNode(tree: Tree, pos: number): SyntaxNode | null { return null; } -export function getIntent(text: string, pos: number): Intent | null { +export function getSituation(text: string, pos: number): Situation | null { // there is a special-case when we are at the start of writing text, // so we handle that case first if (text === '') { return { - type: 'HISTORY_AND_FUNCTIONS_AND_ALL_METRIC_NAMES', + type: 'EMPTY', }; }