diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.test.tsx
index 46a1396aaa3..4397d4104de 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.test.tsx
@@ -2,7 +2,9 @@ import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
+
import { DataSourceInstanceSettings, MetricFindValue } from '@grafana/data';
+import { config } from '@grafana/runtime';
import { PrometheusDatasource } from '../../datasource';
import { PromOptions } from '../../types';
@@ -124,4 +126,30 @@ describe('MetricCombobox', () => {
expect(mockOnChange).toHaveBeenCalledWith({ metric: 'random_metric', labels: [], operations: [] });
});
+
+ it("doesn't show the metrics explorer button by default", () => {
+ render();
+ expect(screen.queryByRole('button', { name: /open metrics explorer/i })).not.toBeInTheDocument();
+ });
+
+ describe('when metrics explorer toggle is enabled', () => {
+ beforeAll(() => {
+ jest.replaceProperty(config, 'featureToggles', {
+ prometheusMetricEncyclopedia: true,
+ });
+ });
+
+ afterAll(() => {
+ jest.restoreAllMocks();
+ });
+
+ it('opens the metrics explorer when the button is clicked', async () => {
+ render( Promise.resolve([])} />);
+
+ const button = screen.getByRole('button', { name: /open metrics explorer/i });
+ await userEvent.click(button);
+
+ expect(screen.getByText('Metrics explorer')).toBeInTheDocument();
+ });
+ });
});
diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.tsx
index 796b794b6c3..26b55f30087 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.tsx
@@ -1,14 +1,18 @@
-import { useCallback } from 'react';
+import { useCallback, useState } from 'react';
import { SelectableValue } from '@grafana/data';
-import { EditorField, EditorFieldGroup } from '@grafana/experimental';
-import { InlineField, InlineFieldRow, Combobox, ComboboxOption } from '@grafana/ui';
+import { EditorField, EditorFieldGroup, InputGroup } from '@grafana/experimental';
+import { config } from '@grafana/runtime';
+import { Button, InlineField, InlineFieldRow } from '@grafana/ui';
+import { Combobox, ComboboxOption } from '@grafana/ui/src/components/Combobox/Combobox';
import { PrometheusDatasource } from '../../datasource';
import { regexifyLabelValuesQueryString } from '../parsingUtils';
import { QueryBuilderLabelFilter } from '../shared/types';
import { PromVisualQuery } from '../types';
+import { MetricsModal } from './metrics-modal';
+
export interface MetricComboboxProps {
metricLookupDisabled: boolean;
query: PromVisualQuery;
@@ -28,6 +32,8 @@ export function MetricCombobox({
labelsFilters,
variableEditor,
}: Readonly) {
+ const [metricsModalOpen, setMetricsModalOpen] = useState(false);
+
/**
* Gets label_values response from prometheus API for current autocomplete query string and any existing labels filters
*/
@@ -65,21 +71,59 @@ export function MetricCombobox({
[getMetricLabels, onGetMetrics]
);
+ const loadMetricsExplorerMetrics = useCallback(async () => {
+ const allMetrics = await onGetMetrics();
+ const metrics: string[] = [];
+ for (const metric of allMetrics) {
+ if (metric.value) {
+ metrics.push(metric.value);
+ }
+ }
+
+ return metrics;
+ }, [onGetMetrics]);
+
+ const metricsExplorerEnabled = config.featureToggles.prometheusMetricEncyclopedia;
+
const asyncSelect = () => {
return (
-
+
+
+
+ {metricsExplorerEnabled ? (
+
);
};
return (
<>
+ {metricsExplorerEnabled && !datasource.lookupsDisabled && metricsModalOpen && (
+ setMetricsModalOpen(false)}
+ query={query}
+ onChange={onChange}
+ initialMetrics={loadMetricsExplorerMetrics}
+ />
+ )}
{variableEditor ? (
void;
onChange: (query: PromVisualQuery) => void;
- initialMetrics: string[];
+ initialMetrics: string[] | (() => Promise);
};
export const MetricsModal = (props: MetricsModalProps) => {
@@ -70,7 +70,11 @@ export const MetricsModal = (props: MetricsModalProps) => {
// *** Loading Gif
dispatch(setIsLoading(true));
- const data: MetricsModalMetadata = await setMetrics(datasource, query, initialMetrics);
+ // Because Combobox in MetricsCombobox doesn't use the same lifecycle as Select to open the Metrics Explorer
+ // it might not have loaded any metrics yet, so it instead passes in an async function to get the metrics
+ const metrics = typeof initialMetrics === 'function' ? await initialMetrics() : initialMetrics;
+
+ const data: MetricsModalMetadata = await setMetrics(datasource, query, metrics);
dispatch(
buildMetrics({
isLoading: false,