diff --git a/public/app/features/explore/QueryRow.tsx b/public/app/features/explore/QueryRow.tsx index 5b5361fcff7..7dc1b3bcd42 100644 --- a/public/app/features/explore/QueryRow.tsx +++ b/public/app/features/explore/QueryRow.tsx @@ -13,7 +13,7 @@ import { changeQuery, modifyQueries, runQueries, addQueryRow } from './state/act // Types import { StoreState } from 'app/types'; -import { TimeRange } from '@grafana/data'; +import { TimeRange, AbsoluteTimeRange } from '@grafana/data'; import { DataQuery, DataSourceApi, QueryFixAction, DataSourceStatus, PanelData, DataQueryError } from '@grafana/ui'; import { HistoryItem, ExploreItemState, ExploreId, ExploreMode } from 'app/types/explore'; import { Emitter } from 'app/core/utils/emitter'; @@ -38,6 +38,7 @@ interface QueryRowProps extends PropsFromParent { query: DataQuery; modifyQueries: typeof modifyQueries; range: TimeRange; + absoluteRange: AbsoluteTimeRange; removeQueryRowAction: typeof removeQueryRowAction; runQueries: typeof runQueries; queryResponse: PanelData; @@ -116,6 +117,7 @@ export class QueryRow extends PureComponent { query, exploreEvents, range, + absoluteRange, datasourceStatus, queryResponse, latency, @@ -148,6 +150,7 @@ export class QueryRow extends PureComponent { onChange={this.onChange} panelData={null} queryResponse={queryResponse} + absoluteRange={absoluteRange} /> ) : ( = ({ }) => { const { isSyntaxReady, setActiveOption, refreshLabels, ...syntaxProps } = useLokiSyntax( datasource.languageProvider, - datasourceStatus + datasourceStatus, + otherProps.absoluteRange ); return ( diff --git a/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx b/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx index a23cd86ad58..8646a7c6849 100644 --- a/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx +++ b/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx @@ -17,6 +17,7 @@ import BracesPlugin from 'app/features/explore/slate-plugins/braces'; import { LokiQuery } from '../types'; import { TypeaheadOutput, HistoryItem } from 'app/types/explore'; import { DataSourceApi, ExploreQueryFieldProps, DataSourceStatus } from '@grafana/ui'; +import { AbsoluteTimeRange } from '@grafana/data'; function getChooserText(hasSyntax: boolean, hasLogLabels: boolean, datasourceStatus: DataSourceStatus) { if (datasourceStatus === DataSourceStatus.Disconnected) { @@ -70,6 +71,7 @@ export interface LokiQueryFieldFormProps extends ExploreQueryFieldProps void; onLabelsRefresh?: () => void; } @@ -123,7 +125,7 @@ export class LokiQueryFieldForm extends React.PureComponent { it('should refresh labels', async () => { @@ -10,6 +11,10 @@ describe('useLokiLabels hook', () => { }; const languageProvider = new LanguageProvider(datasource); const logLabelOptionsMock = ['Holy mock!']; + const rangeMock: AbsoluteTimeRange = { + from: 1560153109000, + to: 1560153109000, + }; languageProvider.refreshLogLabels = () => { languageProvider.logLabelOptions = logLabelOptionsMock; @@ -17,7 +22,7 @@ describe('useLokiLabels hook', () => { }; const { result, waitForNextUpdate } = renderHook(() => - useLokiLabels(languageProvider, true, [], DataSourceStatus.Connected, DataSourceStatus.Connected) + useLokiLabels(languageProvider, true, [], rangeMock, DataSourceStatus.Connected, DataSourceStatus.Connected) ); act(() => result.current.refreshLabels()); expect(result.current.logLabelOptions).toEqual([]); @@ -29,26 +34,38 @@ describe('useLokiLabels hook', () => { const datasource = { metadataRequest: () => ({ data: { data: [] as any[] } }), }; + + const rangeMock: AbsoluteTimeRange = { + from: 1560153109000, + to: 1560153109000, + }; + const languageProvider = new LanguageProvider(datasource); languageProvider.refreshLogLabels = jest.fn(); renderHook(() => - useLokiLabels(languageProvider, true, [], DataSourceStatus.Connected, DataSourceStatus.Disconnected) + useLokiLabels(languageProvider, true, [], rangeMock, DataSourceStatus.Connected, DataSourceStatus.Disconnected) ); expect(languageProvider.refreshLogLabels).toBeCalledTimes(1); - expect(languageProvider.refreshLogLabels).toBeCalledWith(true); + expect(languageProvider.refreshLogLabels).toBeCalledWith(rangeMock, true); }); it('should not force refresh labels after a connect', () => { const datasource = { metadataRequest: () => ({ data: { data: [] as any[] } }), }; + + const rangeMock: AbsoluteTimeRange = { + from: 1560153109000, + to: 1560153109000, + }; + const languageProvider = new LanguageProvider(datasource); languageProvider.refreshLogLabels = jest.fn(); renderHook(() => - useLokiLabels(languageProvider, true, [], DataSourceStatus.Disconnected, DataSourceStatus.Connected) + useLokiLabels(languageProvider, true, [], rangeMock, DataSourceStatus.Disconnected, DataSourceStatus.Connected) ); expect(languageProvider.refreshLogLabels).not.toBeCalled(); diff --git a/public/app/plugins/datasource/loki/components/useLokiLabels.ts b/public/app/plugins/datasource/loki/components/useLokiLabels.ts index b73f4a3d916..487814501d1 100644 --- a/public/app/plugins/datasource/loki/components/useLokiLabels.ts +++ b/public/app/plugins/datasource/loki/components/useLokiLabels.ts @@ -1,5 +1,6 @@ import { useState, useEffect } from 'react'; import { DataSourceStatus } from '@grafana/ui/src/types/datasource'; +import { AbsoluteTimeRange } from '@grafana/data'; import LokiLanguageProvider from 'app/plugins/datasource/loki/language_provider'; import { CascaderOption } from 'app/plugins/datasource/loki/components/LokiQueryFieldForm'; @@ -17,6 +18,7 @@ export const useLokiLabels = ( languageProvider: LokiLanguageProvider, languageProviderInitialised: boolean, activeOption: CascaderOption[], + absoluteRange: AbsoluteTimeRange, datasourceStatus: DataSourceStatus, initialDatasourceStatus?: DataSourceStatus // used for test purposes ) => { @@ -32,14 +34,14 @@ export const useLokiLabels = ( // Async const fetchOptionValues = async (option: string) => { - await languageProvider.fetchLabelValues(option); + await languageProvider.fetchLabelValues(option, absoluteRange); if (mounted.current) { setLogLabelOptions(languageProvider.logLabelOptions); } }; const tryLabelsRefresh = async () => { - await languageProvider.refreshLogLabels(shouldForceRefreshLabels); + await languageProvider.refreshLogLabels(absoluteRange, shouldForceRefreshLabels); if (mounted.current) { setRefreshLabels(false); diff --git a/public/app/plugins/datasource/loki/components/useLokiSyntax.test.ts b/public/app/plugins/datasource/loki/components/useLokiSyntax.test.ts index bee092ecd87..99e7904c347 100644 --- a/public/app/plugins/datasource/loki/components/useLokiSyntax.test.ts +++ b/public/app/plugins/datasource/loki/components/useLokiSyntax.test.ts @@ -1,5 +1,6 @@ import { renderHook, act } from 'react-hooks-testing-library'; import { DataSourceStatus } from '@grafana/ui/src/types/datasource'; +import { AbsoluteTimeRange } from '@grafana/data'; import LanguageProvider from 'app/plugins/datasource/loki/language_provider'; import { useLokiSyntax } from './useLokiSyntax'; @@ -14,6 +15,11 @@ describe('useLokiSyntax hook', () => { const logLabelOptionsMock2 = ['Mock the hell?!']; const logLabelOptionsMock3 = ['Oh my mock!']; + const rangeMock: AbsoluteTimeRange = { + from: 1560153109000, + to: 1560163909000, + }; + languageProvider.refreshLogLabels = () => { languageProvider.logLabelOptions = logLabelOptionsMock; return Promise.resolve(); @@ -30,7 +36,9 @@ describe('useLokiSyntax hook', () => { }; it('should provide Loki syntax when used', async () => { - const { result, waitForNextUpdate } = renderHook(() => useLokiSyntax(languageProvider, DataSourceStatus.Connected)); + const { result, waitForNextUpdate } = renderHook(() => + useLokiSyntax(languageProvider, DataSourceStatus.Connected, rangeMock) + ); expect(result.current.syntax).toEqual(null); await waitForNextUpdate(); @@ -39,7 +47,9 @@ describe('useLokiSyntax hook', () => { }); it('should fetch labels on first call', async () => { - const { result, waitForNextUpdate } = renderHook(() => useLokiSyntax(languageProvider, DataSourceStatus.Connected)); + const { result, waitForNextUpdate } = renderHook(() => + useLokiSyntax(languageProvider, DataSourceStatus.Connected, rangeMock) + ); expect(result.current.isSyntaxReady).toBeFalsy(); expect(result.current.logLabelOptions).toEqual([]); @@ -50,7 +60,9 @@ describe('useLokiSyntax hook', () => { }); it('should try to fetch missing options when active option changes', async () => { - const { result, waitForNextUpdate } = renderHook(() => useLokiSyntax(languageProvider, DataSourceStatus.Connected)); + const { result, waitForNextUpdate } = renderHook(() => + useLokiSyntax(languageProvider, DataSourceStatus.Connected, rangeMock) + ); await waitForNextUpdate(); expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock2); diff --git a/public/app/plugins/datasource/loki/components/useLokiSyntax.ts b/public/app/plugins/datasource/loki/components/useLokiSyntax.ts index a48afe19ca1..7faa5a6fb24 100644 --- a/public/app/plugins/datasource/loki/components/useLokiSyntax.ts +++ b/public/app/plugins/datasource/loki/components/useLokiSyntax.ts @@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'; // @ts-ignore import Prism from 'prismjs'; import { DataSourceStatus } from '@grafana/ui/src/types/datasource'; - +import { AbsoluteTimeRange } from '@grafana/data'; import LokiLanguageProvider from 'app/plugins/datasource/loki/language_provider'; import { useLokiLabels } from 'app/plugins/datasource/loki/components/useLokiLabels'; import { CascaderOption } from 'app/plugins/datasource/loki/components/LokiQueryFieldForm'; @@ -15,7 +15,11 @@ const PRISM_SYNTAX = 'promql'; * @param languageProvider * @description Initializes given language provider, exposes Loki syntax and enables loading label option values */ -export const useLokiSyntax = (languageProvider: LokiLanguageProvider, datasourceStatus: DataSourceStatus) => { +export const useLokiSyntax = ( + languageProvider: LokiLanguageProvider, + datasourceStatus: DataSourceStatus, + absoluteRange: AbsoluteTimeRange +) => { const mounted = useRefMounted(); // State const [languageProviderInitialized, setLanguageProviderInitilized] = useState(false); @@ -32,11 +36,13 @@ export const useLokiSyntax = (languageProvider: LokiLanguageProvider, datasource languageProvider, languageProviderInitialized, activeOption, + absoluteRange, datasourceStatus ); // Async const initializeLanguageProvider = async () => { + languageProvider.initialRange = absoluteRange; await languageProvider.start(); Prism.languages[PRISM_SYNTAX] = languageProvider.getSyntax(); if (mounted.current) { diff --git a/public/app/plugins/datasource/loki/datasource.ts b/public/app/plugins/datasource/loki/datasource.ts index 28a0857e377..bd4080b061b 100644 --- a/public/app/plugins/datasource/loki/datasource.ts +++ b/public/app/plugins/datasource/loki/datasource.ts @@ -78,6 +78,7 @@ export class LokiDatasource extends DataSourceApi { ...options, url, }; + return this.backendSrv.datasourceRequest(req); } @@ -254,10 +255,10 @@ export class LokiDatasource extends DataSourceApi { return this.languageProvider.importQueries(queries, originMeta.id); } - metadataRequest(url: string) { + metadataRequest(url: string, params?: any) { // HACK to get label values for {job=|}, will be replaced when implementing LokiQueryField const apiUrl = url.replace('v1', 'prom'); - return this._request(apiUrl, { silent: true }).then((res: DataQueryResponse) => { + return this._request(apiUrl, params, { silent: true }).then((res: DataQueryResponse) => { const data: any = { data: { data: res.data.values || [] } }; return data; }); diff --git a/public/app/plugins/datasource/loki/language_provider.test.ts b/public/app/plugins/datasource/loki/language_provider.test.ts index 301fbb30fcd..986f5335821 100644 --- a/public/app/plugins/datasource/loki/language_provider.test.ts +++ b/public/app/plugins/datasource/loki/language_provider.test.ts @@ -1,7 +1,8 @@ // @ts-ignore import Plain from 'slate-plain-serializer'; -import LanguageProvider, { LABEL_REFRESH_INTERVAL } from './language_provider'; +import LanguageProvider, { LABEL_REFRESH_INTERVAL, rangeToParams } from './language_provider'; +import { AbsoluteTimeRange } from '@grafana/data'; import { advanceTo, clear, advanceBy } from 'jest-date-mock'; import { beforeEach } from 'test/lib/common'; import { DataQueryResponseData } from '@grafana/ui'; @@ -11,8 +12,13 @@ describe('Language completion provider', () => { metadataRequest: () => ({ data: { data: [] as DataQueryResponseData[] } }), }; + const rangeMock: AbsoluteTimeRange = { + from: 1560153109000, + to: 1560163909000, + }; + describe('empty query suggestions', () => { - it('returns no suggestions on emtpty context', () => { + it('returns no suggestions on empty context', () => { const instance = new LanguageProvider(datasource); const value = Plain.deserialize(''); const result = instance.provideCompletionItems({ text: '', prefix: '', value, wrapperClasses: [] }); @@ -21,7 +27,7 @@ describe('Language completion provider', () => { expect(result.suggestions.length).toEqual(0); }); - it('returns default suggestions with history on emtpty context when history was provided', () => { + it('returns default suggestions with history on empty context when history was provided', () => { const instance = new LanguageProvider(datasource); const value = Plain.deserialize(''); const history = [ @@ -29,7 +35,10 @@ describe('Language completion provider', () => { query: { refId: '1', expr: '{app="foo"}' }, }, ]; - const result = instance.provideCompletionItems({ text: '', prefix: '', value, wrapperClasses: [] }, { history }); + const result = instance.provideCompletionItems( + { text: '', prefix: '', value, wrapperClasses: [] }, + { history, absoluteRange: rangeMock } + ); expect(result.context).toBeUndefined(); expect(result.refresher).toBeUndefined(); expect(result.suggestions).toMatchObject([ @@ -79,64 +88,102 @@ describe('Language completion provider', () => { anchorOffset: 1, }); const valueWithSelection = value.change().select(range).value; - const result = instance.provideCompletionItems({ - text: '', - prefix: '', - wrapperClasses: ['context-labels'], - value: valueWithSelection, - }); + const result = instance.provideCompletionItems( + { + text: '', + prefix: '', + wrapperClasses: ['context-labels'], + value: valueWithSelection, + }, + { absoluteRange: rangeMock } + ); expect(result.context).toBe('context-labels'); expect(result.suggestions).toEqual([{ items: [{ label: 'job' }, { label: 'namespace' }], label: 'Labels' }]); }); }); }); +describe('Request URL', () => { + it('should contain range params', async () => { + const rangeMock: AbsoluteTimeRange = { + from: 1560153109000, + to: 1560163909000, + }; + + const datasourceWithLabels = { + metadataRequest: url => { + if (url.slice(0, 15) === '/api/prom/label') { + return { data: { data: ['other'] } }; + } else { + return { data: { data: [] } }; + } + }, + }; + + const datasourceSpy = jest.spyOn(datasourceWithLabels, 'metadataRequest'); + + const instance = new LanguageProvider(datasourceWithLabels, { initialRange: rangeMock }); + await instance.refreshLogLabels(rangeMock, true); + const expectedUrl = '/api/prom/label'; + expect(datasourceSpy).toHaveBeenCalledWith(expectedUrl, rangeToParams(rangeMock)); + }); +}); + describe('Query imports', () => { const datasource = { metadataRequest: () => ({ data: { data: [] as DataQueryResponseData[] } }), }; + const rangeMock: AbsoluteTimeRange = { + from: 1560153109000, + to: 1560163909000, + }; + it('returns empty queries for unknown origin datasource', async () => { - const instance = new LanguageProvider(datasource); + const instance = new LanguageProvider(datasource, { initialRange: rangeMock }); const result = await instance.importQueries([{ refId: 'bar', expr: 'foo' }], 'unknown'); expect(result).toEqual([{ refId: 'bar', expr: '' }]); }); describe('prometheus query imports', () => { it('returns empty query from metric-only query', async () => { - const instance = new LanguageProvider(datasource); + const instance = new LanguageProvider(datasource, { initialRange: rangeMock }); const result = await instance.importPrometheusQuery('foo'); expect(result).toEqual(''); }); it('returns empty query from selector query if label is not available', async () => { const datasourceWithLabels = { - metadataRequest: (url: string) => - url === '/api/prom/label' ? { data: { data: ['other'] } } : { data: { data: [] as DataQueryResponseData[] } }, + metadataRequest: url => + url.slice(0, 15) === '/api/prom/label' + ? { data: { data: ['other'] } } + : { data: { data: [] as DataQueryResponseData[] } }, }; - const instance = new LanguageProvider(datasourceWithLabels); + const instance = new LanguageProvider(datasourceWithLabels, { initialRange: rangeMock }); const result = await instance.importPrometheusQuery('{foo="bar"}'); expect(result).toEqual('{}'); }); it('returns selector query from selector query with common labels', async () => { const datasourceWithLabels = { - metadataRequest: (url: string) => - url === '/api/prom/label' ? { data: { data: ['foo'] } } : { data: { data: [] as DataQueryResponseData[] } }, + metadataRequest: url => + url.slice(0, 15) === '/api/prom/label' + ? { data: { data: ['foo'] } } + : { data: { data: [] as DataQueryResponseData[] } }, }; - const instance = new LanguageProvider(datasourceWithLabels); + const instance = new LanguageProvider(datasourceWithLabels, { initialRange: rangeMock }); const result = await instance.importPrometheusQuery('metric{foo="bar",baz="42"}'); expect(result).toEqual('{foo="bar"}'); }); it('returns selector query from selector query with all labels if logging label list is empty', async () => { const datasourceWithLabels = { - metadataRequest: (url: string) => - url === '/api/prom/label' + metadataRequest: url => + url.slice(0, 15) === '/api/prom/label' ? { data: { data: [] as DataQueryResponseData[] } } : { data: { data: [] as DataQueryResponseData[] } }, }; - const instance = new LanguageProvider(datasourceWithLabels); + const instance = new LanguageProvider(datasourceWithLabels, { initialRange: rangeMock }); const result = await instance.importPrometheusQuery('metric{foo="bar",baz="42"}'); expect(result).toEqual('{baz="42",foo="bar"}'); }); @@ -149,6 +196,11 @@ describe('Labels refresh', () => { }; const instance = new LanguageProvider(datasource); + const rangeMock: AbsoluteTimeRange = { + from: 1560153109000, + to: 1560163909000, + }; + beforeEach(() => { instance.fetchLogLabels = jest.fn(); }); @@ -157,18 +209,20 @@ describe('Labels refresh', () => { jest.clearAllMocks(); clear(); }); + it("should not refresh labels if refresh interval hasn't passed", () => { advanceTo(new Date(2019, 1, 1, 0, 0, 0)); instance.logLabelFetchTs = Date.now(); advanceBy(LABEL_REFRESH_INTERVAL / 2); - instance.refreshLogLabels(); + instance.refreshLogLabels(rangeMock); expect(instance.fetchLogLabels).not.toBeCalled(); }); + it('should refresh labels if refresh interval passed', () => { advanceTo(new Date(2019, 1, 1, 0, 0, 0)); instance.logLabelFetchTs = Date.now(); advanceBy(LABEL_REFRESH_INTERVAL + 1); - instance.refreshLogLabels(); + instance.refreshLogLabels(rangeMock); expect(instance.fetchLogLabels).toBeCalled(); }); }); diff --git a/public/app/plugins/datasource/loki/language_provider.ts b/public/app/plugins/datasource/loki/language_provider.ts index 0c4877066d7..f465d9c022a 100644 --- a/public/app/plugins/datasource/loki/language_provider.ts +++ b/public/app/plugins/datasource/loki/language_provider.ts @@ -15,16 +15,18 @@ import { HistoryItem, } from 'app/types/explore'; import { LokiQuery } from './types'; -import { dateTime } from '@grafana/data'; +import { dateTime, AbsoluteTimeRange } from '@grafana/data'; import { PromQuery } from '../prometheus/types'; const DEFAULT_KEYS = ['job', 'namespace']; const EMPTY_SELECTOR = '{}'; const HISTORY_ITEM_COUNT = 10; const HISTORY_COUNT_CUTOFF = 1000 * 60 * 60 * 24; // 24h +const NS_IN_MS = 1_000_000; export const LABEL_REFRESH_INTERVAL = 1000 * 30; // 30sec const wrapLabel = (label: string) => ({ label }); +export const rangeToParams = (range: AbsoluteTimeRange) => ({ start: range.from * NS_IN_MS, end: range.to * NS_IN_MS }); type LokiHistoryItem = HistoryItem; @@ -50,6 +52,7 @@ export default class LokiLanguageProvider extends LanguageProvider { logLabelOptions: any[]; logLabelFetchTs?: number; started: boolean; + initialRange: AbsoluteTimeRange; constructor(datasource: any, initialValues?: any) { super(); @@ -67,13 +70,13 @@ export default class LokiLanguageProvider extends LanguageProvider { return syntax; } - request = (url: string) => { - return this.datasource.metadataRequest(url); + request = (url: string, params?: any) => { + return this.datasource.metadataRequest(url, params); }; start = () => { if (!this.startTask) { - this.startTask = this.fetchLogLabels(); + this.startTask = this.fetchLogLabels(this.initialRange); } return this.startTask; }; @@ -120,7 +123,10 @@ export default class LokiLanguageProvider extends LanguageProvider { return { suggestions }; } - getLabelCompletionItems({ text, wrapperClasses, labelKey, value }: TypeaheadInput): TypeaheadOutput { + getLabelCompletionItems( + { text, wrapperClasses, labelKey, value }: TypeaheadInput, + { absoluteRange }: any + ): TypeaheadOutput { let context: string; let refresher: Promise = null; const suggestions: CompletionItemGroup[] = []; @@ -146,7 +152,7 @@ export default class LokiLanguageProvider extends LanguageProvider { items: labelValues.map(wrapLabel), }); } else { - refresher = this.fetchLabelValues(labelKey); + refresher = this.fetchLabelValues(labelKey, absoluteRange); } } } else { @@ -206,7 +212,7 @@ export default class LokiLanguageProvider extends LanguageProvider { if (existingKeys && existingKeys.length > 0) { // Check for common labels for (const key in labels) { - if (existingKeys && existingKeys.indexOf(key) > -1) { + if (existingKeys && existingKeys.includes(key)) { // Should we check for label value equality here? labelsToKeep[key] = labels[key]; } @@ -227,11 +233,12 @@ export default class LokiLanguageProvider extends LanguageProvider { return ''; } - async fetchLogLabels(): Promise { + async fetchLogLabels(absoluteRange: AbsoluteTimeRange): Promise { const url = '/api/prom/label'; try { this.logLabelFetchTs = Date.now(); - const res = await this.request(url); + + const res = await this.request(url, rangeToParams(absoluteRange)); const body = await (res.data || res.json()); const labelKeys = body.data.slice().sort(); this.labelKeys = { @@ -244,7 +251,7 @@ export default class LokiLanguageProvider extends LanguageProvider { return Promise.all( labelKeys .filter((key: string) => DEFAULT_KEYS.indexOf(key) > -1) - .map((key: string) => this.fetchLabelValues(key)) + .map((key: string) => this.fetchLabelValues(key, absoluteRange)) ); } catch (e) { console.error(e); @@ -252,16 +259,16 @@ export default class LokiLanguageProvider extends LanguageProvider { return []; } - async refreshLogLabels(forceRefresh?: boolean) { + async refreshLogLabels(absoluteRange: AbsoluteTimeRange, forceRefresh?: boolean) { if ((this.labelKeys && Date.now() - this.logLabelFetchTs > LABEL_REFRESH_INTERVAL) || forceRefresh) { - await this.fetchLogLabels(); + await this.fetchLogLabels(absoluteRange); } } - async fetchLabelValues(key: string) { + async fetchLabelValues(key: string, absoluteRange: AbsoluteTimeRange) { const url = `/api/prom/label/${key}/values`; try { - const res = await this.request(url); + const res = await this.request(url, rangeToParams(absoluteRange)); const body = await (res.data || res.json()); const values = body.data.slice().sort(); diff --git a/public/app/types/explore.ts b/public/app/types/explore.ts index d816255ba84..5a2ddd1bc72 100644 --- a/public/app/types/explore.ts +++ b/public/app/types/explore.ts @@ -286,7 +286,7 @@ export interface HistoryItem { export abstract class LanguageProvider { datasource: any; - request: (url: any) => Promise; + request: (url: string, params?: any) => Promise; /** * Returns startTask that resolves with a task list when main syntax is loaded. * Task list consists of secondary promises that load more detailed language features.