Prometheus: Add Metrics Explorer button next to MetricCombobox (#95647)
This commit is contained in:
@@ -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(<MetricCombobox {...defaultProps} />);
|
||||
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(<MetricCombobox {...defaultProps} onGetMetrics={() => Promise.resolve([])} />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /open metrics explorer/i });
|
||||
await userEvent.click(button);
|
||||
|
||||
expect(screen.getByText('Metrics explorer')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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<MetricComboboxProps>) {
|
||||
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 (
|
||||
<Combobox
|
||||
placeholder="Select metric"
|
||||
width="auto"
|
||||
minWidth={25}
|
||||
options={loadOptions}
|
||||
value={query.metric}
|
||||
onChange={onComboboxChange}
|
||||
/>
|
||||
<InputGroup>
|
||||
<Combobox
|
||||
placeholder="Select metric"
|
||||
width="auto"
|
||||
minWidth={25}
|
||||
options={loadOptions}
|
||||
value={query.metric}
|
||||
onChange={onComboboxChange}
|
||||
/>
|
||||
|
||||
{metricsExplorerEnabled ? (
|
||||
<Button
|
||||
tooltip="Open metrics explorer"
|
||||
aria-label="Open metrics explorer"
|
||||
variant="secondary"
|
||||
icon="book-open"
|
||||
onClick={() => setMetricsModalOpen(true)}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</InputGroup>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{metricsExplorerEnabled && !datasource.lookupsDisabled && metricsModalOpen && (
|
||||
<MetricsModal
|
||||
datasource={datasource}
|
||||
isOpen={metricsModalOpen}
|
||||
onClose={() => setMetricsModalOpen(false)}
|
||||
query={query}
|
||||
onChange={onChange}
|
||||
initialMetrics={loadMetricsExplorerMetrics}
|
||||
/>
|
||||
)}
|
||||
{variableEditor ? (
|
||||
<InlineFieldRow>
|
||||
<InlineField
|
||||
|
||||
+6
-2
@@ -52,7 +52,7 @@ export type MetricsModalProps = {
|
||||
query: PromVisualQuery;
|
||||
onClose: () => void;
|
||||
onChange: (query: PromVisualQuery) => void;
|
||||
initialMetrics: string[];
|
||||
initialMetrics: string[] | (() => Promise<string[]>);
|
||||
};
|
||||
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user