diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx index 07175ecd17b..cc715189263 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx @@ -94,6 +94,55 @@ describe('PromQueryField', () => { checkMetricsInCascader(await screen.findByRole('button'), changedMetrics); }); + it('does not refreshes metrics when after rounding to minute time range does not change', async () => { + const defaultProps = { + query: { expr: '', refId: '' }, + onRunQuery: () => {}, + onChange: () => {}, + history: [], + }; + const metrics = ['foo', 'bar']; + const changedMetrics = ['foo', 'baz']; + const range = { + from: dateTime('2020-10-28T00:00:00Z'), + to: dateTime('2020-10-28T01:00:00Z'), + }; + + const languageProvider = makeLanguageProvider({ metrics: [metrics, changedMetrics] }); + const queryField = render( + + ); + checkMetricsInCascader(await screen.findByRole('button'), metrics); + + const newRange = { + from: dateTime('2020-10-28T00:00:01Z'), + to: dateTime('2020-10-28T01:00:01Z'), + }; + queryField.rerender( + + ); + let cascader = screen.getByRole('button'); + // Should not show loading + expect(cascader.textContent).toContain('Metrics'); + checkMetricsInCascader(await screen.findByRole('button'), metrics); + }); + it('refreshes metrics when time range changes but dont show loading state', async () => { const defaultProps = { query: { expr: '', refId: '' }, diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx index 16ca7b0f20c..752c9ac0a12 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx @@ -16,8 +16,16 @@ import { LanguageMap, languages as prismLanguages } from 'prismjs'; // dom also includes Element polyfills import { PromQuery, PromOptions, PromMetricsMetadata } from '../types'; +import { roundMsToMin } from '../language_utils'; import { CancelablePromise, makePromiseCancelable } from 'app/core/utils/CancelablePromise'; -import { ExploreQueryFieldProps, QueryHint, isDataFrame, toLegacyResponseData, HistoryItem } from '@grafana/data'; +import { + ExploreQueryFieldProps, + QueryHint, + isDataFrame, + toLegacyResponseData, + HistoryItem, + TimeRange, +} from '@grafana/data'; import { DOMUtil, SuggestionsState } from '@grafana/ui'; import { PrometheusDatasource } from '../datasource'; @@ -168,17 +176,6 @@ class PromQueryField extends React.PureComponent { let query; if (selectedOptions.length === 1) { diff --git a/public/app/plugins/datasource/prometheus/language_provider.ts b/public/app/plugins/datasource/prometheus/language_provider.ts index 685517fe0df..e54a1835966 100644 --- a/public/app/plugins/datasource/prometheus/language_provider.ts +++ b/public/app/plugins/datasource/prometheus/language_provider.ts @@ -5,7 +5,13 @@ import { Value } from 'slate'; import { dateTime, HistoryItem, LanguageProvider } from '@grafana/data'; import { CompletionItem, CompletionItemGroup, TypeaheadInput, TypeaheadOutput } from '@grafana/ui'; -import { fixSummariesMetadata, parseSelector, processHistogramLabels, processLabels } from './language_utils'; +import { + fixSummariesMetadata, + parseSelector, + processHistogramLabels, + processLabels, + roundSecToMin, +} from './language_utils'; import PromqlSyntax, { FUNCTIONS, RATE_RANGES } from './promql'; import { PrometheusDatasource } from './datasource'; @@ -421,10 +427,6 @@ export default class PromQlLanguageProvider extends LanguageProvider { return { [key]: data }; }; - roundToMinutes(seconds: number): number { - return Math.floor(seconds / 60); - } - /** * Fetch labels for a series. This is cached by it's args but also by the global timeRange currently selected as * they can change over requested time. @@ -443,8 +445,8 @@ export default class PromQlLanguageProvider extends LanguageProvider { // The rounding may seem strange but makes relative intervals like now-1h less prone to need separate request every // millisecond while still actually getting all the keys for the correct interval. This still can create problems // when user does not the newest values for a minute if already cached. - params.set('start', this.roundToMinutes(tRange['start']).toString()); - params.set('end', this.roundToMinutes(tRange['end']).toString()); + params.set('start', roundSecToMin(tRange['start']).toString()); + params.set('end', roundSecToMin(tRange['end']).toString()); params.append('withName', withName ? 'true' : 'false'); const cacheKey = `/api/v1/series?${params.toString()}`; let value = this.labelsCache.get(cacheKey); diff --git a/public/app/plugins/datasource/prometheus/language_utils.ts b/public/app/plugins/datasource/prometheus/language_utils.ts index 716172a131f..13d56b7bc31 100644 --- a/public/app/plugins/datasource/prometheus/language_utils.ts +++ b/public/app/plugins/datasource/prometheus/language_utils.ts @@ -185,3 +185,11 @@ export function fixSummariesMetadata(metadata: PromMetricsMetadata): PromMetrics } return { ...metadata, ...summaryMetadata }; } + +export function roundMsToMin(milliseconds: number): number { + return roundSecToMin(milliseconds / 1000); +} + +export function roundSecToMin(seconds: number): number { + return Math.floor(seconds / 60); +}