diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.test.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.test.tsx index 754d588269e..ef1713cc915 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.test.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.test.tsx @@ -12,6 +12,7 @@ import { testIds as regularTestIds } from './PromQueryEditor'; function setup(app: CoreApp): RenderResult { const dataSource = ({ createQuery: jest.fn((q) => q), + getInitHints: () => [], getPrometheusTime: jest.fn((date, roundup) => 123), languageProvider: { start: () => Promise.resolve([]), diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx index f05bf5712d3..5caf277a0bf 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx @@ -3,7 +3,7 @@ import RCCascader from 'rc-cascader'; import React from 'react'; import PromQlLanguageProvider from '../language_provider'; import PromQueryField from './PromQueryField'; -import { DataSourceInstanceSettings } from '@grafana/data'; +import { DataSourceInstanceSettings, PanelData, LoadingState, DataFrame } from '@grafana/data'; import { PromOptions } from '../types'; import { render, screen } from '@testing-library/react'; @@ -21,6 +21,7 @@ describe('PromQueryField', () => { getLabelKeys: () => [], metrics: [], }, + getInitHints: () => [], } as unknown) as DataSourceInstanceSettings; const queryField = render( @@ -45,6 +46,7 @@ describe('PromQueryField', () => { getLabelKeys: () => [], metrics: [], }, + getInitHints: () => [], } as unknown) as DataSourceInstanceSettings; const queryField = render( { expect(bcButton).toBeDisabled(); }); + it('renders an initial hint if no data and initial hint provided', () => { + const datasource = ({ + languageProvider: { + start: () => Promise.resolve([]), + syntax: () => {}, + getLabelKeys: () => [], + metrics: [], + }, + getInitHints: () => [{ label: 'Initial hint', type: 'INFO' }], + } as unknown) as DataSourceInstanceSettings; + render( + {}} + onChange={() => {}} + history={[]} + /> + ); + expect(screen.getByText('Initial hint')).toBeInTheDocument(); + }); + + it('renders query hint if data, query hint and initial hint provided', () => { + const datasource = ({ + languageProvider: { + start: () => Promise.resolve([]), + syntax: () => {}, + getLabelKeys: () => [], + metrics: [], + }, + getInitHints: () => [{ label: 'Initial hint', type: 'INFO' }], + getQueryHints: () => [{ label: 'Query hint', type: 'INFO' }], + } as unknown) as DataSourceInstanceSettings; + render( + {}} + onChange={() => {}} + history={[]} + data={ + { + series: [{ name: 'test name' }] as DataFrame[], + state: LoadingState.Done, + } as PanelData + } + /> + ); + expect(screen.getByText('Query hint')).toBeInTheDocument(); + expect(screen.queryByText('Initial hint')).not.toBeInTheDocument(); + }); + it('refreshes metrics when the data source changes', async () => { const defaultProps = { query: { expr: '', refId: '' }, @@ -74,6 +130,7 @@ describe('PromQueryField', () => { // @ts-ignore datasource={{ languageProvider: makeLanguageProvider({ metrics: [metrics] }), + getInitHints: () => [], }} {...defaultProps} /> diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx index c1e25cb6a39..a06a22f2847 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx @@ -153,24 +153,21 @@ class PromQueryField extends React.PureComponent { const { datasource, query, data } = this.props; + const initHints = datasource.getInitHints(); + const initHint = initHints.length > 0 ? initHints[0] : null; if (!data || data.series.length === 0) { - this.setState({ hint: null }); + this.setState({ + hint: initHint, + }); return; } const result = isDataFrame(data.series[0]) ? data.series.map(toLegacyResponseData) : data.series; - const hints = datasource.getQueryHints(query, result); - let hint = hints.length > 0 ? hints[0] : null; - - // Hint for big disabled lookups - if (!hint && datasource.lookupsDisabled) { - hint = { - label: `Labels and metrics lookup was disabled in data source settings.`, - type: 'INFO', - }; - } - this.setState({ hint }); + const queryHints = datasource.getQueryHints(query, result); + let queryHint = queryHints.length > 0 ? queryHints[0] : null; + + this.setState({ hint: queryHint ?? initHint }); }; refreshMetrics = async () => { diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 1f1c35760b1..db75f915398 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -24,7 +24,7 @@ import { catchError, filter, map, tap } from 'rxjs/operators'; import addLabelToQuery from './add_label_to_query'; import PrometheusLanguageProvider from './language_provider'; import { expandRecordingRules } from './language_utils'; -import { getQueryHints } from './query_hints'; +import { getQueryHints, getInitHints } from './query_hints'; import { getOriginalMetricName, renderTemplate, transform } from './result_transformer'; import { ExemplarTraceIdDestination, @@ -746,6 +746,10 @@ export class PrometheusDatasource extends DataSourceApi return getQueryHints(query.expr ?? '', result, this); } + getInitHints() { + return getInitHints(this); + } + async loadRules() { try { const res = await this.metadataRequest('/api/v1/rules'); diff --git a/public/app/plugins/datasource/prometheus/language_provider.ts b/public/app/plugins/datasource/prometheus/language_provider.ts index aa88e221acb..4dcf74cabfa 100644 --- a/public/app/plugins/datasource/prometheus/language_provider.ts +++ b/public/app/plugins/datasource/prometheus/language_provider.ts @@ -119,7 +119,7 @@ export default class PromQlLanguageProvider extends LanguageProvider { // TODO #33976: make those requests parallel await this.fetchLabels(); - this.metrics = await this.fetchLabelValues('__name__'); + this.metrics = (await this.fetchLabelValues('__name__')) || []; this.metricsMetadata = fixSummariesMetadata(await this.request('/api/v1/metadata', {})); this.processHistogramMetrics(this.metrics); diff --git a/public/app/plugins/datasource/prometheus/query_hints.ts b/public/app/plugins/datasource/prometheus/query_hints.ts index 9f8d2d07b7a..f9bcef45381 100644 --- a/public/app/plugins/datasource/prometheus/query_hints.ts +++ b/public/app/plugins/datasource/prometheus/query_hints.ts @@ -127,3 +127,24 @@ export function getQueryHints(query: string, series?: any[], datasource?: Promet return hints; } + +export function getInitHints(datasource: PrometheusDatasource): QueryHint[] { + const hints = []; + // Hint if using Loki as Prometheus data source + if (datasource.directUrl.includes('/loki') && !datasource.languageProvider.metrics.length) { + hints.push({ + label: `Using Loki as a Prometheus data source is no longer supported. You must use the Loki data source for your Loki instance.`, + type: 'INFO', + }); + } + + // Hint for big disabled lookups + if (datasource.lookupsDisabled) { + hints.push({ + label: `Labels and metrics lookup was disabled in data source settings.`, + type: 'INFO', + }); + } + + return hints; +}