Prometheus: Show initial hint on builder mode when metric lookup disabled (#65827)

* Show initial hint on builder mode when metric lookup disabled

* Disable MetricEncyclopedia and label request when metric lookup is disabled
This commit is contained in:
ismail simsek 2023-04-12 17:22:35 +02:00 committed by GitHub
parent e0385d08a8
commit 08727b7d6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 12 deletions

View File

@ -1,8 +1,6 @@
{ {
"npmClient": "yarn", "npmClient": "yarn",
"useWorkspaces": true, "useWorkspaces": true,
"packages": [ "packages": ["packages/*"],
"packages/*"
],
"version": "10.0.0-pre" "version": "10.0.0-pre"
} }

View File

@ -6,8 +6,8 @@ import (
context "context" context "context"
dashboards "github.com/grafana/grafana/pkg/services/dashboards" dashboards "github.com/grafana/grafana/pkg/services/dashboards"
mock "github.com/stretchr/testify/mock"
models "github.com/grafana/grafana/pkg/services/publicdashboards/models" models "github.com/grafana/grafana/pkg/services/publicdashboards/models"
mock "github.com/stretchr/testify/mock"
) )
// FakePublicDashboardStore is an autogenerated mock type for the Store type // FakePublicDashboardStore is an autogenerated mock type for the Store type

View File

@ -7,7 +7,7 @@ import { DataSourceInstanceSettings, MetricFindValue } from '@grafana/data/src';
import { PrometheusDatasource } from '../../datasource'; import { PrometheusDatasource } from '../../datasource';
import { PromOptions } from '../../types'; import { PromOptions } from '../../types';
import { MetricSelect } from './MetricSelect'; import { MetricSelect, Props } from './MetricSelect';
const instanceSettings = { const instanceSettings = {
url: 'proxied', url: 'proxied',
@ -44,7 +44,7 @@ dataSourceMock.metricFindQuery = jest.fn((query: string) => {
); );
}); });
const props = { const props: Props = {
labelsFilters: [], labelsFilters: [],
datasource: dataSourceMock, datasource: dataSourceMock,
query: { query: {
@ -54,6 +54,7 @@ const props = {
}, },
onChange: jest.fn(), onChange: jest.fn(),
onGetMetrics: jest.fn().mockResolvedValue(mockValues), onGetMetrics: jest.fn().mockResolvedValue(mockValues),
metricLookupDisabled: false,
}; };
describe('MetricSelect', () => { describe('MetricSelect', () => {

View File

@ -3,7 +3,7 @@ import debounce from 'debounce-promise';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import Highlighter from 'react-highlight-words'; import Highlighter from 'react-highlight-words';
import { SelectableValue, toOption, GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
import { EditorField, EditorFieldGroup } from '@grafana/experimental'; import { EditorField, EditorFieldGroup } from '@grafana/experimental';
import { AsyncSelect, FormatOptionLabelMeta, useStyles2 } from '@grafana/ui'; import { AsyncSelect, FormatOptionLabelMeta, useStyles2 } from '@grafana/ui';
@ -16,6 +16,7 @@ import { PromVisualQuery } from '../types';
const splitSeparator = ' '; const splitSeparator = ' ';
export interface Props { export interface Props {
metricLookupDisabled: boolean;
query: PromVisualQuery; query: PromVisualQuery;
onChange: (query: PromVisualQuery) => void; onChange: (query: PromVisualQuery) => void;
onGetMetrics: () => Promise<SelectableValue[]>; onGetMetrics: () => Promise<SelectableValue[]>;
@ -25,7 +26,14 @@ export interface Props {
export const PROMETHEUS_QUERY_BUILDER_MAX_RESULTS = 1000; export const PROMETHEUS_QUERY_BUILDER_MAX_RESULTS = 1000;
export function MetricSelect({ datasource, query, onChange, onGetMetrics, labelsFilters }: Props) { export function MetricSelect({
datasource,
query,
onChange,
onGetMetrics,
labelsFilters,
metricLookupDisabled,
}: Props) {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const [state, setState] = useState<{ const [state, setState] = useState<{
metrics?: Array<SelectableValue<any>>; metrics?: Array<SelectableValue<any>>;
@ -114,6 +122,9 @@ export function MetricSelect({ datasource, query, onChange, onGetMetrics, labels
}); });
}; };
// When metric and label lookup is disabled we won't request labels
const metricLookupDisabledSearch = () => Promise.resolve([]);
const debouncedSearch = debounce( const debouncedSearch = debounce(
(query: string) => getMetricLabels(query), (query: string) => getMetricLabels(query),
datasource.getDebounceTimeInMilliseconds() datasource.getDebounceTimeInMilliseconds()
@ -126,11 +137,14 @@ export function MetricSelect({ datasource, query, onChange, onGetMetrics, labels
inputId="prometheus-metric-select" inputId="prometheus-metric-select"
className={styles.select} className={styles.select}
value={query.metric ? toOption(query.metric) : undefined} value={query.metric ? toOption(query.metric) : undefined}
placeholder="Select metric" placeholder={'Select metric'}
allowCustomValue allowCustomValue
formatOptionLabel={formatOptionLabel} formatOptionLabel={formatOptionLabel}
filterOption={customFilterOption} filterOption={customFilterOption}
onOpenMenu={async () => { onOpenMenu={async () => {
if (metricLookupDisabled) {
return;
}
setState({ isLoading: true }); setState({ isLoading: true });
const metrics = await onGetMetrics(); const metrics = await onGetMetrics();
if (metrics.length > PROMETHEUS_QUERY_BUILDER_MAX_RESULTS) { if (metrics.length > PROMETHEUS_QUERY_BUILDER_MAX_RESULTS) {
@ -138,7 +152,7 @@ export function MetricSelect({ datasource, query, onChange, onGetMetrics, labels
} }
setState({ metrics, isLoading: undefined }); setState({ metrics, isLoading: undefined });
}} }}
loadOptions={debouncedSearch} loadOptions={metricLookupDisabled ? metricLookupDisabledSearch : debouncedSearch}
isLoading={state.isLoading} isLoading={state.isLoading}
defaultOptions={state.metrics} defaultOptions={state.metrics}
onChange={({ value }) => { onChange={({ value }) => {

View File

@ -8,6 +8,7 @@ import {
LoadingState, LoadingState,
MutableDataFrame, MutableDataFrame,
PanelData, PanelData,
QueryHint,
TimeRange, TimeRange,
} from '@grafana/data'; } from '@grafana/data';
@ -229,6 +230,45 @@ describe('PromQueryBuilder', () => {
expect(await screen.queryByText(EXPLAIN_LABEL_FILTER_CONTENT)).not.toBeInTheDocument(); expect(await screen.queryByText(EXPLAIN_LABEL_FILTER_CONTENT)).not.toBeInTheDocument();
}); });
it('renders hint if initial hint provided', async () => {
const { datasource } = createDatasource();
datasource.getInitHints = (): QueryHint[] => [
{
label: 'Initial hint',
type: 'warning',
},
];
const props = createProps(datasource);
render(
<PromQueryBuilder
{...props}
query={{
metric: 'histogram_metric_sum',
labels: [],
operations: [],
}}
/>
);
expect(await screen.queryByText('Initial hint')).toBeInTheDocument();
});
it('renders no hint if no initial hint provided', async () => {
const { datasource } = createDatasource();
datasource.getInitHints = (): QueryHint[] => [];
const props = createProps(datasource);
render(
<PromQueryBuilder
{...props}
query={{
metric: 'histogram_metric_sum',
labels: [],
operations: [],
}}
/>
);
expect(await screen.queryByText('Initial hint')).not.toBeInTheDocument();
});
// <ModernPrometheus> // <ModernPrometheus>
it('tries to load labels when metric selected modern prom', async () => { it('tries to load labels when metric selected modern prom', async () => {
const { languageProvider } = setup(undefined, undefined, { const { languageProvider } = setup(undefined, undefined, {

View File

@ -208,12 +208,14 @@ export const PromQueryBuilder = React.memo<Props>((props) => {
}, [datasource, query, withTemplateVariableOptions]); }, [datasource, query, withTemplateVariableOptions]);
const lang = { grammar: promqlGrammar, name: 'promql' }; const lang = { grammar: promqlGrammar, name: 'promql' };
const MetricEncyclopedia = config.featureToggles.prometheusMetricEncyclopedia; const isMetricEncyclopediaEnabled = config.featureToggles.prometheusMetricEncyclopedia;
const initHints = datasource.getInitHints();
return ( return (
<> <>
<EditorRow> <EditorRow>
{MetricEncyclopedia ? ( {isMetricEncyclopediaEnabled && !datasource.lookupsDisabled ? (
<> <>
<Button <Button
className={styles.button} className={styles.button}
@ -252,6 +254,7 @@ export const PromQueryBuilder = React.memo<Props>((props) => {
onGetMetrics={onGetMetrics} onGetMetrics={onGetMetrics}
datasource={datasource} datasource={datasource}
labelsFilters={query.labels} labelsFilters={query.labels}
metricLookupDisabled={datasource.lookupsDisabled}
/> />
)} )}
<LabelFilters <LabelFilters
@ -264,6 +267,18 @@ export const PromQueryBuilder = React.memo<Props>((props) => {
onGetLabelValues={(forLabel) => withTemplateVariableOptions(onGetLabelValues(forLabel))} onGetLabelValues={(forLabel) => withTemplateVariableOptions(onGetLabelValues(forLabel))}
/> />
</EditorRow> </EditorRow>
{initHints.length ? (
<div className="query-row-break">
<div className="prom-query-field-info text-warning">
{initHints[0].label}{' '}
{initHints[0].fix ? (
<button type="button" className={'text-warning'}>
{initHints[0].fix.label}
</button>
) : null}
</div>
</div>
) : null}
{showExplain && ( {showExplain && (
<OperationExplainedBox <OperationExplainedBox
stepNumber={1} stepNumber={1}